diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8930bf3ce3..af4e8ef7d5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -412,6 +412,7 @@ add_subdirectory(tests/shell) if (NOT("${CROSS_COMPILE}" MATCHES "ON")) add_subdirectory(tests/shared) endif() +add_subdirectory(tests/util/lp) # Include style check if (NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows")) diff --git a/src/tests/util/lp/CMakeLists.txt b/src/tests/util/lp/CMakeLists.txt new file mode 100644 index 0000000000..13a8c30be6 --- /dev/null +++ b/src/tests/util/lp/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(lp_tst lp.cpp $ $) +target_link_libraries(lp_tst ${EXTRA_LIBS}) +add_test(lp_tst ${CMAKE_CURRENT_BINARY_DIR}/lp_tst) +add_executable(double_compare double_compare.cpp $ $) +target_link_libraries(double_compare ${EXTRA_LIBS}) +add_test(double_compare ${CMAKE_CURRENT_BINARY_DIR}/double_compare) diff --git a/src/tests/util/lp/argument_parser.h b/src/tests/util/lp/argument_parser.h new file mode 100644 index 0000000000..7a699f56e9 --- /dev/null +++ b/src/tests/util/lp/argument_parser.h @@ -0,0 +1,136 @@ +/* +Copyright (c) 2013 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Lev Nachmanson +*/ + +#include +#include +#include +#include +#include + +using namespace std; +namespace lean { +class argument_parser { + unordered_map m_options; + unordered_map m_options_with_after_string; + std::set m_used_options; + unordered_map m_used_options_with_after_string; + vector m_free_args; + vector m_args; + +public: + string m_error_message; + argument_parser(unsigned argn, char * const* args) { + for (unsigned i = 0; i < argn; i++) { + m_args.push_back(string(args[i])); + } + } + + void add_option(string s) { + add_option_with_help_string(s, ""); + } + + void add_option_with_help_string(string s, string help_string) { + m_options[s]=help_string; + } + + void add_option_with_after_string(string s) { + add_option_with_after_string_with_help(s, ""); + } + + void add_option_with_after_string_with_help(string s, string help_string) { + m_options_with_after_string[s]=help_string; + } + + + bool parse() { + bool status_is_ok = true; + for (unsigned i = 0; i < m_args.size(); i++) { + string ar = m_args[i]; + if (m_options.find(ar) != m_options.end() ) + m_used_options.insert(ar); + else if (m_options_with_after_string.find(ar) != m_options_with_after_string.end()) { + if (i == m_args.size() - 1) { + m_error_message = "Argument is missing after "+ar; + return false; + } + i++; + m_used_options_with_after_string[ar] = m_args[i]; + } else { + if (starts_with(ar, "-") || starts_with(ar, "//")) { + m_error_message = "Unknown option " + ar; + status_is_ok = false; + } + + m_free_args.push_back(ar); + } + } + return status_is_ok; + } + + bool contains(unordered_map & m, string s) { + return m.find(s) != m.end(); + } + + bool contains(std::set & m, string s) { + return m.find(s) != m.end(); + } + + bool option_is_used(string option) { + return contains(m_used_options, option) || contains(m_used_options_with_after_string, option); + } + + string get_option_value(string option) { + auto t = m_used_options_with_after_string.find(option); + if (t != m_used_options_with_after_string.end()){ + return t->second; + } + return string(); + } + + bool starts_with(string s, char const * prefix) { + return starts_with(s, string(prefix)); + } + + bool starts_with(string s, string prefix) { + return s.substr(0, prefix.size()) == prefix; + } + + string usage_string() { + string ret = ""; + vector unknown_options; + for (auto t : m_free_args) { + if (starts_with(t, "-") || starts_with(t, "\\")) { + unknown_options.push_back(t); + } + } + if (unknown_options.size()) { + ret = "Unknown options:"; + } + for (auto unknownOption : unknown_options) { + ret += unknownOption; + ret += ","; + } + ret += "\n"; + ret += "Usage:\n"; + for (auto allowed_option : m_options) + ret += allowed_option.first + " " + (allowed_option.second.size() == 0 ? string("") : string("/") + allowed_option.second) + string("\n"); + for (auto s : m_options_with_after_string) { + ret += s.first + " " + (s.second.size() == 0? " \"option value\"":("\""+ s.second+"\"")) + "\n"; + } + return ret; + } + + void print() { + for (string s : m_used_options) { + cout << s << endl; + } + for (auto & t : m_used_options_with_after_string) { + cout << t.first << " " << t.second << endl; + } + } +}; +} diff --git a/src/tests/util/lp/compare_with_glpk.sh b/src/tests/util/lp/compare_with_glpk.sh new file mode 100755 index 0000000000..ec880ffa73 --- /dev/null +++ b/src/tests/util/lp/compare_with_glpk.sh @@ -0,0 +1,140 @@ +#!/bin/bash +if [ $# -ne 2 -a $# -ne 3 ]; then + echo "Usage: compare_with_glpk.sh --min [--mpq] mps_file_name" + echo "or compare_with_glpk.sh --max [--mpq] mps_file_name" + exit 1 +fi +minmax_option=$1 +if [ $minmax_option != "--min" -a $minmax_option != "--max" ]; then + echo "Usage: compare_with_glpk.sh --min [--mpq] mps_file_name" + echo "or compare_with_glpk.sh --max [--mpq] mps_file_name" + exit 1 +fi + +if [ $minmax_option == "--min" ]; then + prefix="_min"; +else + if [ $minmax_option == "--max" ]; then + prefix="_max" + else + echo "Usage: compare_with_glpk.sh minmax_option mps_file_name" + echo "where minmax_option can be --min or --max" + exit 1 + fi +fi +mpq_option="" +if [ $# -eq 3 ]; then + mpq_option=$2 + if [ $mpq_option != "--mpq" ]; then + echo "Usage: compare_with_glpk.sh --min [--mpq] mps_file_name" + echo "or compare_with_glpk.sh --max [--mpq] mps_file_name" + exit 1 + fi + mps_input_file=$3 +else + mps_input_file=$2 +fi + +filename=$(basename "$mps_input_file") +extension="${filename##*.}" +filename="${filename%.*}" +#testpath="${mps_input_file%/*}" +testpath="/tmp" +glpsol_output="${testpath}""/""${filename}"$prefix".out" +lp_tst_output="${testpath}""/""${filename}"$prefix".lp_tst.out""$mpq_option" +lp_tst=$HOME"/projects/lean/build/release/tests/util/lp/lp_tst" +cost_compare=$HOME"/projects/lean/build/release/tests/util/lp/double_compare" + +if [ $# -ne 3 ]; then + glpsol --nointopt --nomip $minmax_option --tmlim 60 -o "${glpsol_output}" "${mps_input_file}" > /dev/null + status=$? + if [ $status -ne 0 ]; then + echo "glpsol failed" + exit 2 + fi +fi + +function get_status_from_output() { + local __resultvar=$1 + local status_str=$(grep Status $2) + local tokens=( $status_str ) + local myresult=${tokens[1]} + eval $__resultvar="'$myresult'" +} + +function get_cost_from_glpout() { + local __resultvar=$1 + local status_str=$(grep Objective "${glpsol_output}") + local tokens=( $status_str ) + local myresult=${tokens[3]} + eval $__resultvar="'$myresult'" +} + +get_status_from_output glp_status $glpsol_output + +get_cost_from_glpout glp_cost + +# ~/projects/lean/build/debug/tests/util/lp/double_compare 24501.2549 2.450125496e+04 0.01 +# compare_return=$? +# if [ $compare_return -eq 2 ]; then +# echo "Wrong usage of double_compare"; +# else +# if [ $compare_return -ne 0 ]; then +# echo "the difference is too large" +# else +# echo "the difference is OK" +# fi +# fi + +if [ $# -eq 2 ] ; then + $lp_tst --file $mps_input_file --time_limit 60 $minmax_option > $lp_tst_output +else + $lp_tst --file $mps_input_file --time_limit 12000 $minmax_option "--mpq" > $lp_tst_output +fi +status=$? +if [ $status -ne 0 ]; then + echo "lp_tst failed" + exit 1 +fi + +get_status_from_output lp_tst_status $lp_tst_output + +if [ $glp_status != $lp_tst_status ]; then + if [ "$glp_status" = UNDEFINED ] && [ "$lp_tst_status" = UNBOUNDED ]; then + exit 0 + else + if [ "$glp_status" = UNDEFINED ] && [ "$lp_tst_status" = INFEASIBLE ]; then + exit 0 + else + echo "glpsol and lp_tst disagree: glpsol status is ""$glp_status" + echo "but lp_tst status is ""$lp_tst_status" + exit 1 + fi + fi +fi + +if [ $glp_status != OPTIMAL ]; then + cout "exiting 0" + exit 0 +fi + + +function get_cost_from_lp_tst_out() { + local __resultvar=$1 + local cost_str=$(grep cost "${lp_tst_output}"| tail -1) + local tokens=( $cost_str ) + local myresult=${tokens[2]} + eval $__resultvar="'$myresult'" +} + + +get_cost_from_lp_tst_out lp_tst_cost + +$cost_compare $lp_tst_cost $glp_cost +status=$? +if [ $status -ne 0 ]; then + echo "the costs differ too much" + echo "glp cost is ""$glp_cost"", but lp_tst_cost is ""$lp_tst_cost" + exit 1 +fi +exit 0 diff --git a/src/tests/util/lp/double_compare.cpp b/src/tests/util/lp/double_compare.cpp new file mode 100644 index 0000000000..0ef4b3881e --- /dev/null +++ b/src/tests/util/lp/double_compare.cpp @@ -0,0 +1,51 @@ +/* +Copyright (c) 2013 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Lev Nachmanson +*/ + +// This file is needed for testing. It can be called with two or three +// strings represinting double numbers. If the absolute value of the +// difference between the first two numbers is less than the third +// one, then 0 is returned. Otherwise 1 is returned. If the number of +// arguments is two and the numbers are small then 0 returned. If the +// numbers are not too small then 0 returned when the absolute value +// of their difference is smaller than one percent of their maximal +// abs value. If the number parameters is not 2 or 3, or the arguments +// cannot be converted to doubles then -1 is returned + + +#include +using namespace std; +#include +#include + +int main(int argn, char * const * argv) { + if (argn != 4 && argn != 3) { + cout << "Usage is \"n1 n2 [n3]" << endl; + return 2; + } + + double a = atof(argv[1]); + double b = atof(argv[2]); + if (argn == 4) { + double c = atof(argv[3]); + if (fabs(a - b) < c) { + return 0; + } + return 1; + } + + // argn == 3 + double maxval = max(fabs(a), fabs(b)); + if (maxval < 0.000001) { + return 0; + } + + double one_percent = maxval / 100; + if (fabs(a - b) > one_percent) { + return 1; + } + return 0; +} diff --git a/src/tests/util/lp/init_module.cpp b/src/tests/util/lp/init_module.cpp new file mode 100644 index 0000000000..5350a2a049 --- /dev/null +++ b/src/tests/util/lp/init_module.cpp @@ -0,0 +1,44 @@ +/* +Copyright (c) 2014 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Lev Nachmanson +*/ +#include "util/ascii.h" +#include "util/debug.h" +#include "util/trace.h" +#include "util/serializer.h" +#include "util/thread_script_state.h" +#include "util/script_state.h" +#include "util/name.h" +#include "util/name_generator.h" +#include "util/lean_path.h" +#include "util/thread.h" +#include "util/memory_pool.h" + +namespace lean { +void initialize_util_module() { + initialize_debug(); + initialize_trace(); + initialize_serializer(); + initialize_thread(); + initialize_ascii(); + initialize_thread_script_state(); + initialize_script_state(); + initialize_name(); + initialize_name_generator(); + initialize_lean_path(); +} +void finalize_util_module() { + finalize_lean_path(); + finalize_name_generator(); + finalize_name(); + finalize_script_state(); + finalize_thread_script_state(); + finalize_ascii(); + finalize_thread(); + finalize_serializer(); + finalize_trace(); + finalize_debug(); +} +} diff --git a/src/tests/util/lp/init_module.h b/src/tests/util/lp/init_module.h new file mode 100644 index 0000000000..17f8d3d631 --- /dev/null +++ b/src/tests/util/lp/init_module.h @@ -0,0 +1,12 @@ +/* +Copyright (c) 2014 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Lev Nachmanson +*/ +#pragma once + +namespace lean { +void initialize_util_module(); +void finalize_util_module(); +} diff --git a/src/tests/util/lp/l0.mps b/src/tests/util/lp/l0.mps new file mode 100644 index 0000000000..70bbf3b885 --- /dev/null +++ b/src/tests/util/lp/l0.mps @@ -0,0 +1,36 @@ +NAME l0 (135 a) +ROWS + N Z + E R1 + E R2 +COLUMNS + X1 R1 1.0 + X1 Z -3.0 + X2 Z -1.0 R2 1.0 + X3 Z -1.0 R1 3 R2 -2 + X4 Z 2 R1 1 R2 -1 + X5 Z -1 R1 -5 R2 4 + X6 Z 1 R1 -2 R2 1 + X7 Z 1 R1 4 R2 -3 + X8 Z -4 R1 -6 R2 5 +RHS + RHS1 R1 7 + RHS1 R2 -3 +BOUNDS + LO BND1 X1 0 + UP BND1 X1 8 + LO BND1 X2 0 + UP BND1 X2 6 + LO BND1 X3 0 + UP BND1 X3 4 + LO BND1 X4 0 + UP BND1 X4 15 + LO BND1 X5 0 + UP BND1 X5 2 + LO BND1 X6 0 + UP BND1 X6 10 + LO BND1 X7 0 + UP BND1 X7 10 + LO BND1 X8 0 + UP BND1 X8 3 +ENDATA diff --git a/src/tests/util/lp/l0redund.mps b/src/tests/util/lp/l0redund.mps new file mode 100644 index 0000000000..9d0a951db8 --- /dev/null +++ b/src/tests/util/lp/l0redund.mps @@ -0,0 +1,61 @@ +NAME l0 +ROWS + N Z + E R1 + E R4R + E R3 + E R4 + E R11 + E R1R + E R2R + E R3R + E R11R + E R2 +COLUMNS + X1 R1 1.0 R11 1.0 + X1 Z -3.0 + X2 Z -1.0 R4R 1.0 R3 1.0 R4 1.0 + X3 Z -1.0 R1 3 R4R -2 R3 -2 R4 -2 + X4 Z 2 R1 1 R11 1 R4R -1 R3 -1 R4 -1 + X5 Z -1 R1 -5 R11 -5 R4R 4 R3 4 R4 4 + X6 Z 1 R1 -2 R11 -2 R4R 1 R3 1 R4 1 + X7 Z 1 R1 4 R11 4 R4R -3 R3 -3 R4 -3 + X8 Z -4 R1 -6 R11 -6 R4R 5 R3 5 R4 5 + X1 R1R 1.0 R11R 1.0 + X1 Z -3.0 + X2 Z -1.0 R2R 1.0 R3R 1.0 R2 1.0 + X3 Z -1.0 R1R 3 R2R -2 R3R -2 R2 -2 + X4 Z 2 R1R 1 R11R 1 R2R -1 R3R -1 R2 -1 + X5 Z -1 R1R -5 R11R -5 R2R 4 R3R 4 R2 4 + X6 Z 1 R1R -2 R11R -2 R2R 1 R3R 1 R2 1 + X7 Z 1 R1R 4 R11R 4 R2R -3 R3R -3 R2 -3 + X8 Z -4 R1R -6 R11R -6 R2R 5 R3R 5 R2 5 +RHS + RHS1 R1 7 + RHS1 R4R -3 + RHS1 R3 -3 + RHS1 R4 -3 + RHS1 R11 7 + RHS1 R1R 7 + RHS1 R2R -3 + RHS1 R3R -3 + RHS1 R2 -3 + RHS1 R11R 7 +BOUNDS + LO BND1 X1 0 + UP BND1 X1 8 + LO BND1 X2 0 + UP BND1 X2 6 + LO BND1 X3 0 + UP BND1 X3 4 + LO BND1 X4 0 + UP BND1 X4 15 + LO BND1 X5 0 + UP BND1 X5 2 + LO BND1 X6 0 + UP BND1 X6 10 + LO BND1 X7 0 + UP BND1 X7 10 + LO BND1 X8 0 + UP BND1 X8 3 +ENDATA diff --git a/src/tests/util/lp/l1.mps b/src/tests/util/lp/l1.mps new file mode 100644 index 0000000000..e2cd2e26df --- /dev/null +++ b/src/tests/util/lp/l1.mps @@ -0,0 +1,25 @@ +*SOURCE Chvatal, page 135(b) +NAME l1 +ROWS + N Z + L R1 + L R2 + L R3 + L R4 +COLUMNS + X1 Z 3 R1 1 R2 1 R3 1 R4 1 + X2 Z 1 R1 4 R2 3 R3 2 R4 3 + X3 Z 4 R1 3 R2 -1 R3 3 R4 1 + X4 Z 2 R1 3 R2 1 R3 2 R4 1 + +RHS + RHS1 R1 2 + RHS1 R2 -2 + RHS1 R3 3 + RHS1 R4 -3 +BOUNDS + FR BND1 X1 + FR BND1 X2 + LO BND1 X3 0 + LO BND1 X4 0 +ENDATA diff --git a/src/tests/util/lp/l2.mps b/src/tests/util/lp/l2.mps new file mode 100644 index 0000000000..c6ac587eef --- /dev/null +++ b/src/tests/util/lp/l2.mps @@ -0,0 +1,27 @@ +NAME l2 ( from chvatal's book page 135, Problem c. ) +ROWS + N Z + L R1 + L R2 + E R3 +COLUMNS + X1 Z 5 R1 3 R2 -5 R3 1 + X2 Z 2 R1 1 R2 4 R3 1 + X3 Z -3 R1 -4 R2 2 R3 2 + X4 Z 3 R1 2 R2 -3 R3 1 + X5 Z 6 R1 5 R2 2 R3 1 + X6 Z 1 R1 1 R2 3 R3 2 +RHS + RHS1 R1 3 + RHS1 R2 25 + RHS1 R3 4 +BOUNDS + LO BND1 X1 0 + LO BND1 X2 2 + UP BND1 X2 10 + UP BND1 X3 0 + LO BND1 X4 -3 + UP BND1 X4 3 + FR BND1 X5 + FR BND1 X6 +ENDATA diff --git a/src/tests/util/lp/l3.mps b/src/tests/util/lp/l3.mps new file mode 100644 index 0000000000..b0ce59c67e --- /dev/null +++ b/src/tests/util/lp/l3.mps @@ -0,0 +1,28 @@ +NAME l3 ( from chvatal's book page 135, Problem (d) the problem is infeasible ) + +ROWS + N Z + E R1 + E R2 + E R3 + E R4 + L R5 +COLUMNS + X1 Z 8 R1 3 R2 -1 R3 1 R4 2 R5 2 + X2 Z 6 R1 2 R2 2 R3 0 R4 -3 R5 0 + X3 Z -2 R1 -1 R2 -2 R3 0 R4 2 R5 1 + X4 Z 6 R1 3 R2 0 R3 -3 R4 3 R5 0 + X5 Z -3 R1 2 R2 0 R3 2 R4 0 R5 -1 +RHS + RHS1 R1 7 + RHS1 R2 10 + RHS1 R3 7 + RHS1 R4 -10 + RHS1 R5 -6 +BOUNDS + LO BND1 X1 0 + LO BND1 X2 2 + FR BND1 X3 + FR BND1 X4 + FR BND1 X5 +ENDATA diff --git a/src/tests/util/lp/l3flipped.mps b/src/tests/util/lp/l3flipped.mps new file mode 100644 index 0000000000..efbed0ab63 --- /dev/null +++ b/src/tests/util/lp/l3flipped.mps @@ -0,0 +1,27 @@ +NAME l3 ( from chvatal's book page 135, Problem d. ) +ROWS + N Z + E R1 + E R2 + E R3 + E R4 + L R5 +COLUMNS + X1 Z 8 R1 3 R2 -1 R3 1 R4 2 R5 2 + X2 Z -6 R1 -2 R2 -2 R3 0 R4 3 R5 0 + X3 Z -2 R1 -1 R2 -2 R3 0 R4 2 R5 1 + X4 Z 6 R1 3 R2 0 R3 -3 R4 3 R5 0 + X5 Z -3 R1 2 R2 0 R3 2 R4 0 R5 -1 +RHS + RHS1 R1 7 + RHS1 R2 10 + RHS1 R3 7 + RHS1 R4 -10 + RHS1 R5 -6 +BOUNDS + LO BND1 X1 0 + UP BND1 X2 -2 + FR BND1 X3 + FR BND1 X4 + FR BND1 X5 +ENDATA diff --git a/src/tests/util/lp/l4.mps b/src/tests/util/lp/l4.mps new file mode 100644 index 0000000000..1e7ce2dda8 --- /dev/null +++ b/src/tests/util/lp/l4.mps @@ -0,0 +1,22 @@ +NAME l3 ( from chvatal's book page 135, Problem e. ) +ROWS + N Z + E R1 + E R2 + E R3 + E R4 +COLUMNS + X1 Z 1 R1 3 R2 4 R3 2 R4 1 + X2 Z 0 R1 5 R2 6 R3 4 R4 1 + X3 Z 0 R1 3 R2 5 R3 1 R4 2 + X4 Z 0 R1 2 R2 3 R3 1 R4 1 + X5 Z 0 R1 1 R2 5 R3 -3 R4 4 + X6 Z 0 R1 2 R2 5 R3 -1 R4 3 + X7 Z 0 R1 1 R2 6 R3 -4 R4 5 +RHS + RHS1 R1 6 + RHS1 R2 11 + RHS1 R3 1 + RHS1 R4 5 +BOUNDS +ENDATA diff --git a/src/tests/util/lp/l4fix.mps b/src/tests/util/lp/l4fix.mps new file mode 100644 index 0000000000..1e7ce2dda8 --- /dev/null +++ b/src/tests/util/lp/l4fix.mps @@ -0,0 +1,22 @@ +NAME l3 ( from chvatal's book page 135, Problem e. ) +ROWS + N Z + E R1 + E R2 + E R3 + E R4 +COLUMNS + X1 Z 1 R1 3 R2 4 R3 2 R4 1 + X2 Z 0 R1 5 R2 6 R3 4 R4 1 + X3 Z 0 R1 3 R2 5 R3 1 R4 2 + X4 Z 0 R1 2 R2 3 R3 1 R4 1 + X5 Z 0 R1 1 R2 5 R3 -3 R4 4 + X6 Z 0 R1 2 R2 5 R3 -1 R4 3 + X7 Z 0 R1 1 R2 6 R3 -4 R4 5 +RHS + RHS1 R1 6 + RHS1 R2 11 + RHS1 R3 1 + RHS1 R4 5 +BOUNDS +ENDATA diff --git a/src/tests/util/lp/lp.cpp b/src/tests/util/lp/lp.cpp new file mode 100644 index 0000000000..42e596d000 --- /dev/null +++ b/src/tests/util/lp/lp.cpp @@ -0,0 +1,2690 @@ +/* +Copyright (c) 2013 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Lev Nachmanson +*/ +#include +#include +#include +#include +#include "util/lp/lp.h" +#include "util/lp/lp_primal_simplex.h" +#include +#include + +#include "tests/util/lp/mps_reader.h" +#include "tests/util/lp/smt_reader.h" +#include "util/numerics/mpq.h" +#include "util/lp/binary_heap_priority_queue.h" +#include "tests/util/lp/argument_parser.h" +#include "tests/util/lp/test_file_reader.h" +#include +#include +#include "util/lp/indexed_value.h" +#include +#include "tests/util/lp/init_module.h" +#include "util/numerics/init_module.h" +#include +#include +#include "util/lp/lar_solver.h" +#include "util/lp/numeric_pair.h" +#include "util/lp/binary_heap_upair_queue.h" +#include +using namespace lean; +using namespace std; +unsigned seed = 1; +#ifndef NDEBUG +unsigned lp_settings::ddd = 0; +#endif +std::unordered_map default_column_names(unsigned n) { + std::unordered_map ret; + for (unsigned i = 0; i < n; i++) { + ret[i] = std::string("x") + T_to_string(i); + } + return ret; +} + +template +void test_matrix(sparse_matrix & a) { + auto m = a.dimension(); + +// copy a to b in the reversed order + sparse_matrix b(m); + std::cout << "copy b to a"<< std::endl; + for (int row = m - 1; row >= 0; row--) + for (int col = m - 1; col >= 0; col --) { + b(row, col) = (T const&) a(row, col); + } + + + std::cout << "zeroing b in the reverse order"<< std::endl; + for (int row = m - 1; row >= 0; row--) + for (int col = m - 1; col >= 0; col --) + b.set(row, col, T(0)); + + + + for (unsigned row = 0; row < m; row ++) + for (unsigned col = 0; col < m; col ++) + a.set(row, col, T(0)); + + + unsigned i = rand_r(& seed) % m; + unsigned j = rand_r(& seed) % m; + + auto t = T(1); + + a.set(i, j, t); + + lean_assert(a.get(i, j) == t); + + unsigned j1; + if (j < m - 1) { + j1 = m - 1; + a.set(i, j1, T(2)); + } +} + +void tst1() { + std::cout << "testing the minimial matrix with 1 row and 1 column" << std::endl; + sparse_matrix m0(1); + m0.set(0, 0, 1); + // print_matrix(m0); + m0.set(0, 0, 0); + // print_matrix(m0); + test_matrix(m0); + + unsigned rows = 2; + sparse_matrix m(rows); + std::cout << "setting m(0,1)=" << std::endl; + + m.set(0, 1, 11); + m.set(0, 0, 12); + + // print_matrix(m); + + test_matrix(m); + + sparse_matrix m1(2); + m1.set(0, 0, 2); + m1.set(1, 0, 3); + // print_matrix(m1); + std::cout << " zeroing matrix 2 by 2" << std::endl; + m1.set(0, 0, 0); + m1.set(1, 0, 0); + // print_matrix(m1); + + test_matrix(m1); + + + std::cout << "printing zero matrix 3 by 1" << std::endl; + sparse_matrix m2(3); + // print_matrix(m2); + + m2.set(0, 0, 1); + m2.set(2, 0, 2); + std::cout << "printing matrix 3 by 1 with a gap" << std::endl; + // print_matrix(m2); + + test_matrix(m2); + + sparse_matrix m10by9(10); + m10by9.set(0, 1, 1); + + m10by9(0, 1) = 4; + + float test = m10by9(0, 1); + + std::cout << "got " << test << std:: endl; + + + m10by9.set(0, 8, 8); + m10by9.set(3, 4, 7); + m10by9.set(3, 2, 5); + m10by9.set(3, 8, 99); + m10by9.set(3, 2, 6); + m10by9.set(1, 8, 9); + m10by9.set(4, 0, 40); + m10by9.set(0, 0, 10); + + std::cout << "printing matrix 10 by 9" << std::endl; + // print_matrix(m10by9); + + + test_matrix(m10by9); + std::cout <<"zeroing m10by9\n"; +#ifndef NDEBUG + for (unsigned int i = 0; i < m10by9.dimension(); i++) + for (unsigned int j = 0; j < m10by9.column_count(); j++) + m10by9.set(i, j, 0); +#endif + // print_matrix(m10by9); +} + +vector allocate_basis_heading(unsigned count) { // the rest of initilization will be handled by lu_QR + vector basis_heading(count, -1); + return basis_heading; +} + + +void test_small_lu(lp_settings & settings) { + std::cout << " test_small_lu" << std::endl; + static_matrix m(3, 6); + vector basis(3); + basis[0] = 0; + basis[1] = 1; + basis[2] = 3; + + m(0, 0) = 1; m(0, 2)= 3.9; m(2, 3) = 11; m(0, 5) = -3; + m(1, 1) = 4; m(1, 4) = 7; + m(2, 0) = 1.8; m(2, 2) = 5; m(2, 4) = 2; m(2, 5) = 8; + +#ifndef NDEBUG + print_matrix(m); +#endif + vector heading = allocate_basis_heading(m.column_count()); + vector non_basic_columns; + init_basis_heading_and_non_basic_columns_vector(basis, m.row_count(), heading, m.column_count(), non_basic_columns); + lu l(m, basis, heading, settings, non_basic_columns); + lean_assert(l.is_correct()); + indexed_vector w(m.row_count()); + cout << "entering 2, leaving 0" << endl; + l.prepare_entering(2, w); // to init vector w + l.replace_column(0, 0, w); + l.change_basis(2, 0); + // #ifndef NDEBUG + // cout << "we were factoring " << endl; + // print_matrix(get_B(l)); + // #endif + lean_assert(l.is_correct()); + cout << "entering 4, leaving 3" << endl; + l.prepare_entering(4, w); // to init vector w + l.replace_column(3, 0, w); + l.change_basis(4, 3); + cout << "we were factoring " << endl; +#ifndef NDEBUG + print_matrix(get_B(l)); +#endif + lean_assert(l.is_correct()); + + cout << "entering 5, leaving 1" << endl; + l.prepare_entering(5, w); // to init vector w + l.replace_column(1, 0, w); + l.change_basis(5, 1); + cout << "we were factoring " << endl; +#ifndef NDEBUG + print_matrix(get_B(l)); +#endif + lean_assert(l.is_correct()); + cout << "entering 3, leaving 2" << endl; + l.prepare_entering(3, w); // to init vector w + l.replace_column(2, 0, w); + l.change_basis(3, 2); + cout << "we were factoring " << endl; +#ifndef NDEBUG + print_matrix(get_B(l)); +#endif + lean_assert(l.is_correct()); +} + + + +void fill_long_row(sparse_matrix &m, int i) { + int n = m.dimension(); + for (int j = 0; j < n; j ++) { + m (i, (j + i) % n) = j * j; + } +} + +void fill_long_row(static_matrix &m, int i) { + int n = m.column_count(); + for (int j = 0; j < n; j ++) { + m (i, (j + i) % n) = j * j; + } +} + + +void fill_long_row_exp(sparse_matrix &m, int i) { + int n = m.dimension(); + + for (int j = 0; j < n; j ++) { + m(i, j) = rand_r(& seed) % 20; + } +} + +void fill_long_row_exp(static_matrix &m, int i) { + int n = m.column_count(); + + for (int j = 0; j < n; j ++) { + m(i, j) = rand_r(& seed) % 20; + } +} + +void fill_larger_sparse_matrix_exp(sparse_matrix & m){ + for ( unsigned i = 0; i < m.dimension(); i++ ) + fill_long_row_exp(m, i); +} + +void fill_larger_sparse_matrix_exp(static_matrix & m){ + for ( unsigned i = 0; i < m.row_count(); i++ ) + fill_long_row_exp(m, i); +} + + +void fill_larger_sparse_matrix(sparse_matrix & m){ + for ( unsigned i = 0; i < m.dimension(); i++ ) + fill_long_row(m, i); +} + +void fill_larger_sparse_matrix(static_matrix & m){ + for ( unsigned i = 0; i < m.row_count(); i++ ) + fill_long_row(m, i); +} + + +int perm_id = 0; + +#ifndef NDEBUG +void test_larger_lu_exp(lp_settings & settings) { + std::cout << " test_larger_lu_exp" << std::endl; + static_matrix m(6, 12); + std::vector basis(6); + basis[0] = 1; + basis[1] = 3; + basis[2] = 0; + basis[3] = 4; + basis[4] = 5; + basis[5] = 6; + + + fill_larger_sparse_matrix_exp(m); + // print_matrix(m); + vector heading = allocate_basis_heading(m.column_count()); + vector non_basic_columns; + init_basis_heading_and_non_basic_columns_vector(basis, m.row_count(), heading, m.column_count(), non_basic_columns); + lu l(m, basis, heading, settings, non_basic_columns); + + dense_matrix left_side = l.get_left_side(); + dense_matrix right_side = l.get_right_side(); + lean_assert(left_side == right_side); + int leaving = 3; + int entering = 8; + for (unsigned i = 0; i < m.row_count(); i++) { + std::cout << static_cast(m(i, entering)) << std::endl; + } + + indexed_vector w(m.row_count()); + + l.prepare_entering(entering, w); + l.replace_column(leaving, 0, w); + l.change_basis(entering, leaving); + lean_assert(l.is_correct()); + + l.prepare_entering(11, w); // to init vector w + l.replace_column(0, 0, w); + l.change_basis(11, 0); + lean_assert(l.is_correct()); +} + +void test_larger_lu_with_holes(lp_settings & settings) { + std::cout << " test_larger_lu_with_holes" << std::endl; + static_matrix m(8, 9); + std::vector basis(8); + for (unsigned i = 0; i < m.row_count(); i++) { + basis[i] = i; + } + m(0, 0) = 1; m(0, 1) = 2; m(0, 2) = 3; m(0, 3) = 4; m(0, 4) = 5; m(0, 8) = 99; + /* */ m(1, 1) =- 6; m(1, 2) = 7; m(1, 3) = 8; m(1, 4) = 9; + /* */ m(2, 2) = 10; + /* */ m(3, 2) = 11; m(3, 3) = -12; + /* */ m(4, 2) = 13; m(4, 3) = 14; m(4, 4) = 15; + // the rest of the matrix is denser + m(5, 4) = 28; m(5, 5) = -18; m(5, 6) = 19; m(5, 7) = 25; + /* */ m(6, 5) = 20; m(6, 6) = -21; + /* */ m(7, 5) = 22; m(7, 6) = 23; m(7, 7) = 24; m(7, 8) = 88; + print_matrix(m); + vector heading = allocate_basis_heading(m.column_count()); + vector non_basic_columns; + init_basis_heading_and_non_basic_columns_vector(basis, m.row_count(), heading, m.column_count(), non_basic_columns); + lu l(m, basis, heading, settings, non_basic_columns); + std::cout << "printing factorization" << std::endl; + for (int i = l.tail_size() - 1; i >=0; i--) { + auto lp = l.get_lp_matrix(i); + lp->set_number_of_columns(m.row_count()); + lp->set_number_of_rows(m.row_count()); + print_matrix(* lp); + } + + dense_matrix left_side = l.get_left_side(); + dense_matrix right_side = l.get_right_side(); + if (!(left_side == right_side)) { + std::cout << "different sides" << std::endl; + } + + indexed_vector w(m.row_count()); + l.prepare_entering(8, w); // to init vector w + l.replace_column(0, 0, w); + l.change_basis(8, 0); + lean_assert(l.is_correct()); +} + + +void test_larger_lu(lp_settings& settings) { + std::cout << " test_larger_lu" << std::endl; + static_matrix m(6, 12); + std::vector basis(6); + basis[0] = 1; + basis[1] = 3; + basis[2] = 0; + basis[3] = 4; + basis[4] = 5; + basis[5] = 6; + + + fill_larger_sparse_matrix(m); + print_matrix(m); + + vector heading = allocate_basis_heading(m.column_count()); + vector non_basic_columns; + init_basis_heading_and_non_basic_columns_vector(basis, m.row_count(), heading, m.column_count(), non_basic_columns); + auto l = lu (m, basis, heading, settings, non_basic_columns); + // std::cout << "printing factorization" << std::endl; + // for (int i = lu.tail_size() - 1; i >=0; i--) { + // auto lp = lu.get_lp_matrix(i); + // lp->set_number_of_columns(m.row_count()); + // lp->set_number_of_rows(m.row_count()); + // print_matrix(* lp); + // } + + dense_matrix left_side = l.get_left_side(); + dense_matrix right_side = l.get_right_side(); + if (!(left_side == right_side)) { + cout << "left side" << endl; + print_matrix(left_side); + cout << "right side" << endl; + print_matrix(right_side); + + std::cout << "different sides" << std::endl; + cout << "initial factorization is incorrect" << endl; + exit(1); + } + indexed_vector w(m.row_count()); + l.prepare_entering(9, w); // to init vector w + l.replace_column(0, 0, w); + l.change_basis(9, 0); + lean_assert(l.is_correct()); +} + + +void test_lu(lp_settings & settings) { + test_small_lu(settings); + test_larger_lu(settings); + test_larger_lu_with_holes(settings); + test_larger_lu_exp(settings); +} +#endif + + + + + + +void init_b(std::vector & b, sparse_matrix & m, vector& x) { + for (unsigned i = 0; i < m.dimension(); i++) { + b.push_back(m.dot_product_with_row(i, x)); + } +} + +void init_b(std::vector & b, static_matrix & m, std::vector & x) { + for (unsigned i = 0; i < m.row_count(); i++) { + b.push_back(m.dot_product_with_row(i, x)); + } +} + + +void test_lp_0() { + std::cout << " test_lp_0 " << std::endl; + static_matrix m_(3, 7); + m_(0, 0) = 3; m_(0, 1) = 2; m_(0, 2) = 1; m_(0, 3) = 2; m_(0, 4) = 1; + m_(1, 0) = 1; m_(1, 1) = 1; m_(1, 2) = 1; m_(1, 3) = 1; m_(1, 5) = 1; + m_(2, 0) = 4; m_(2, 1) = 3; m_(2, 2) = 3; m_(2, 3) = 4; m_(2, 6) = 1; + std::vector x_star(7); + x_star[0] = 225; x_star[1] = 117; x_star[2] = 420; + x_star[3] = x_star[4] = x_star[5] = x_star[6] = 0; + std::vector b; + init_b(b, m_, x_star); + std::vector basis(3); + basis[0] = 0; basis[1] = 1; basis[2] = 2; + std::vector costs(7); + costs[0] = 19; + costs[1] = 13; + costs[2] = 12; + costs[3] = 17; + costs[4] = 0; + costs[5] = 0; + costs[6] = 0; + + std::vector column_types(7, low_bound); + std::vector upper_bound_values; + lp_settings settings; + auto cn = default_column_names(m_.column_count()); + lp_primal_core_solver lpsolver(m_, b, x_star, basis, costs, column_types, upper_bound_values, settings, cn); + + lpsolver.solve(); +} + +void test_lp_1() { + std::cout << " test_lp_1 " << std::endl; + static_matrix m(4, 7); + m(0, 0) = 1; m(0, 1) = 3; m(0, 2) = 1; m(0, 3) = 1; + m(1, 0) = -1; m(1, 2) = 3; m(1, 4) = 1; + m(2, 0) = 2; m(2, 1) = -1; m(2, 2) = 2; m(2, 5) = 1; + m(3, 0) = 2; m(3, 1) = 3; m(3, 2) = -1; m(3, 6) = 1; +#ifndef NDEBUG + print_matrix(m); +#endif + std::vector x_star(7); + x_star[0] = 0; x_star[1] = 0; x_star[2] = 0; + x_star[3] = 3; x_star[4] = 2; x_star[5] = 4; x_star[6] = 2; + + std::vector basis(4); + basis[0] = 3; basis[1] = 4; basis[2] = 5; basis[3] = 6; + + std::vector b; + b.push_back(3); + b.push_back(2); + b.push_back(4); + b.push_back(2); + + std::vector costs(7); + costs[0] = 5; + costs[1] = 5; + costs[2] = 3; + costs[3] = 0; + costs[4] = 0; + costs[5] = 0; + costs[6] = 0; + + + + std::vector column_types(7, low_bound); + std::vector upper_bound_values; + + std::cout << "calling lp\n"; + lp_settings settings; + auto cn = default_column_names(m.column_count()); + + lp_primal_core_solver lpsolver(m, b, + x_star, + basis, + costs, + column_types, upper_bound_values, settings, cn); + + lpsolver.solve(); +} + + +void test_lp_primal_core_solver() { + test_lp_0(); + test_lp_1(); +} +#ifndef NDEBUG +template +void test_swap_rows_with_permutation(sparse_matrix& m){ + cout << "testing swaps" << endl; + unsigned dim = m.row_count(); + dense_matrix original(m); + permutation_matrix q(dim); + print_matrix(m); + lean_assert(original == q * m); + for (int i = 0; i < 100; i++) { + unsigned row1 = lrand48() % dim; + unsigned row2 = lrand48() % dim; + if (row1 == row2) continue; + cout << "swap " << row1 << " " << row2 << endl; + m.swap_rows(row1, row2); + q.transpose_from_left(row1, row2); + lean_assert(original == q * m); + print_matrix(m); + cout << endl; + } +} +#endif +template +void fill_matrix(sparse_matrix& m); // forward definition +#ifndef NDEBUG +void matrix_repro_test() { + unsigned dim = 10; + sparse_matrix m(dim); + fill_matrix(m); + for (int i = 0; i < 100; i++) { + unsigned row1 = lrand48() % dim; + unsigned row2 = lrand48() % dim; + if (row1 == row2) continue; + m.swap_rows(row1, row2); + } + + for (int i = 0; i < 100; i++) { + unsigned col1 = lrand48() % dim; + unsigned col2 = lrand48() % dim; + if (col1 == col2) continue; + m.swap_columns(col1, col2); + } + + dense_matrix d(m); + for (unsigned i = 0; i < d.row_count(); i++) + for (unsigned j = 0; j < d.column_count(); j++) + d.set_elem(i, j, m.get_not_adjusted(i, j)); + + auto l = d * m.m_column_permutation; + l = m.m_row_permutation * l; + cout << "matrix_repro_test" << endl; + print_matrix(l); + lean_assert(l == m); +} + +template +void test_swap_cols_with_permutation(sparse_matrix& m){ + cout << "testing swaps" << endl; + unsigned dim = m.row_count(); + dense_matrix original(m); + permutation_matrix q(dim); + print_matrix(m); + lean_assert(original == q * m); + for (int i = 0; i < 100; i++) { + unsigned row1 = lrand48() % dim; + unsigned row2 = lrand48() % dim; + if (row1 == row2) continue; + cout << "swap " << row1 << " " << row2 << endl; + m.swap_rows(row1, row2); + q.transpose_from_right(row1, row2); + lean_assert(original == q * m); + print_matrix(m); + cout << endl; + } +} + + +template +void test_swap_rows(sparse_matrix& m, unsigned i0, unsigned i1){ + std::cout << "test_swap_rows(" << i0 << "," << i1 << ")" << std::endl; + sparse_matrix mcopy(m.dimension()); + for (unsigned i = 0; i < m.dimension(); i++) + for (unsigned j = 0; j < m.dimension(); j++) { + mcopy(i, j)= m(i, j); + } + std::cout << "swapping rows "<< i0 << "," << i1 << std::endl; + m.swap_rows(i0, i1); + + for (unsigned j = 0; j < m.dimension(); j++) { + lean_assert(mcopy(i0, j) == m(i1, j)); + lean_assert(mcopy(i1, j) == m(i0, j)); + } +} +template +void test_swap_columns(sparse_matrix& m, unsigned i0, unsigned i1){ + std::cout << "test_swap_columns(" << i0 << "," << i1 << ")" << std::endl; + sparse_matrix mcopy(m.dimension()); + for (unsigned i = 0; i < m.dimension(); i++) + for (unsigned j = 0; j < m.dimension(); j++) { + mcopy(i, j)= m(i, j); + } + m.swap_columns(i0, i1); + + for (unsigned j = 0; j < m.dimension(); j++) { + lean_assert(mcopy(j, i0) == m(j, i1)); + lean_assert(mcopy(j, i1) == m(j, i0)); + } + + for (unsigned i = 0; i < m.dimension(); i++) { + if (i == i0 || i == i1) + continue; + for (unsigned j = 0; j < m.dimension(); j++) { + lean_assert(mcopy(j, i)== m(j, i)); + } + } +} +#endif + +template +void fill_matrix(sparse_matrix& m){ + int v = 0; + for (int i = m.dimension() - 1; i >= 0; i--) { + for (int j = m.dimension() - 1; j >=0; j--){ + m(i, j) = v++; + } + } +} + +void test_pivot_like_swaps_and_pivot(){ + sparse_matrix m(10); + fill_matrix(m); + // print_matrix(m); +// pivot at 2,7 + m.swap_columns(0, 7); + // print_matrix(m); + m.swap_rows(2, 0); + // print_matrix(m); + for (unsigned i = 1; i < m.dimension(); i++) { + m(i, 0) = 0; + } + // print_matrix(m); + +// say pivot at 3,4 + m.swap_columns(1, 4); + // print_matrix(m); + m.swap_rows(1, 3); + // print_matrix(m); + + vector row; + float alpha = 2.33; + unsigned pivot_row = 1; + unsigned target_row = 2; + unsigned pivot_row_0 = 3; + float beta = 3.1; + m(target_row, 3) = 0; + m(target_row, 5) = 0; + m(pivot_row, 6) = 0; +#ifndef NDEBUG + print_matrix(m); +#endif + + for (unsigned j = 0; j < m.dimension(); j++) { + row.push_back(m(target_row, j) + alpha * m(pivot_row, j) + beta * m(pivot_row_0, j)); + } + + for (auto & t : row) { + cout << t << ","; + } + cout << endl; + lp_settings settings; + m.pivot_row_to_row(pivot_row, alpha, target_row, settings); + m.pivot_row_to_row(pivot_row_0, beta, target_row, settings); + // print_matrix(m); + for (unsigned j = 0; j < m.dimension(); j++) { + lean_assert(abs(row[j] - m(target_row, j)) < 0.00000001); + } +} + +#ifndef NDEBUG +void test_swap_rows() { + sparse_matrix m(10); + fill_matrix(m); + // print_matrix(m); + test_swap_rows(m, 3, 5); + + test_swap_rows(m, 1, 3); + + + test_swap_rows(m, 1, 3); + + test_swap_rows(m, 1, 7); + + test_swap_rows(m, 3, 7); + + test_swap_rows(m, 0, 7); + + m(0, 4) = 1; + // print_matrix(m); + test_swap_rows(m, 0, 7); + +// go over some corner cases + sparse_matrix m0(2); + test_swap_rows(m0, 0, 1); + m0(0, 0) = 3; + test_swap_rows(m0, 0, 1); + m0(1, 0) = 3; + test_swap_rows(m0, 0, 1); + + + sparse_matrix m1(10); + test_swap_rows(m1, 0, 1); + m1(0, 0) = 3; + test_swap_rows(m1, 0, 1); + m1(1, 0) = 3; + m1(0, 3) = 5; + m1(1, 3) = 4; + m1(1, 8) = 8; + m1(1, 9) = 8; + + test_swap_rows(m1, 0, 1); + + sparse_matrix m2(3); + test_swap_rows(m2, 0, 1); + m2(0, 0) = 3; + test_swap_rows(m2, 0, 1); + m2(2, 0) = 3; + test_swap_rows(m2, 0, 2); +} + +void fill_uniformly(sparse_matrix & m, unsigned dim) { + int v = 0; + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + m(i, j) = v++; + } + } +} + +void fill_uniformly(dense_matrix & m, unsigned dim) { + int v = 0; + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + m.set_elem(i, j, v++); + } + } +} + +void sparse_matrix_with_permutaions_test() { + unsigned dim = 4; + sparse_matrix m(dim); + fill_uniformly(m, dim); + dense_matrix dm(dim, dim); + fill_uniformly(dm, dim); + dense_matrix dm0(dim, dim); + fill_uniformly(dm0, dim); + permutation_matrix q0(dim); + q0[0] = 1; + q0[1] = 0; + q0[2] = 3; + q0[3] = 2; + permutation_matrix q1(dim); + q1[0] = 1; + q1[1] = 2; + q1[2] = 3; + q1[3] = 0; + permutation_matrix p0(dim); + p0[0] = 1; + p0[1] = 0; + p0[2] = 3; + p0[3] = 2; + permutation_matrix p1(dim); + p1[0] = 1; + p1[1] = 2; + p1[2] = 3; + p1[3] = 0; + + m.multiply_from_left(q0); + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + lean_assert(m(i, j) == dm0.get_elem(q0[i], j)); + } + } + + auto q0_dm = q0 * dm; + lean_assert(m == q0_dm); + + m.multiply_from_left(q1); + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], j)); + } + } + + + auto q1_q0_dm = q1 * q0_dm; + + lean_assert(m == q1_q0_dm); + + m.multiply_from_right(p0); + + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p0[j])); + } + } + + auto q1_q0_dm_p0 = q1_q0_dm * p0; + + lean_assert(m == q1_q0_dm_p0); + + m.multiply_from_right(p1); + + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p0[j]])); + } + } + + auto q1_q0_dm_p0_p1 = q1_q0_dm_p0 * p1; + lean_assert(m == q1_q0_dm_p0_p1); + + m.multiply_from_right(p1); + for (unsigned i = 0; i < dim; i++) { + for (unsigned j = 0; j < dim; j++) { + lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p1[p0[j]]])); + } + } + auto q1_q0_dm_p0_p1_p1 = q1_q0_dm_p0_p1 * p1; + + lean_assert(m == q1_q0_dm_p0_p1_p1); +} + +void test_swap_columns() { + sparse_matrix m(10); + fill_matrix(m); + // print_matrix(m); + + test_swap_columns(m, 3, 5); + + test_swap_columns(m, 1, 3); + + test_swap_columns(m, 1, 3); + + // print_matrix(m); + test_swap_columns(m, 1, 7); + + test_swap_columns(m, 3, 7); + + test_swap_columns(m, 0, 7); + + test_swap_columns(m, 0, 7); + +// go over some corner cases + sparse_matrix m0(2); + test_swap_columns(m0, 0, 1); + m0(0, 0) = 3; + test_swap_columns(m0, 0, 1); + m0(0, 1) = 3; + test_swap_columns(m0, 0, 1); + + + sparse_matrix m1(10); + test_swap_columns(m1, 0, 1); + m1(0, 0) = 3; + test_swap_columns(m1, 0, 1); + m1(0, 1) = 3; + m1(3, 0) = 5; + m1(3, 1) = 4; + m1(8, 1) = 8; + m1(9, 1) = 8; + + test_swap_columns(m1, 0, 1); + + sparse_matrix m2(3); + test_swap_columns(m2, 0, 1); + m2(0, 0) = 3; + test_swap_columns(m2, 0, 1); + m2(0, 2) = 3; + test_swap_columns(m2, 0, 2); +} + + + +void test_swap_operations() { + test_swap_rows(); + test_swap_columns(); +} +#endif +#ifndef NDEBUG +void test_dense_matrix() { + dense_matrix d(3, 2); + d.set_elem(0, 0, 1); + d.set_elem(1, 1, 2); + d.set_elem(2, 0, 3); + // print_matrix(d); + + dense_matrix unit(2, 2); + d.set_elem(0, 0, 1); + d.set_elem(1, 1, 1); + + dense_matrix c = d * unit; + + // print_matrix(d); + + dense_matrix perm(3, 3); + perm.set_elem(0, 1, 1); + perm.set_elem(1, 0, 1); + perm.set_elem(2, 2, 1); + auto c1 = perm * d; + // print_matrix(c1); + + + dense_matrix p2(2, 2); + p2.set_elem(0, 1, 1); + p2.set_elem(1, 0, 1); + auto c2 = d * p2; +} + +void test_conjugate_eta_matrix() { + permutation_matrix p(5); + p[0] = 3; p[1] = 2; p[2] = 1; p[3] = 4; + p[4] = 0; + + cout << "p="; p.print(); +#ifndef NDEBUG + eta_matrix l(2, 5); +#else + eta_matrix l(2); +#endif + for (unsigned i = 3; i <= 4; i++) + l.push_back(i, i+2); // i+2 for the value + + l.set_diagonal_element(10); + + cout << "l" << endl; + print_matrix(l); + dense_matrix lcopy(l); + + l.conjugate_by_permutation(p); + + permutation_matrix pr = p.get_inverse(); + + auto conj = lcopy * pr; + cout << "U*pr" << endl; + print_matrix(conj); + conj = p * conj; + cout << "conj " << endl; + print_matrix(conj); + cout << "l" << endl; + print_matrix(l); + lean_assert(conj == l); +} + +void test_conjugate0() { + permutation_matrix p(5); + p[0] = 3; p[1] = 2; p[2] = 1; p[3] = 4; + p[4] = 0; + + one_off_diagonal_matrix one_off(1, 4, 2, 3); + one_off.set_number_of_rows(5); + one_off.set_number_of_columns(5); + one_off_diagonal_matrix one_off_copy(1, 4, 2, 3); + one_off_copy.set_number_of_rows(5); + one_off_copy.set_number_of_columns(5); + one_off.conjugate_by_permutation(p); + + permutation_matrix pr = p.get_inverse(); + + auto conj = one_off_copy * (pr); + conj = p * conj; + lean_assert(conj == one_off); +} + +void test_conjugate_perm(){ + permutation_matrix p(5); + p[0] = 1; p[1] = 2; p[2] = 3; p[3] = 4; + p[4] = 0; + + one_off_diagonal_matrix one_off(1, 3, 2, 3); + one_off.set_number_of_rows(5); + one_off.set_number_of_columns(5); + one_off_diagonal_matrix one_off_copy(1, 3, 2, 3); + one_off_copy.set_number_of_rows(5); + one_off_copy.set_number_of_columns(5); + one_off.conjugate_by_permutation(p); + + permutation_matrix pr = p.get_inverse(); + + auto conj = one_off_copy * pr; + conj = p * conj; + lean_assert(conj == one_off); + test_conjugate0(); +} + +void test_conjugate() { + permutation_matrix p(5); + p[0] = 1; p[1] = 2; p[2] = 3; p[3] = 4; + p[4] = 0; + + one_off_diagonal_matrix one_off(1, 3, 2, 3); + one_off.set_number_of_rows(5); + one_off.set_number_of_columns(5); + one_off_diagonal_matrix one_off_copy(1, 3, 2, 3); + one_off_copy.set_number_of_rows(5); + one_off_copy.set_number_of_columns(5); + one_off.conjugate_by_permutation(p); + + permutation_matrix pr = p.get_inverse(); + + auto conj = one_off_copy * pr; + conj = p * conj; + lean_assert(conj == one_off); + test_conjugate0(); +} +#endif + +std::vector> vector_of_permutaions() { + std::vector> ret; + { + permutation_matrix p0(5); + p0[0] = 1; p0[1] = 2; p0[2] = 3; p0[3] = 4; + p0[4] = 0; + ret.push_back(p0); + } + { + permutation_matrix p0(5); + p0[0] = 2; p0[1] = 0; p0[2] = 1; p0[3] = 4; + p0[4] = 3; + ret.push_back(p0); + } + return ret; +} + +void test_apply_reverse_from_right_to_perm(permutation_matrix & l) { + permutation_matrix p(5); + p[0] = 4; p[1] = 2; p[2] = 0; p[3] = 3; + p[4] = 1; + + permutation_matrix pclone(5); + pclone[0] = 4; pclone[1] = 2; pclone[2] = 0; pclone[3] = 3; + pclone[4] = 1; + + p.multiply_by_reverse_from_right(l); +#ifndef NDEBUG + auto rev = l.get_inverse(); + auto rs = pclone * rev; + lean_assert(p == rs) +#endif +} + +void test_apply_reverse_from_right() { + auto vec = vector_of_permutaions(); + for (unsigned i = 0; i < vec.size(); i++) { + test_apply_reverse_from_right_to_perm(vec[i]); + } +} + +void test_permutations() { + test_apply_reverse_from_right(); +} + +#ifndef NDEBUG +void test_perm_apply_reverse_from_right() { + permutation_generator allp(5); + vector w(6); + for (int i = 0; i < 5; i ++) { + w[i] = i; + } + + while (allp.move_next()){ + allp.current()->apply_reverse_from_right(w); + } +} +#endif +void lp_solver_test() { + // lp_revised_solver lp_revised; + // lp_revised.get_minimal_solution(); +} + +bool get_int_from_args_parser(const char * option, argument_parser & args_parser, unsigned & n) { + string s = args_parser.get_option_value(option); + if (s.size() > 0) { + n = atoi(s.c_str()); + return true; + } + return false; +} + +bool get_double_from_args_parser(const char * option, argument_parser & args_parser, double & n) { + string s = args_parser.get_option_value(option); + if (s.size() > 0) { + n = atof(s.c_str()); + return true; + } + return false; +} + + +void update_settings(argument_parser & args_parser, lp_settings& settings) { + unsigned n; + if (get_int_from_args_parser("--rep_frq", args_parser, n)) + settings.report_frequency = n; + + if (get_int_from_args_parser("--percent_for_enter", args_parser, n)) + settings.percent_of_entering_to_check = n; + if (get_int_from_args_parser("--partial_pivot", args_parser, n)) { + cout << "setting partial pivot constant to " << n << endl; + settings.c_partial_pivoting = n; + } + if (get_int_from_args_parser("--density", args_parser, n)) { + double density = static_cast(n) / 100.0; + cout << "setting density to " << density << endl; + settings.density_threshold = density; + } + if (get_int_from_args_parser("--maxng", args_parser, n)) + settings.max_number_of_iterations_with_no_improvements = n; + double d; + if (get_double_from_args_parser("--harris_toler", args_parser, d)) { + cout << "setting harris_feasibility_tolerance to " << d << endl; + settings.harris_feasibility_tolerance = d; + } +} + + +void setup_solver(unsigned max_iterations, unsigned time_limit, bool look_for_min, argument_parser & args_parser, lp_solver * solver) { + if (max_iterations > 0) + solver->set_max_iterations_per_stage(max_iterations); + + if (time_limit > 0) + solver->set_time_limit(time_limit); + + if (look_for_min) + solver->flip_costs(); + + update_settings(args_parser, solver->settings()); +} + +bool values_are_one_percent_close(double a, double b); + +void print_x(mps_reader & reader, lp_solver * solver) { + for (auto name : reader.column_names()) { + std::cout << name << "=" << solver->get_column_value_by_name(name) << ' '; + } + cout << endl; +} + +void compare_solutions(mps_reader & reader, lp_solver * solver, lp_solver * solver0) { + for (auto name : reader.column_names()) { + double a = solver->get_column_value_by_name(name); + double b = solver0->get_column_value_by_name(name); + if (!values_are_one_percent_close(a, b)) { + cout << "different values for " << name << ":" << a << " and " << b << endl; + } + } +} + + +void solve_mps_double(std::string file_name, bool look_for_min, unsigned max_iterations, unsigned time_limit, bool dual, bool compare_with_primal, argument_parser & args_parser) { + mps_reader reader(file_name); + reader.read(); + if (!reader.is_ok()) { + std::cout << "cannot process " << file_name << std::endl; + return; + } + lp_solver * solver = reader.create_solver(dual); + setup_solver(max_iterations, time_limit, look_for_min, args_parser, solver); + int begin = get_millisecond_count(); + if (dual) { + cout << "solving for dual" << endl; + } + solver->find_maximal_solution(); + int span = get_millisecond_span(begin); + std::cout << "Status: " << lp_status_to_string(solver->get_status()) << std::endl; + if (solver->get_status() == lp_status::OPTIMAL) { + if (reader.column_names().size() < 20) { + print_x(reader, solver); + } + double cost = solver->get_current_cost(); + if (look_for_min) { + cost = -cost; + } + std::cout << "cost = " << cost << std::endl; + } + cout << "processed in " << span / 1000.0 << " seconds, running for " << solver->m_total_iterations << " iterations" << endl; + if (compare_with_primal) { + auto * primal_solver = reader.create_solver(false); + setup_solver(max_iterations, time_limit, look_for_min, args_parser, primal_solver); + primal_solver->find_maximal_solution(); + if (solver->get_status() != primal_solver->get_status()) { + cout << "statuses are different: dual " << lp_status_to_string(solver->get_status()) << " primal = " << lp_status_to_string(primal_solver->get_status()) << endl; + } else { + if (solver->get_status() == lp_status::OPTIMAL) { + double cost = solver->get_current_cost(); + if (look_for_min) { + cost = -cost; + } + double primal_cost = primal_solver->get_current_cost(); + if (look_for_min) { + primal_cost = -primal_cost; + } + cout << "primal cost = " << primal_cost << endl; + if (!values_are_one_percent_close(cost, primal_cost)) { + compare_solutions(reader, primal_solver, solver); + print_x(reader, primal_solver); + cout << "dual cost is " << cost << ", but primal cost is " << primal_cost << endl; + lean_assert(false); + } + } + } + delete primal_solver; + } + delete solver; +} + +void solve_mps_rational(std::string file_name, bool look_for_min, unsigned max_iterations, unsigned time_limit, bool dual, argument_parser & /*args_parser*/) { + mps_reader reader(file_name); + reader.read(); + if (reader.is_ok()) { + auto * solver = reader.create_solver(dual); + if (look_for_min) { + solver->flip_costs(); + } + int begin = get_millisecond_count(); + if (max_iterations > 0) { + solver->set_max_iterations_per_stage(max_iterations); + } + + if (time_limit > 0) { + solver->set_time_limit(time_limit); + } + solver->find_maximal_solution(); + std::cout << "Status: " << lp_status_to_string(solver->get_status()) << std::endl; + + if (solver->get_status() == lp_status::OPTIMAL) { + // for (auto name: reader.column_names()) { + // std::cout << name << "=" << solver->get_column_value_by_name(name) << ' '; + // } + mpq cost = solver->get_current_cost(); + if (look_for_min) { + cost = -cost; + } + std::cout << "cost = " << cost.get_double() << std::endl; + } + cout << "processed in " << get_millisecond_span(begin) / 1000.0 << " seconds, running for " << solver->m_total_iterations << " iterations" << endl; + delete solver; + } else { + std::cout << "cannot process " << file_name << std::endl; + } +} +void get_time_limit_and_max_iters_from_parser(argument_parser & args_parser, unsigned & time_limit, unsigned & max_iters); // forward definition + +void solve_mps(std::string file_name, bool look_for_min, unsigned max_iterations, unsigned time_limit, bool solve_for_rational, bool dual, bool compare_with_primal, argument_parser & args_parser) { + if (!solve_for_rational) { + std::cout << "solving " << file_name << std::endl; + solve_mps_double(file_name, look_for_min, max_iterations, time_limit, dual, compare_with_primal, args_parser); + } else { + std::cout << "solving " << file_name << " in rationals " << std::endl; + solve_mps_rational(file_name, look_for_min, max_iterations, time_limit, dual, args_parser); + } +} + +void solve_mps(string file_name, argument_parser & args_parser) { + bool look_for_min = args_parser.option_is_used("--min"); + unsigned max_iterations, time_limit; + bool solve_for_rational = args_parser.option_is_used("--mpq"); + bool dual = args_parser.option_is_used("--dual"); + bool compare_with_primal = args_parser.option_is_used("--compare_with_primal"); + get_time_limit_and_max_iters_from_parser(args_parser, time_limit, max_iterations); + solve_mps(file_name, look_for_min, max_iterations, time_limit, solve_for_rational, dual, compare_with_primal, args_parser); +} + +void solve_mps_in_rational(std::string file_name, bool dual, argument_parser & /*args_parser*/) { + std::cout << "solving " << file_name << std::endl; + + mps_reader reader(file_name); + reader.read(); + if (reader.is_ok()) { + auto * solver = reader.create_solver(dual); + solver->find_maximal_solution(); + std::cout << "status is " << lp_status_to_string(solver->get_status()) << std::endl; + if (solver->get_status() == lp_status::OPTIMAL) { + if (reader.column_names().size() < 20) { + for (auto name : reader.column_names()) { + std::cout << name << "=" << solver->get_column_value_by_name(name).get_double() << ' '; + } + } + std::cout << std::endl << "cost = " << numeric_traits::get_double(solver->get_current_cost()) << std::endl; + } + delete solver; + } else { + std::cout << "cannot process " << file_name << std::endl; + } +} + +void test_upair_queue() { + int n = 10; + binary_heap_upair_queue q(2); + unordered_map m; + for (int k = 0; k < 100; k++) { + int i = lrand48()%n; + int j = lrand48()%n; + q.enqueue(i, j, lrand48()%n); + } + + q.remove(5, 5); + + while (!q.is_empty()) { + unsigned i, j; + q.dequeue(i, j); + } +} + +void test_binary_priority_queue() { + cout << "testing binary_heap_priority_queue..."; + auto q = binary_heap_priority_queue(10); + q.enqueue(2, 2); + q.enqueue(1, 1); + q.enqueue(9, 9); + q.enqueue(8, 8); + q.enqueue(5, 25); + q.enqueue(3, 3); + q.enqueue(4, 4); + q.enqueue(7, 30); + q.enqueue(6, 6); + q.enqueue(0, 0); + q.enqueue(5, 5); + q.enqueue(7, 7); + + for (unsigned i = 0; i < 10; i++) { + unsigned de = q.dequeue(); + lean_assert(i == de); + cout << de << endl; + } + q.enqueue(2, 2); + q.enqueue(1, 1); + q.enqueue(9, 9); + q.enqueue(8, 8); + q.enqueue(5, 5); + q.enqueue(3, 3); + q.enqueue(4, 4); + q.enqueue(7, 2); + q.enqueue(0, 1); + q.enqueue(6, 6); + q.enqueue(7, 7); + q.enqueue(33, 1000); + q.enqueue(20, 0); + q.dequeue(); + q.remove(33); + q.enqueue(0, 0); +#ifndef NDEBUG + unsigned t = 0; +#endif + while (q.size() > 0) { + unsigned d =q.dequeue(); + lean_assert(t++ == d); + cout << d << endl; + } + + test_upair_queue(); + cout << " done" << endl; +} + +bool solution_is_feasible(std::string file_name, const std::unordered_map & solution) { + mps_reader reader(file_name); + reader.read(); + if (reader.is_ok()) { + lp_primal_simplex * solver = static_cast *>(reader.create_solver(false)); + return solver->solution_is_feasible(solution); + } + return false; +} + + +void solve_mps_with_known_solution(std::string file_name, std::unordered_map * solution, lp_status status, bool dual) { + std::cout << "solving " << file_name << std::endl; + mps_reader reader(file_name); + reader.read(); + if (reader.is_ok()) { + auto * solver = reader.create_solver(dual); + solver->find_maximal_solution(); + std::cout << "status is " << lp_status_to_string(solver->get_status()) << std::endl; + if (status != solver->get_status()){ + cout << "status should be " << lp_status_to_string(status) << endl; + lean_assert(status == solver->get_status()); + throw "status is wrong"; + } + if (solver->get_status() == lp_status::OPTIMAL) { + std::cout << "cost = " << solver->get_current_cost() << std::endl; + if (solution != nullptr) { + for (auto it : *solution) { + if (fabs(it.second - solver->get_column_value_by_name(it.first)) >= 0.000001) { + std::cout << "expected:" << it.first << "=" << + it.second <<", got " << solver->get_column_value_by_name(it.first) << std::endl; + } + lean_assert(fabs(it.second - solver->get_column_value_by_name(it.first)) < 0.000001); + } + } + if (reader.column_names().size() < 20) { + for (auto name : reader.column_names()) { + std::cout << name << "=" << solver->get_column_value_by_name(name) << ' '; + } + cout << endl; + } + } + delete solver; + } else { + std::cout << "cannot process " << file_name << std::endl; + } +} + +int get_random_rows() { + return 5 + rand_r(& seed) % 2; +} + +int get_random_columns() { + return 5 + rand_r(& seed) % 3; +} + +int get_random_int() { + return -1 + rand_r(& seed) % 2; // (1.0 + RAND_MAX); +} + +void add_random_row(lp_primal_simplex * solver, int cols, int row) { + solver->add_constraint(lp_relation::Greater_or_equal, 1, row); + for (int i = 0; i < cols; i++) { + solver->set_row_column_coefficient(row, i, get_random_int()); + } +} + +void add_random_cost(lp_primal_simplex * solver, int cols) { + for (int i = 0; i < cols; i++) { + solver->set_cost_for_column(i, get_random_int()); + } +} + +lp_primal_simplex * generate_random_solver() { + int rows = get_random_rows(); + int cols = get_random_columns(); + auto * solver = new lp_primal_simplex(); + for (int i = 0; i < rows; i++) { + add_random_row(solver, cols, i); + } + add_random_cost(solver, cols); + return solver; +} + + + +void random_test_on_i(unsigned i) { + if (i % 1000 == 0) { + cout << "."; + } + srand(i); + auto *solver = generate_random_solver(); + solver->find_maximal_solution(); + // cout << lp_status_to_string(solver->get_status()) << endl; + delete solver; +} + +void random_test() { + for (unsigned i = 0; i < UINT_MAX; i++) { + try { + random_test_on_i(i); + } + catch (const char * error) { + cout << "i = " << i << ", throwing at ' " << error << "'" << endl; + break; + } + } +} + + +void fill_file_names(std::vector &file_names, std::set & minimums) { + char *home_dir = getenv("HOME"); + if (home_dir == nullptr) { + cout << "cannot find home directory, don't know how to find the files"; + return; + } + string home_dir_str(home_dir); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l0redund.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l1.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l2.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l3.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l4.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l4fix.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/plan.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/samp2.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/murtagh.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l0.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AFIRO.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC50B.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC50A.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/KB2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC105.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STOCFOR1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/ADLITTLE.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BLEND.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCAGR7.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC205.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHARE2B.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/RECIPELP.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/LOTFI.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/VTP-BASE.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHARE1B.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BOEING2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BORE3D.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCORPION.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/CAPRI.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BRANDY.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCAGR25.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/ISRAEL.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCFXM1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BANDM.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/E226.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AGG.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GROW7.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/ETAMACRO.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FINNIS.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCSD1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STANDATA.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STANDGUB.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BEACONFD.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STAIR.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STANDMPS.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GFRD-PNC.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCRS8.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BOEING1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/MODSZK1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/DEGEN2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FORPLAN.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AGG2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AGG3.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCFXM2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHELL.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT4.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCSD6.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP04S.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SEBA.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GROW15.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FFFFF800.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BNL1.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PEROLD.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/QAP8.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCFXM3.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP04L.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GANGES.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GROW22.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP08S.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT-WE.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/MAROS.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STOCFOR2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/25FV47.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP12S.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCSD8.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT1P.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP3.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SIERRA.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOTNOV.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/CZPROB.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT1D.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT-JA.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP08L.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BNL2.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/NESM.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/CYCLE.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/acc-tight5.mps"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP12L.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/DEGEN3.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEA.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEB.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/80BAU3B.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/TRUSS.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/D2Q06C.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/WOODW.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/QAP12.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/D6CUBE.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/DFL001.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/WOOD1P.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT2P.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT87.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STOCFOR3.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/QAP15.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT2D.SIF"); + file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/MAROS-R7.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/FIT2P.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/DFL001.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/D2Q06C.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/80BAU3B.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEB.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEA.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/BNL2.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SHIP08L.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/FIT1D.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP3.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SCSD8.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SCSD6.SIF"); + minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/MAROS-R7.SIF"); +} + +void test_out_dir(string out_dir) { + DIR *out_dir_p = opendir(out_dir.c_str()); + if (out_dir_p == nullptr) { + cout << "creating directory " << out_dir << endl; + int res = mkdir(out_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (res) { + cout << "Cannot open output directory \"" << out_dir << "\"" << endl; + } + return; + } + closedir(out_dir_p); +} + +void find_dir_and_file_name(string a, string & dir, string& fn) { + // todo: make it system independent + size_t last_slash_pos = a.find_last_of("/"); + if (last_slash_pos >= a.size()) { + cout << "cannot find file name in " << a << endl; + throw; + } + dir = a.substr(0, last_slash_pos); + // cout << "dir = " << dir << endl; + fn = a.substr(last_slash_pos + 1); + // cout << "fn = " << fn << endl; +} + +void process_test_file(string test_dir, string test_file_name, argument_parser & args_parser, string out_dir, unsigned max_iters, unsigned time_limit, unsigned & successes, unsigned & failures, unsigned & inconclusives); + +void solve_some_mps(argument_parser & args_parser) { + unsigned max_iters, time_limit; + get_time_limit_and_max_iters_from_parser(args_parser, time_limit, max_iters); + unsigned successes = 0; + unsigned failures = 0; + unsigned inconclusives = 0; + std::set minimums; + std::vector file_names; + fill_file_names(file_names, minimums); + bool solve_for_rational = args_parser.option_is_used("--mpq"); + bool dual = args_parser.option_is_used("--dual"); + bool compare_with_primal = args_parser.option_is_used("--compare_with_primal"); + bool compare_with_glpk = args_parser.option_is_used("--compare_with_glpk"); + if (compare_with_glpk) { + string out_dir = args_parser.get_option_value("--out_dir"); + if (out_dir.size() == 0) { + out_dir = "/tmp/test"; + } + test_out_dir(out_dir); + for (auto& a : file_names) { + try { + string file_dir; + string file_name; + find_dir_and_file_name(a, file_dir, file_name); + process_test_file(file_dir, file_name, args_parser, out_dir, max_iters, time_limit, successes, failures, inconclusives); + } + catch(const char *s){ + std::cout<< "exception: "<< s << std::endl; + } + } + cout << "comparing with glpk: successes " << successes << ", failures " << failures << ", inconclusives " << inconclusives << endl; + return; + } + if (!solve_for_rational) { + solve_mps(file_names[6], false, 0, time_limit, false, dual, compare_with_primal, args_parser); + solve_mps_with_known_solution(file_names[3], nullptr, INFEASIBLE, dual); // chvatal: 135(d) + std::unordered_map sol; + sol["X1"] = 0; + sol["X2"] = 6; + sol["X3"] = 0; + sol["X4"] = 15; + sol["X5"] = 2; + sol["X6"] = 1; + sol["X7"] = 1; + sol["X8"] = 0; + solve_mps_with_known_solution(file_names[9], &sol, OPTIMAL, dual); + solve_mps_with_known_solution(file_names[0], &sol, OPTIMAL, dual); + sol.clear(); + sol["X1"] = 25.0/14.0; + // sol["X2"] = 0; + // sol["X3"] = 0; + // sol["X4"] = 0; + // sol["X5"] = 0; + // sol["X6"] = 0; + // sol["X7"] = 9.0/14.0; + solve_mps_with_known_solution(file_names[5], &sol, OPTIMAL, dual); // chvatal: 135(e) + solve_mps_with_known_solution(file_names[4], &sol, OPTIMAL, dual); // chvatal: 135(e) + solve_mps_with_known_solution(file_names[2], nullptr, UNBOUNDED, dual); // chvatal: 135(c) + solve_mps_with_known_solution(file_names[1], nullptr, UNBOUNDED, dual); // chvatal: 135(b) + solve_mps(file_names[8], false, 0, time_limit, false, dual, compare_with_primal, args_parser); + // return; + for (auto& s : file_names) { + try { + solve_mps(s, minimums.find(s) != minimums.end(), max_iters, time_limit, false, dual, compare_with_primal, args_parser); + } + catch(const char *s){ + std::cout<< "exception: "<< s << std::endl; + } + } + } else { + unsigned i = 0; + for (auto& s : file_names) { + if (i++ > 9) return; + try { + solve_mps_in_rational(s, dual, args_parser); + } + catch(const char *s){ + std::cout<< "exception: "<< s << std::endl; + } + } + } +} + +void solve_rational() { + lp_primal_simplex solver; + solver.add_constraint(lp_relation::Equal, mpq(7), 0); + solver.add_constraint(lp_relation::Equal, mpq(-3), 1); + + // setting the cost + std::array cost = {{-3, -1, -1, 2, -1, 1, 1, -4}}; + std::array var_names={{"x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8"}}; + + for (unsigned i = 0; i < 8; i++) { + solver.set_cost_for_column(i, mpq(cost[i])); + solver.give_symbolic_name_to_column(var_names[i], i); + } + + std::array row0 = {{1, 0, 3, 1, -5, -2 , 4, -6}}; + for (unsigned i = 0; i < 8; i++) { + solver.set_row_column_coefficient(0, i, mpq(row0[i])); + } + + std::array row1 = {{0, 1, -2, -1, 4, 1, -3, 5}}; + for (unsigned i = 0; i < 8; i++) { + solver.set_row_column_coefficient(1, i, mpq(row1[i])); + } + + std::array bounds = {{8, 6, 4, 15, 2, 10, 10, 3}}; + for (unsigned i = 0; i < 8; i++) { + solver.set_low_bound(i, mpq(0)); + solver.set_upper_bound(i, mpq(bounds[i])); + } + + std::unordered_map expected_sol; + expected_sol["x1"] = mpq(0); + expected_sol["x2"] = mpq(6); + expected_sol["x3"] = mpq(0); + expected_sol["x4"] = mpq(15); + expected_sol["x5"] = mpq(2); + expected_sol["x6"] = mpq(1); + expected_sol["x7"] = mpq(1); + expected_sol["x8"] = mpq(0); + solver.find_maximal_solution(); + lean_assert(solver.get_status() == OPTIMAL); + for (auto it : expected_sol) { + lean_assert(it.second == solver.get_column_value_by_name(it.first)); + } +} + + +string read_line(bool & end, ifstream & file) { + string s; + if (!getline(file, s)) { + end = true; + return string(); + } + end = false; + return s; +} + +bool contains(string const & s, char const * pattern) { + return s.find(pattern) != string::npos; +} + + +unordered_map * get_solution_from_glpsol_output(string & file_name) { + ifstream file(file_name); + if (!file.is_open()){ + cerr << "cannot open " << file_name << endl; + return nullptr; + } + string s; + bool end; + do { + s = read_line(end, file); + if (end) { + cerr << "unexpected file end " << file_name << endl; + return nullptr; + } + if (contains(s, "Column name")){ + break; + } + } while (true); + + read_line(end, file); + if (end) { + cerr << "unexpected file end " << file_name << endl; + return nullptr; + } + + auto ret = new unordered_map(); + + do { + s = read_line(end, file); + if (end) { + cerr << "unexpected file end " << file_name << endl; + return nullptr; + } + auto split = string_split(s, " \t", false); + if (split.size() == 0) { + return ret; + } + + lean_assert(split.size() > 3); + (*ret)[split[1]] = atof(split[3].c_str()); + } while (true); +} + + + +void test_init_U() { + static_matrix m(3, 7); + m(0, 0) = 10; m(0, 1) = 11; m(0, 2) = 12; m(0, 3) = 13; m(0, 4) = 14; + m(1, 0) = 20; m(1, 1) = 21; m(1, 2) = 22; m(1, 3) = 23; m(1, 5) = 24; + m(2, 0) = 30; m(2, 1) = 31; m(2, 2) = 32; m(2, 3) = 33; m(2, 6) = 34; +#ifndef NDEBUG + print_matrix(m); +#endif + std::vector basis(3); + basis[0] = 1; + basis[1] = 2; + basis[2] = 4; + + sparse_matrix u(m, basis); + + for (unsigned i = 0; i < 3; i++) { + for (unsigned j = 0; j < 3; j ++) { + lean_assert(m(i, basis[j]) == u(i, j)); + } + } + + // print_matrix(m); + // print_matrix(u); +} + +void test_replace_column() { + sparse_matrix m(10); + fill_matrix(m); + m.swap_columns(0, 7); + m.swap_columns(6, 3); + m.swap_rows(2, 0); + for (unsigned i = 1; i < m.dimension(); i++) { + m(i, 0) = 0; + } + + indexed_vector w(m.dimension()); + for (unsigned i = 0; i < m.dimension(); i++) { + w.set_value(i % 3, i); + } + + lp_settings settings; + + for (unsigned column_to_replace = 0; column_to_replace < m.dimension(); column_to_replace ++) { + m.replace_column(column_to_replace, w, settings); + for (unsigned i = 0; i < m.dimension(); i++) { + lean_assert(abs(w[i] - m(i, column_to_replace)) < 0.00000001); + } + } +} + +void test_eta_matrix() { + sparse_matrix m(8); + fill_matrix(m); + lp_settings settings; + for (unsigned j = 0; j < m.dimension(); j++){ + eta_matrix * eta; + m.fill_eta_matrix(j, &eta); + m.prepare_for_factorization(); + + for (auto it = eta->get_sparse_vector_iterator(); !it.done(); it.move()) { + m.pivot_row_to_row(j, it.value(), it.index(), settings); + double de = eta->get_diagonal_element(); + m.divide_row_by_constant(j, de, settings); + } + delete eta; + } + + lean_assert(m.is_upper_triangular_and_maximums_are_set_correctly_in_rows(settings)); +} + + +void setup_args_parser(argument_parser & parser) { + parser.add_option_with_after_string_with_help("--density", "the percentage of non-zeroes in the matrix below which it is not dense"); + parser.add_option_with_after_string_with_help("--harris_toler", "harris tolerance"); + parser.add_option_with_help_string("--test_swaps", "test row swaps with a permutation"); + parser.add_option_with_after_string_with_help("--checklu", "the file name for lu checking"); + parser.add_option_with_after_string_with_help("--partial_pivot", "the partial pivot constant, a number somewhere between 10 and 100"); + parser.add_option_with_after_string_with_help("--percent_for_enter", "which percent of columns check for entering column"); + parser.add_option_with_help_string("--totalinf", "minimizes the total infeasibility instead of diminishin infeasibility of the rows"); + parser.add_option_with_after_string_with_help("--rep_frq", "the report frequency, in how many iterations print the cost and other info "); + parser.add_option_with_help_string("--smt", "smt file format"); + parser.add_option_with_after_string_with_help("--filelist", "the file containing the list of files"); + parser.add_option_with_after_string_with_help("--file", "the input file name"); + parser.add_option_with_help_string("--min", "will look for the minimum for the given file if --file is used; the default is looking for the max"); + parser.add_option_with_help_string("--max", "will look for the maximum for the given file if --file is used; it is the default behavior"); + parser.add_option_with_after_string_with_help("--max_iters", "maximum total iterations in a core solver stage"); + parser.add_option_with_after_string_with_help("--time_limit", "time limit in seconds"); + parser.add_option_with_help_string("--mpq", "solve for rational numbers"); + parser.add_option_with_help_string("--test_lu", "test the work of the factorization"); + parser.add_option_with_help_string("--test_larger_lu", "test the work of the factorization"); + parser.add_option_with_help_string("--test_larger_lu_with_holes", "test the work of the factorization"); + parser.add_option_with_help_string("--test_lp_0", "solve a small lp"); + parser.add_option_with_help_string("--solve_some_mps", "solves a list of mps problems"); + parser.add_option_with_after_string_with_help("--test_file_directory", "loads files from the directory for testing"); + parser.add_option_with_help_string("--compare_with_glpk", "compares the results by running glpsol"); + parser.add_option_with_after_string_with_help("--out_dir", "setting the output directory for tests, if not set /tmp is used"); + parser.add_option_with_help_string("--dual", "using the dual simplex solver"); + parser.add_option_with_help_string("--compare_with_primal", "using the primal simplex solver for comparison"); + parser.add_option_with_help_string("--lar", "test lar_solver"); + parser.add_option_with_after_string_with_help("--maxng", "max iterations without progress"); + parser.add_option_with_help_string("-tbq", "test binary queue"); +} + +void solve_test_flipped(bool dual) { + // solving a problem with a constraint xj <= c, a flipped constraint + char * home_dir = getenv("HOME"); + if (home_dir == nullptr) { + cout << "cannot find home directory" << endl; + return; + } + string file_name = string(home_dir) + "/projects/lean/src/tests/util/lp/l4.mps"; + mps_reader reader(file_name); + reader.read(); + + if (reader.is_ok()) { + auto * solver = reader.create_solver(dual); + solver->find_maximal_solution(); + lean_assert(solver->get_status() == OPTIMAL); + double x1_val = solver->get_column_value_by_name("X1"); + cout << "X1 = " << x1_val << endl; + mps_reader reader_(file_name); + reader_.read(); + auto solver_ = reader_.create_solver(dual); + int j = solver_ -> get_column_index_by_name("X1"); + lean_assert(j != -1) + solver_-> unset_low_bound(j); + solver_->set_upper_bound(j, x1_val + 1); + solver_->find_maximal_solution(); + cout << "new X1 = " << solver_->get_column_value_by_name("X1") << endl; + lean_assert(fabs(x1_val - solver_->get_column_value_by_name("X1")) < 1e-10); + delete solver; + delete solver_; + } +} + +template +void print_chunk(T * arr, unsigned len) { + for (unsigned i = 0; i < len; i++) { + cout << arr[i] << ", "; + } + cout << endl; +} + +struct mem_cpy_place_holder { + static void mem_copy_hook(int * destination, unsigned num) { + if (destination == nullptr || num == 0) { + throw "bad parameters"; + } + } +}; + +int finalize(unsigned ret) { + finalize_util_module(); + finalize_numerics_module(); + return ret; +} + +void get_time_limit_and_max_iters_from_parser(argument_parser & args_parser, unsigned & time_limit, unsigned & max_iters) { + string s = args_parser.get_option_value("--max_iters"); + if (s.size() > 0) { + max_iters = atoi(s.c_str()); + } else { + max_iters = 0; + } + + string time_limit_string = args_parser.get_option_value("--time_limit"); + if (time_limit_string.size() > 0) { + time_limit = atoi(time_limit_string.c_str()); + } else { + time_limit = 0; + } +} + + +string create_output_file_name(bool minimize, string file_name, bool mpq) { + string ret = file_name + "_lp_tst_" + (minimize?"min":"max"); + if (mpq) return ret + "_mpq.out"; + return ret + ".out"; +} + +string create_output_file_name_for_glpsol(bool minimize, string file_name){ + return file_name + (minimize?"_min":"_max") + "_glpk_out"; +} + +int run_glpk(string file_name, string glpk_out_file_name, bool minimize, unsigned time_limit) { + string minmax(minimize?"--min":"--max"); + string tmlim = time_limit > 0 ? string(" --tmlim ") + std::to_string(time_limit)+ " ":string(); + string command_line = string("glpsol --nointopt --nomip ") + minmax + tmlim + + " -o " + glpk_out_file_name +" " + file_name + " > /dev/null"; + return system(command_line.c_str()); +} + +string get_status(string file_name) { + std::ifstream f(file_name); + if (!f.is_open()) { + cout << "cannot open " << file_name << endl; + throw 0; + } + string str; + while (getline(f, str)) { + if (str.find("Status") != string::npos) { + vector tokens = split_and_trim(str); + if (tokens.size() != 2) { + cout << "unexpected Status string " << str << endl; + throw 0; + } + return tokens[1]; + } + } + cout << "cannot find the status line in " << file_name << endl; + throw 0; +} + +// returns true if the costs should be compared too +bool compare_statuses(string glpk_out_file_name, string lp_out_file_name, unsigned & successes, unsigned & failures) { + string glpk_status = get_status(glpk_out_file_name); + string lp_tst_status = get_status(lp_out_file_name); + + if (glpk_status != lp_tst_status) { + if (glpk_status == "UNDEFINED" && (lp_tst_status == "UNBOUNDED" || lp_tst_status == "INFEASIBLE")) { + successes++; + return false; + } else { + cout << "glpsol and lp_tst disagree: glpsol status is " << glpk_status; + cout << " but lp_tst status is " << lp_tst_status << endl; + failures++; + return false; + } + } + return lp_tst_status == "OPTIMAL"; +} + +double get_glpk_cost(string file_name) { + std::ifstream f(file_name); + if (!f.is_open()) { + cout << "cannot open " << file_name << endl; + throw 0; + } + string str; + while (getline(f, str)) { + if (str.find("Objective") != string::npos) { + vector tokens = split_and_trim(str); + if (tokens.size() != 5) { + cout << "unexpected Objective string " << str << endl; + throw 0; + } + return atof(tokens[3].c_str()); + } + } + cout << "cannot find the Objective line in " << file_name << endl; + throw 0; +} + +double get_lp_tst_cost(string file_name) { + std::ifstream f(file_name); + if (!f.is_open()) { + cout << "cannot open " << file_name << endl; + throw 0; + } + string str; + string cost_string; + while (getline(f, str)) { + if (str.find("cost") != string::npos) { + cost_string = str; + } + } + if (cost_string.size() == 0) { + cout << "cannot find the cost line in " << file_name << endl; + throw 0; + } + + vector tokens = split_and_trim(cost_string); + if (tokens.size() != 3) { + cout << "unexpected cost string " << cost_string << endl; + throw 0; + } + return atof(tokens[2].c_str()); +} + +bool values_are_one_percent_close(double a, double b) { + double maxval = std::max(fabs(a), fabs(b)); + if (maxval < 0.000001) { + return true; + } + + double one_percent = maxval / 100; + return fabs(a - b) <= one_percent; +} + +// returns true if both are optimal +void compare_costs(string glpk_out_file_name, + string lp_out_file_name, + unsigned & successes, + unsigned & failures) { + double a = get_glpk_cost(glpk_out_file_name); + double b = get_lp_tst_cost(lp_out_file_name); + + if (values_are_one_percent_close(a, b)) { + successes++; + } else { + failures++; + cout << "glpsol cost is " << a << " lp_tst cost is " << b << endl; + } +} + + + +void compare_with_glpk(string glpk_out_file_name, string lp_out_file_name, unsigned & successes, unsigned & failures, string lp_file_name) { + std::unordered_map * solution_table = get_solution_from_glpsol_output(glpk_out_file_name); + if (solution_is_feasible(lp_file_name, *solution_table)) { + cout << "glpk solution is feasible" << endl; + } else { + cout << "glpk solution is infeasible" << endl; + } + delete solution_table; + if (compare_statuses(glpk_out_file_name, lp_out_file_name, successes, failures)) { + compare_costs(glpk_out_file_name, lp_out_file_name, successes, failures); + } +} +void test_lar_on_file(string file_name, argument_parser & args_parser); + +void process_test_file(string test_dir, string test_file_name, argument_parser & args_parser, string out_dir, unsigned max_iters, unsigned time_limit, unsigned & successes, unsigned & failures, unsigned & inconclusives) { + bool use_mpq = args_parser.option_is_used("--mpq"); + bool minimize = args_parser.option_is_used("--min"); + string full_lp_tst_out_name = out_dir + "/" + create_output_file_name(minimize, test_file_name, use_mpq); + + string input_file_name = test_dir + "/" + test_file_name; + if (input_file_name[input_file_name.size() - 1] == '~') { + // cout << "ignoring " << input_file_name << endl; + return; + } + cout <<"processing " << input_file_name << endl; + + std::ofstream out(full_lp_tst_out_name); + if (!out.is_open()) { + cout << "cannot open file " << full_lp_tst_out_name << endl; + throw 0; + } + std::streambuf *coutbuf = std::cout.rdbuf(); // save old buffer + std::cout.rdbuf(out.rdbuf()); // redirect std::cout to dir_entry->d_name! + bool dual = args_parser.option_is_used("--dual"); + try { + if (args_parser.option_is_used("--lar")) + test_lar_on_file(input_file_name, args_parser); + else + solve_mps(input_file_name, minimize, max_iters, time_limit, use_mpq, dual, false, args_parser); + } + catch(...) { + cout << "catching the failure" << endl; + failures++; + std::cout.rdbuf(coutbuf); // reset to standard output again + return; + } + std::cout.rdbuf(coutbuf); // reset to standard output again + + if (args_parser.option_is_used("--compare_with_glpk")) { + string glpk_out_file_name = out_dir + "/" + create_output_file_name_for_glpsol(minimize, string(test_file_name)); + int glpk_exit_code = run_glpk(input_file_name, glpk_out_file_name, minimize, time_limit); + if (glpk_exit_code != 0) { + cout << "glpk failed" << endl; + inconclusives++; + } else { + compare_with_glpk(glpk_out_file_name, full_lp_tst_out_name, successes, failures, input_file_name); + } + } +} + +vector> get_file_list_of_dir(string test_file_dir) { + DIR *dir; + if ((dir = opendir(test_file_dir.c_str())) == nullptr) { + cout << "Cannot open directory " << test_file_dir << endl; + throw 0; + } + vector> ret; + struct dirent entry; + struct dirent* result; + int return_code; + for (return_code = readdir_r(dir, &entry, &result); + result != NULL && return_code == 0; + return_code = readdir_r(dir, &entry, &result)) { + DIR *tmp_dp = opendir(entry.d_name); + struct stat file_record; + if (tmp_dp == nullptr) { + string s = test_file_dir+ "/" + entry.d_name; + int stat_ret = stat(s.c_str(), & file_record); + if (stat_ret!= -1) { + ret.push_back(make_pair(entry.d_name, file_record.st_size)); + } else { + perror("stat"); + exit(1); + } + } else { + closedir(tmp_dp); + } + } + closedir(dir); + return ret; +} + + +struct file_size_comp { + unordered_map& m_file_sizes; + file_size_comp(unordered_map& fs) :m_file_sizes(fs) {} + int operator()(string a, string b) { + cout << m_file_sizes.size() << endl; + cout << a << endl; + cout << b << endl; + + auto ls = m_file_sizes.find(a); + cout << "fa" << endl; + auto rs = m_file_sizes.find(b); + cout << "fb" << endl; + if (ls != m_file_sizes.end() && rs != m_file_sizes.end()) { + cout << "fc " << endl; + int r = (*ls < *rs? -1: (*ls > *rs)? 1 : 0); + cout << "calc r " << endl; + return r; + } else { + cout << "sc " << endl; + return 0; + } + } +}; + + +struct sort_pred { + bool operator()(const std::pair &left, const std::pair &right) { + return left.second < right.second; + } +}; + + +void test_files_from_directory(string test_file_dir, argument_parser & args_parser) { + cout << "loading files from directory \"" << test_file_dir << "\"" << endl; + string out_dir = args_parser.get_option_value("--out_dir"); + if (out_dir.size() == 0) { + out_dir = "/tmp/test"; + } + DIR *out_dir_p = opendir(out_dir.c_str()); + if (out_dir_p == nullptr) { + cout << "Cannot open output directory \"" << out_dir << "\"" << endl; + return; + } + closedir(out_dir_p); + vector> files = get_file_list_of_dir(test_file_dir); + std::sort(files.begin(), files.end(), sort_pred()); + unsigned max_iters, time_limit; + get_time_limit_and_max_iters_from_parser(args_parser, time_limit, max_iters); + unsigned successes = 0, failures = 0, inconclusives = 0; + for (auto & t : files) { + process_test_file(test_file_dir, t.first, args_parser, out_dir, max_iters, time_limit, successes, failures, inconclusives); + } + cout << "comparing with glpk: successes " << successes << ", failures " << failures << ", inconclusives " << inconclusives << endl; +} + + +unordered_map get_solution_map(lp_solver * lps, mps_reader & reader) { + unordered_map ret; + for (auto it : reader.column_names()) { + ret[it] = lps->get_column_value_by_name(it); + } + return ret; +} + +void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_reader * reader) { + string maxng = args_parser.get_option_value("--maxng"); + if (maxng.size() > 0) { + solver->settings().max_number_of_iterations_with_no_improvements = atoi(maxng.c_str()); + } + if (args_parser.option_is_used("--totalinf")) { + solver->settings().row_feasibility = false; + } + if (args_parser.option_is_used("--mpq")) { + solver->settings().use_double_solver_for_lar = false; + } + string iter = args_parser.get_option_value("--max_iters"); + if (iter.size() > 0) { + solver->settings().max_total_number_of_iterations = atoi(iter.c_str()); + } + if (args_parser.option_is_used("--compare_with_primal")){ + if (reader == nullptr) { + cout << "cannot compare with primal, the reader is null " << endl; + return; + } + auto * lps = reader->create_solver(false); + lps->find_maximal_solution(); + unordered_map sol = get_solution_map(lps, *reader); + mpq inf = solver->get_infeasibility_of_solution(sol); + cout << "inf with primal = " << inf << endl; + return; + } + int begin = get_millisecond_count(); + lp_status status = solver->check(); + cout << "status is " << lp_status_to_string(status) << ", processed for " << get_millisecond_span(begin) / 1000.0 <<" seconds, and " << solver->get_total_iterations() << " iterations" << endl; + if (solver->get_status() == INFEASIBLE) { + buffer> evidence; + solver->get_infeasibility_evidence(evidence); + } +} + +void test_lar_on_file(string file_name, argument_parser & args_parser) { + lar_solver * solver = nullptr; + cout << "processing " << file_name << endl; + if (args_parser.option_is_used("--smt")) { + smt_reader reader(file_name); + reader.read(); + if (!reader.is_ok()){ + std::cout << "cannot process " << file_name << std::endl; + return; + } + solver = reader.create_lar_solver(); + run_lar_solver(args_parser, solver, nullptr); + delete solver; + return; + } + mps_reader reader(file_name); + reader.read(); + if (!reader.is_ok()) { + std::cout << "cannot process " << file_name << std::endl; + return; + } + solver = reader.create_lar_solver(); + run_lar_solver(args_parser, solver, & reader); + delete solver; +} + +vector get_file_names_from_file_list(string filelist) { + ifstream file(filelist); + if (!file.is_open()) { + cout << "cannot open " << filelist << endl; + return vector(); + } + vector ret; + bool end; + do { + string s = read_line(end, file); + if (end) + break; + if (s.size() == 0) + break; + ret.push_back(s); + } while (true); + return ret; +} + +void test_lar_solver(argument_parser & args_parser) { + string file_name = args_parser.get_option_value("--file"); + if (file_name.size() > 0) { + test_lar_on_file(file_name, args_parser); + return; + } + + string file_list = args_parser.get_option_value("--filelist"); + if (file_list.size() > 0) { + for (string fn : get_file_names_from_file_list(file_list)) + test_lar_on_file(fn, args_parser); + return; + } +} + +void test_numeric_pair() { + numeric_pair a; + numeric_pair b(2, mpq(6, 2)); + a = b; + numeric_pair c(0.1, 0.5); + a += 2*c; + a -= c; + lean_assert (a == b + c); + numeric_pair d = a * 2; + cout << a << endl; + lean_assert(b == b); + lean_assert(b < a); + lean_assert(b <= a); + lean_assert(a > b); + lean_assert(a != b); + lean_assert(a >= b); + lean_assert(-a < b); + lean_assert(a < 2 * b); + lean_assert(b + b > a); + lean_assert(mpq(2.1) * b + b > a); + lean_assert(-b * mpq(2.1) - b < mpq(0.99) * a); + cout << - b * mpq(2.1) - b << endl; + lean_assert(-b *(mpq(2.1) + 1) == - b * mpq(2.1) - b); +} + +void get_matrix_dimensions(ifstream & f, unsigned & m, unsigned & n) { + string line; + getline(f, line); + getline(f, line); + vector r = split_and_trim(line); + m = atoi(r[1].c_str()); + getline(f, line); + r = split_and_trim(line); + n = atoi(r[1].c_str()); +} + +void read_row_cols(unsigned i, static_matrix& A, ifstream & f) { + do { + string line; + getline(f, line); + if (line== "row_end") + break; + auto r = split_and_trim(line); + lean_assert(r.size() == 4); + unsigned j = atoi(r[1].c_str()); + double v = atof(r[3].c_str()); + A.set(i, j, v); + } while (true); +} + +bool read_row(static_matrix & A, ifstream & f) { + string line; + getline(f, line); + if (static_cast(line.find("row")) == -1) + return false; + auto r = split_and_trim(line); + if (r[0] != "row") + cout << "wrong row line" << line << endl; + unsigned i = atoi(r[1].c_str()); + read_row_cols(i, A, f); + return true; +} + +void read_rows(static_matrix& A, ifstream & f) { + while (read_row(A, f)) {} +} + +void read_basis(vector & basis, ifstream & f) { + cout << "reading basis" << endl; + string line; + getline(f, line); + lean_assert(line == "basis_start"); + do { + getline(f, line); + if (line == "basis_end") + break; + unsigned j = atoi(line.c_str()); + basis.push_back(j); + } while (true); +} + +void read_indexed_vector(indexed_vector & v, ifstream & f) { + string line; + getline(f, line); + lean_assert(line == "vector_start"); + do { + getline(f, line); + if (line == "vector_end") break; + auto r = split_and_trim(line); + unsigned i = atoi(r[0].c_str()); + double val = atof(r[1].c_str()); + v.set_value(val, i); + cout << "setting value " << i << " = " << val << endl; + } while (true); +} + +void check_lu_from_file(string lufile_name) { + ifstream f(lufile_name); + if (!f.is_open()) { + cout << "cannot open file " << lufile_name << endl; + } + unsigned m, n; + get_matrix_dimensions(f, m, n); + cout << "init matrix " << m << " by " << n << endl; + static_matrix A(m, n); + read_rows(A, f); + vector basis; + read_basis(basis, f); + indexed_vector v(m); + // read_indexed_vector(v, f); + f.close(); + vector basis_heading; + lp_settings settings; + vector non_basic_columns; + lu lsuhl(A, basis, basis_heading, settings, non_basic_columns); + vector d(A.row_count()); +#ifndef NDEBUG + lp_settings::ddd = 1; +#endif + unsigned entering = 26; + lsuhl.solve_Bd(entering, d, v); +#ifndef NDEBUG + auto B = get_B(lsuhl); + vector a(m); + A.copy_column_to_vector(entering, a); + vector cd(d); + B.apply_from_left(cd, settings); + lean_assert(vectors_are_equal(cd , a)); +#endif +} + +void test_square_dense_submatrix() { + cout << "testing square_dense_submatrix" << endl; + unsigned parent_dim = 7; + sparse_matrix parent(parent_dim); + fill_matrix(parent); + unsigned index_start = 3; + square_dense_submatrix d; + d.init(&parent, index_start); + for (unsigned i = index_start; i < parent_dim; i++) + for (unsigned j = index_start; j < parent_dim; j++) + d[i][j] = i*3+j*2; +#ifndef NDEBUG + unsigned dim = parent_dim - index_start; + dense_matrix m(dim, dim); + for (unsigned i = index_start; i < parent_dim; i++) + for (unsigned j = index_start; j < parent_dim; j++) + m[i-index_start][j-index_start] = d[i][j]; + print_matrix(m); +#endif + for (unsigned i = index_start; i < parent_dim; i++) + for (unsigned j = index_start; j < parent_dim; j++) + d[i][j] = d[j][i]; +#ifndef NDEBUG + for (unsigned i = index_start; i < parent_dim; i++) + for (unsigned j = index_start; j < parent_dim; j++) + m[i-index_start][j-index_start] = d[i][j]; + + print_matrix(m); + cout << endl; +#endif +} + + +int main(int argn, char * const * argv) { + initialize_util_module(); + initialize_numerics_module(); + int ret; + argument_parser args_parser(argn, argv); + setup_args_parser(args_parser); + + if (!args_parser.parse()) { + cout << args_parser.m_error_message << endl; + cout << args_parser.usage_string(); + ret = 1; + return finalize(ret); + } + cout << "the options are " << endl; + args_parser.print(); + string lufile = args_parser.get_option_value("--checklu"); + if (lufile.size()) { + check_lu_from_file(lufile); + return finalize(0); + } + +#ifndef NDEBUG + if (args_parser.option_is_used("--test_swaps")) { + sparse_matrix m(10); + fill_matrix(m); + test_swap_rows_with_permutation(m); + test_swap_cols_with_permutation(m); + return finalize(0); + } +#endif + if (args_parser.option_is_used("--test_file_directory")) { + test_files_from_directory(args_parser.get_option_value("--test_file_directory"), args_parser); + return finalize(0); + } + if (args_parser.option_is_used("--lar")){ + cout <<"calling test_lar_solver" << endl; + test_lar_solver(args_parser); + return finalize(0); + } + string file_list = args_parser.get_option_value("--filelist"); + if (file_list.size() > 0) { + for (string fn : get_file_names_from_file_list(file_list)) + solve_mps(fn, args_parser); + return finalize(0); + } + + if (args_parser.option_is_used("-tbq")) { + test_binary_priority_queue(); + ret = 0; + return finalize(ret); + } + +#ifndef NDEBUG + lp_settings settings; + update_settings(args_parser, settings); + if (args_parser.option_is_used("--test_lu")) { + test_lu(settings); + ret = 0; + return finalize(ret); + } + + if (args_parser.option_is_used("--test_larger_lu")) { + test_larger_lu(settings); + ret = 0; + return finalize(ret); + } + + if (args_parser.option_is_used("--test_larger_lu_with_holes")) { + test_larger_lu_with_holes(settings); + ret = 0; + return finalize(ret); + } +#endif + + if (args_parser.option_is_used("--test_lp_0")) { + test_lp_0(); + ret = 0; + return finalize(ret); + } + + + unsigned max_iters; + unsigned time_limit; + get_time_limit_and_max_iters_from_parser(args_parser, time_limit, max_iters); + bool dual = args_parser.option_is_used("--dual"); + bool solve_for_rational = args_parser.option_is_used("--mpq"); + string file_name = args_parser.get_option_value("--file"); + if (file_name.size() > 0) { + solve_mps(file_name, args_parser.option_is_used("--min"), max_iters, time_limit, solve_for_rational, dual, args_parser.option_is_used("--compare_with_primal"), args_parser); + ret = 0; + return finalize(ret); + } + + if (args_parser.option_is_used("--solve_some_mps")) { + solve_some_mps(args_parser); + ret = 0; + return finalize(ret); + } + // lean::ccc = 0; + return finalize(0); + test_init_U(); + test_replace_column(); +#ifndef NDEBUG + test_perm_apply_reverse_from_right(); + test_conjugate_perm(); + sparse_matrix_with_permutaions_test(); + test_conjugate(); + test_dense_matrix(); + test_swap_operations(); + test_permutations(); + test_pivot_like_swaps_and_pivot(); +#endif + tst1(); + std::cout<< "done with LP tests\n"; + return finalize(has_violations() ? 1 : 0); +} diff --git a/src/tests/util/lp/mps_reader.h b/src/tests/util/lp/mps_reader.h new file mode 100644 index 0000000000..77c9394abd --- /dev/null +++ b/src/tests/util/lp/mps_reader.h @@ -0,0 +1,838 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once + +// reads an MPS file reperesenting a Mixed Integer Program +#include +#include +#include +#include "util/lp/lp_primal_simplex.h" +#include "util/lp/lp_dual_simplex.h" +#include "util/lp/lar_solver.h" +#include +#include +#include +#include +#include +namespace lean { +using namespace std; + // trim from start +inline string <rim(std::string &s) { + s.erase(s.begin(), find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); + return s; +} + + + + + // trim from end +inline string &rtrim(std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); + return s; +} + // trim from both ends +inline string &trim(std::string &s) { + return ltrim(rtrim(s)); +} + +inline string trim(std::string const &r) { + string s = r; + return ltrim(rtrim(s)); +} + + +inline vector string_split(const string &source, const char *delimiter, bool keep_empty) { + vector results; + size_t prev = 0; + size_t next = 0; + while ((next = source.find_first_of(delimiter, prev)) != std::string::npos) { + if (keep_empty || (next - prev != 0)) { + results.push_back(source.substr(prev, next - prev)); + } + prev = next + 1; + } + if (prev < source.size()) { + results.push_back(source.substr(prev)); + } + return results; +} + +inline vector split_and_trim(string line) { + auto split = string_split(line, " \t", false); + vector ret; + for (auto s : split) { + ret.push_back(trim(s)); + } + return ret; +} + +template +class mps_reader { + enum row_type { Cost, Less_or_equal, Greater_or_equal, Equal }; + struct bound { + bool m_low_is_set = true; + T m_low; + bool m_upper_is_set = false; + T m_upper; + bool m_value_is_fixed = false; + T m_fixed_value; + bool m_free = false; + // constructor + bound() : m_low(numeric_traits::zero()) {} // it seems all mps files I have seen have the default low value 0 on a variable + }; + + struct column { + string m_name; + bound * m_bound = nullptr; + unsigned m_index; + column(string name, unsigned index): m_name(name), m_index(index) { + } + }; + + struct row { + row_type m_type; + string m_name; + unordered_map m_row_columns; + T m_right_side = numeric_traits::zero(); + unsigned m_index; + T m_range = numeric_traits::zero(); + row(row_type type, string name, unsigned index) : m_type(type), m_name(name), m_index(index) { + } + }; + + string m_file_name; + bool m_is_OK = true; + unordered_map m_rows; + unordered_map m_columns; + string m_line; + string m_name; + string m_cost_row_name; + ifstream m_file_stream; + // needed to adjust the index row + unsigned m_cost_line_count = 0; + unsigned m_line_number = 0; + + + void set_m_ok_to_false() { + cout << "setting m_is_OK to false" << endl; + m_is_OK = false; + } + + string get_string_from_position(unsigned offset) { + unsigned i = offset; + for (; i < m_line.size(); i++){ + if (m_line[i] == ' ') + break; + } + lean_assert(m_line.size() >= offset); + lean_assert(m_line.size() >> i); + lean_assert(i >= offset); + return m_line.substr(offset, i - offset); + } + + void set_boundary_for_column(unsigned col, bound * b, lp_solver * solver){ + if (b == nullptr) { + solver->set_low_bound(col, numeric_traits::zero()); + return; + } + + if (b->m_free) { + return; + } + if (b->m_low_is_set) { + solver->set_low_bound(col, b->m_low); + } + if (b->m_upper_is_set) { + solver->set_upper_bound(col, b->m_upper); + } + + if (b->m_value_is_fixed) { + solver->set_fixed_value(col, b->m_fixed_value); + } + } + + bool all_white_space() { + for (unsigned i = 0; i < m_line.size(); i++) { + char c = m_line[i]; + if (c != ' ' && c != '\t') { + return false; + } + } + return true; + } + + void read_line() { + while (m_is_OK) { + if (!getline(m_file_stream, m_line)) { + m_line_number++; + set_m_ok_to_false(); + cout << "cannot read from file" << endl; + } + m_line_number++; + if (m_line.size() != 0 && m_line[0] != '*' && !all_white_space()) + break; + } + } + + void read_name() { + do { + read_line(); + if (!m_line.find("NAME") == 0) { + continue; + } + m_line = m_line.substr(4); + m_name = trim(m_line); + break; + } while (m_is_OK); + } + + void read_rows() { + // look for start of the rows + read_line(); + do { + if (m_line.find("ROWS") >= 0) { + break; + } + } while (m_is_OK); + do { + read_line(); + if (m_line.find("COLUMNS") == 0) { + break; + } + add_row(); + } while (m_is_OK); + } + + void read_column_by_columns(string column_name, string column_data) { + // uph, let us try to work with columns + if (column_data.size() >= 22) { + string ss = column_data.substr(0, 8); + string row_name = trim(ss); + auto t = m_rows.find(row_name); + + if (t == m_rows.end()) { + cout << "cannot find " << row_name << endl; + goto fail; + } else { + row * row = t->second; + row->m_row_columns[column_name] = atof(column_data.substr(8).c_str()); + if (column_data.size() > 24) { + column_data = column_data.substr(25); + if (column_data.size() >= 22) { + read_column_by_columns(column_name, column_data); + } + } + } + } else { + fail: + set_m_ok_to_false(); + cout << "cannot understand this line" << endl; + cout << "line = " << m_line << ", line number is " << m_line_number << endl; + return; + } + } + + void read_column(string column_name, string column_data){ + auto tokens = split_and_trim(column_data); + for (int i = 0; i < tokens.size() - 1; i+= 2) { + auto row_name = tokens[i]; + if (row_name == "'MARKER'") return; // it is the integrality marker, no real data here + auto t = m_rows.find(row_name); + if (t == m_rows.end()) { + read_column_by_columns(column_name, column_data); + return; + } + row *r = t->second; + r->m_row_columns[column_name] = atof(tokens[i + 1].c_str()); + } + } + + void read_columns(){ + string column_name; + do { + read_line(); + if (m_line.find("RHS") == 0) { + // cout << "found RHS" << endl; + break; + } + if (m_line.size() < 22) { + cout << "line is too short for a column" << endl; + cout << m_line << endl; + cout << "line number is " << m_line_number << endl; + set_m_ok_to_false(); + return; + } + string column_name_tmp = trim(m_line.substr(4, 8)); + if (!column_name_tmp.empty()) { + column_name = column_name_tmp; + } + auto col_it = m_columns.find(column_name); + mps_reader::column * col; + if (col_it == m_columns.end()) { + col = new mps_reader::column(column_name, m_columns.size()); + m_columns[column_name] = col; + // cout << column_name << '[' << col->m_index << ']'<< endl; + } else { + col = col_it->second; + } + read_column(column_name, m_line.substr(14)); + } while (m_is_OK); + } + + void read_rhs() { + do { + read_line(); + if (m_line.find("BOUNDS") == 0 || m_line.find("ENDATA") == 0 || m_line.find("RANGES") == 0) { + break; + } + fill_rhs(); + } while (m_is_OK); + } + + + void fill_rhs_by_columns(string rhsides) { + // uph, let us try to work with columns + if (rhsides.size() >= 22) { + string ss = rhsides.substr(0, 8); + string row_name = trim(ss); + auto t = m_rows.find(row_name); + + if (t == m_rows.end()) { + cout << "cannot find " << row_name << endl; + goto fail; + } else { + row * row = t->second; + row->m_right_side = atof(rhsides.substr(8).c_str()); + if (rhsides.size() > 24) { + rhsides = rhsides.substr(25); + if (rhsides.size() >= 22) { + fill_rhs_by_columns(rhsides); + } + } + } + } else { + fail: + set_m_ok_to_false(); + cout << "cannot understand this line" << endl; + cout << "line = " << m_line << ", line number is " << m_line_number << endl; + return; + } + } + + void fill_rhs() { + if (m_line.size() < 14) { + cout << "line is too short" << endl; + cout << m_line << endl; + cout << "line number is " << m_line_number << endl; + set_m_ok_to_false(); + return; + } + string rhsides = m_line.substr(14); + vector splitted_line = split_and_trim(rhsides); + + for (unsigned i = 0; i < splitted_line.size() - 1; i += 2) { + auto t = m_rows.find(splitted_line[i]); + if (t == m_rows.end()) { + fill_rhs_by_columns(rhsides); + return; + } + row * row = t->second; + row->m_right_side = atof(splitted_line[i + 1].c_str()); + } + } + + void read_bounds() { + if (!m_line.find("BOUNDS") == 0) { + return; + } + + do { + read_line(); + if (m_line[0] != ' ') { + break; + } + create_or_update_bound(); + } while (m_is_OK); + } + + void read_ranges() { + if (!m_line.find("RANGES") == 0) { + return; + } + do { + read_line(); + auto sl = split_and_trim(m_line); + if (sl.size() < 2) { + break; + } + read_range(sl); + } while (m_is_OK); + } + + + void read_bound_by_columns(string colstr) { + if (colstr.size() < 14) { + cout << "line is too short" << endl; + cout << m_line << endl; + cout << "line number is " << m_line_number << endl; + set_m_ok_to_false(); + return; + } + // uph, let us try to work with columns + if (colstr.size() >= 22) { + string ss = colstr.substr(0, 8); + string column_name = trim(ss); + auto t = m_columns.find(column_name); + + if (t == m_columns.end()) { + cout << "cannot find " << column_name << endl; + goto fail; + } else { + vector bound_string; + bound_string.push_back(column_name); + if (colstr.size() > 14) { + bound_string.push_back(colstr.substr(14)); + } + mps_reader::column * col = t->second; + bound * b = col->m_bound; + if (b == nullptr) { + col->m_bound = b = new bound(); + } + update_bound(b, bound_string); + } + } else { + fail: + set_m_ok_to_false(); + cout << "cannot understand this line" << endl; + cout << "line = " << m_line << ", line number is " << m_line_number << endl; + return; + } + } + + void update_bound(bound * b, vector bound_string) { + /* + UP means an upper bound is applied to the variable. A bound of type LO means a lower bound is applied. A bound type of FX ("fixed") means that the variable has upper and lower bounds equal to a single value. A bound type of FR ("free") means the variable has neither lower nor upper bounds and so can take on negative values. A variation on that is MI for free negative, giving an upper bound of 0 but no lower bound. Bound type PL is for a free positive for zero to plus infinity, but as this is the normal default, it is seldom used. There are also bound types for use in MIP models - BV for binary, being 0 or 1. UI for upper integer and LI for lower integer. SC stands for semi-continuous and indicates that the variable may be zero, but if not must be equal to at least the value given. + */ + + string bound_type = get_string_from_position(1); + if (bound_type == "BV") { + b->m_upper_is_set = true; + b->m_upper = 1; + return; + } + + if (bound_type == "UP" || bound_type == "UI" || bound_type == "LIMITMAX") { + if (bound_string.size() <= 1){ + set_m_ok_to_false(); + return; + } + double val = atof(bound_string[1].c_str()); + + b->m_upper_is_set = true; + b->m_upper= val; + } else if (bound_type == "LO" || bound_type == "LI") { + if (bound_string.size() <= 1){ + set_m_ok_to_false(); + return; + } + + double val = atof(bound_string[1].c_str()); + b->m_low_is_set = true; + b->m_low = val; + } else if (bound_type == "FR") { + b->m_free = true; + } else if (bound_type == "FX") { + if (bound_string.size() <= 1){ + set_m_ok_to_false(); + return; + } + + double val = atof(bound_string[1].c_str()); + b->m_value_is_fixed = true; + b->m_fixed_value = val; + } else if (bound_type == "PL") { + b->m_low_is_set = true; + b->m_low = 0; + } else if (bound_type == "MI") { + b->m_upper_is_set = true; + b->m_upper = 0; + } else { + cout << "unexpected bound type " << bound_type << " at line " << m_line_number << endl; + set_m_ok_to_false(); + throw; + } + } + + void create_or_update_bound() { + const unsigned name_offset = 14; + lean_assert(m_line.size() >= 14); + vector bound_string = split_and_trim(m_line.substr(name_offset, m_line.size())); + + if (bound_string.size() == 0) { + set_m_ok_to_false(); + cout << "error at line " << m_line_number << endl; + throw m_line; + } + + string name = bound_string[0]; + auto it = m_columns.find(name); + if (it == m_columns.end()){ + read_bound_by_columns(m_line.substr(14)); + return; + } + mps_reader::column * col = it->second; + bound * b = col->m_bound; + if (b == nullptr) { + col->m_bound = b = new bound(); + } + update_bound(b, bound_string); + } + + + + void read_range_by_columns(string rhsides) { + if (m_line.size() < 14) { + cout << "line is too short" << endl; + cout << m_line << endl; + cout << "line number is " << m_line_number << endl; + set_m_ok_to_false(); + return; + } + // uph, let us try to work with columns + if (rhsides.size() >= 22) { + string ss = rhsides.substr(0, 8); + string row_name = trim(ss); + auto t = m_rows.find(row_name); + + if (t == m_rows.end()) { + cout << "cannot find " << row_name << endl; + goto fail; + } else { + row * row = t->second; + row->m_range = atof(rhsides.substr(8).c_str()); + maybe_modify_current_row_and_add_row_for_range(row); + if (rhsides.size() > 24) { + rhsides = rhsides.substr(25); + if (rhsides.size() >= 22) { + read_range_by_columns(rhsides); + } + } + } + } else { + fail: + set_m_ok_to_false(); + cout << "cannot understand this line" << endl; + cout << "line = " << m_line << ", line number is " << m_line_number << endl; + return; + } + } + + + void read_range(vector & splitted_line){ + for (unsigned i = 1; i < splitted_line.size() - 1; i += 2) { + auto it = m_rows.find(splitted_line[i]); + if (it == m_rows.end()) { + read_range_by_columns(m_line.substr(14)); + return; + } + row * row = it->second; + row->m_range = atof(splitted_line[i + 1].c_str()); + maybe_modify_current_row_and_add_row_for_range(row); + } + } + + void maybe_modify_current_row_and_add_row_for_range(row * row_with_range) { + unsigned index= m_rows.size() - m_cost_line_count; + string row_name = row_with_range->m_name + "_range"; + row * other_bound_range_row; + switch (row_with_range->m_type) { + case row_type::Greater_or_equal: + m_rows[row_name] = other_bound_range_row = new row(row_type::Less_or_equal, row_name, index); + other_bound_range_row->m_right_side = row_with_range->m_right_side + abs(row_with_range->m_range); + break; + case row_type::Less_or_equal: + m_rows[row_name] = other_bound_range_row = new row(row_type::Greater_or_equal, row_name, index); + other_bound_range_row->m_right_side = row_with_range->m_right_side - abs(row_with_range->m_range); + break; + case row_type::Equal: + if (row_with_range->m_range > 0) { + row_with_range->m_type = row_type::Greater_or_equal; // the existing row type change + m_rows[row_name] = other_bound_range_row = new row(row_type::Less_or_equal, row_name, index); + } else { // row->m_range < 0; + row_with_range->m_type = row_type::Less_or_equal; // the existing row type change + m_rows[row_name] = other_bound_range_row = new row(row_type::Greater_or_equal, row_name, index); + } + other_bound_range_row->m_right_side = row_with_range->m_right_side + row_with_range->m_range; + break; + default: + cout << "unexpected bound type " << row_with_range->m_type << " at line " << m_line_number << endl; + set_m_ok_to_false(); + throw; + } + + for (auto s : row_with_range->m_row_columns) { + lean_assert(m_columns.find(s.first) != m_columns.end()); + other_bound_range_row->m_row_columns[s.first] = s.second; + } + } + + void add_row() { + if (m_line.length() < 2) { + return; + } + + m_line = trim(m_line); + char c = m_line[0]; + m_line = m_line.substr(1); + m_line = trim(m_line); + add_row(c); + } + + void add_row(char c) { + unsigned index= m_rows.size() - m_cost_line_count; + switch (c) { + case 'E': + m_rows[m_line] = new row(row_type::Equal, m_line, index); + break; + case 'L': + m_rows[m_line] = new row(row_type::Less_or_equal, m_line, index); + break; + case 'G': + m_rows[m_line] = new row(row_type::Greater_or_equal, m_line, index); + break; + case 'N': + m_rows[m_line] = new row(row_type::Cost, m_line, index); + m_cost_row_name = m_line; + m_cost_line_count++; + break; + } + } + unsigned range_count() { + unsigned ret = 0; + for (auto s : m_rows) { + if (s.second->m_range != 0) { + ret++; + } + } + return ret; + } + + /* + If rhs is a constraint's right-hand-side value and range is the constraint's range value, then the range interval is defined according to the following table: + + sense interval + G [rhs, rhs + |range|] + L [rhs - |range|, rhs] + E [rhs, rhs + |range|] if range ¡Ý 0 [rhs - |range|, rhs] if range < 0 + where |range| is range's absolute value. + */ + + lp_relation get_relation_from_row(mps_reader::row_type row_type) { + switch (row_type) { + case mps_reader::row_type::Less_or_equal: return lp_relation::Less_or_equal; + case mps_reader::row_type::Greater_or_equal: return lp_relation::Greater_or_equal; + case mps_reader::row_type::Equal: return lp_relation::Equal; + default: + std::cout << "Unexpected row_type " << row_type << endl; + set_m_ok_to_false(); + throw; + } + } + + unsigned solver_row_count() { + return m_rows.size() - m_cost_line_count + range_count(); + } + + void fill_solver_on_row(row * row, lp_solver *solver) { + if (row->m_name != m_cost_row_name) { + solver->add_constraint(get_relation_from_row(row->m_type), row->m_right_side, row->m_index); + for (auto s : row->m_row_columns) { + lean_assert(m_columns.find(s.first) != m_columns.end()); + solver->set_row_column_coefficient(row->m_index, m_columns[s.first]->m_index, s.second); + } + } else { + set_solver_cost(row, solver); + } + } + + T abs(T & t) { return t < numeric_traits::zero() ? -t: t; } + + void fill_solver_on_rows(lp_solver * solver) { + for (auto row_it : m_rows) { + fill_solver_on_row(row_it.second, solver); + } + } + + + void fill_solver_on_columns(lp_solver * solver){ + for (auto s : m_columns) { + mps_reader::column * col = s.second; + unsigned index = col->m_index; + set_boundary_for_column(index, col->m_bound, solver); + // optional call + solver->give_symbolic_name_to_column(col->m_name, col->m_index); + } + } + + void fill_solver(lp_solver *solver) { + fill_solver_on_rows(solver); + fill_solver_on_columns(solver); + } + + void set_solver_cost(row * row, lp_solver *solver) { + for (auto s : row->m_row_columns) { + string name = s.first; + lean_assert(m_columns.find(name) != m_columns.end()); + mps_reader::column * col = m_columns[name]; + solver->set_cost_for_column(col->m_index, s.second); + } + } + +public: + vector column_names() { + vector v; + for (auto s : m_columns) { + v.push_back(s.first); + } + return v; + } + + ~mps_reader() { + for (auto s : m_rows) { + delete s.second; + } + for (auto s : m_columns) { + auto col = s.second; + auto b = col->m_bound; + if (b != nullptr) { + delete b; + } + delete col; + } + } + + mps_reader(string file_name): + m_file_name(file_name), m_file_stream(file_name) { + } + void read() { + if (!m_file_stream.is_open()){ + set_m_ok_to_false(); + return; + } + + read_name(); + read_rows(); + read_columns(); + read_rhs(); + if (m_line.find("BOUNDS") == 0) { + read_bounds(); + read_ranges(); + } else if (m_line.find("RANGES") == 0) { + read_ranges(); + read_bounds(); + } + } + + bool is_ok() { + return m_is_OK; + } + + lp_solver * create_solver(bool dual) { + lp_solver * solver = dual? (lp_solver*)new lp_dual_simplex() : new lp_primal_simplex(); + fill_solver(solver); + return solver; + } + + lconstraint_kind get_lar_relation_from_row(mps_reader::row_type row_type) { + switch (row_type) { + case Less_or_equal: return LE; + case Greater_or_equal: return GE; + case Equal: return EQ; + default: + std::cout << "Unexpected row_type " << row_type << endl; + set_m_ok_to_false(); + throw; + } + } + + void fill_lar_solver_on_row(row * row, lar_solver *solver) { + if (row->m_name != m_cost_row_name) { + auto kind = get_lar_relation_from_row(row->m_type); + buffer> ls; + for (auto s : row->m_row_columns) { + var_index i = solver->add_var(s.first); + ls.push_back(make_pair(s.second, i)); + } + solver->add_constraint(ls, kind, row->m_right_side); + } else { + // ignore the cost row + } + } + + + void fill_lar_solver_on_rows(lar_solver * solver) { + for (auto row_it : m_rows) { + fill_lar_solver_on_row(row_it.second, solver); + } + } + + void create_low_constraint_for_var(column* col, bound * b, lar_solver *solver) { + buffer> ls; + var_index i = solver->add_var(col->m_name); + ls.push_back(make_pair(numeric_traits::one(), i)); + solver->add_constraint(ls, GE, b->m_low); + } + + void create_upper_constraint_for_var(column* col, bound * b, lar_solver *solver) { + var_index i = solver->add_var(col->m_name); + buffer> ls; + ls.push_back(make_pair(numeric_traits::one(), i)); + solver->add_constraint(ls, LE, b->m_upper); + } + + void create_equality_contraint_for_var(column* col, bound * b, lar_solver *solver) { + var_index i = solver->add_var(col->m_name); + buffer> ls; + ls.push_back(make_pair(numeric_traits::one(), i)); + solver->add_constraint(ls, EQ, b->m_fixed_value); + } + + void fill_lar_solver_on_columns(lar_solver * solver) { + for (auto s : m_columns) { + mps_reader::column * col = s.second; + solver->add_var(col->m_name); + auto b = col->m_bound; + if (b == nullptr) return; + + if (b->m_free) continue; + + if (b->m_low_is_set) { + create_low_constraint_for_var(col, b, solver); + } + if (b->m_upper_is_set) { + create_upper_constraint_for_var(col, b, solver); + } + if (b->m_value_is_fixed) { + create_equality_contraint_for_var(col, b, solver); + } + } + } + + + void fill_lar_solver(lar_solver * solver) { + fill_lar_solver_on_columns(solver); + fill_lar_solver_on_rows(solver); + } + + lar_solver * create_lar_solver() { + lar_solver * solver = new lar_solver(); + fill_lar_solver(solver); + return solver; + } +}; +} diff --git a/src/tests/util/lp/murtagh.mps b/src/tests/util/lp/murtagh.mps new file mode 100644 index 0000000000..c03741b51b --- /dev/null +++ b/src/tests/util/lp/murtagh.mps @@ -0,0 +1,600 @@ +*NAME: OIL +*ROWS: 74 +*COLUMNS: 81 +*NONZERO: 504 +*OPT SOLN: 126.057 +*SOURCE: Bruce Murtagh, "Advanced Linear Programming" +*APPLICATION: oil refinery model +*COMMENTS: problem is maximization +* +NAME OIL REFINERY EXAMPLE +ROWS + N PROFIT + L MVOLBOL + L MVOLCOL + E MVOLLNC + E MVOLLNB + E MVOLSRK + E MVOLSRD + E MVOLVBB + E MVOLVBC + E MVOLRCR + E MVOLHVO + E UBALKWH + E UBALH2O + E UBALSTM + E UBALFUL + E MVOLB95 + E MVOLB90 + E MVOLLHG + E MVOLC3S + E MVOLNC4 + E MVOLLSR + E MVOLHSR + E MVOLIC4 + L VCAPSGP + E MVOLRFG + E MSCFHYL + E MVOLR90 + E MVOLR95 + E MVOLF90 + E MVOLF95 + L VCAPRFG + E MVOLLCO + E MVOLHHG + E MVOLHCD + L VCAPHVO + L VCAPHOL + E MVOLC3U + E MVOLC4U + E MVOLFCG + E MVOLSLR + L VCAPCCU + E MVOLLA3 + E MVOLLA4 + L VCAPALK + L XLPRPRE + L XHPRPRE + L XTELPRE + L XRVPPRE + L X200PRE + L X230PRE + E EVOLPRE + L XPSCPRE + L XRSCREG + L XLPRINT + L XHPRINT + L XTELINT + L XRVPINT + L X200INT + L X230INT + E EVOLINT + L XLPRREG + L XHPRREG + L XTELREG + L XRVPREG + L X200REG + L X230REG + E EVOLREG + E EVOLLPG + E EVOLJP4 + L XRVXJP4 + L XRVNJP4 + E EVOLDSL + E EVOLRSD + L XVISRSD +COLUMNS + VCRDBOL MVOLBOL 1.0 + VCRDBOL MVOLLNB -.537 + VCRDBOL MVOLSRK -.131 + VCRDBOL MVOLSRD -.1155 + VCRDBOL MVOLVBB -.037 + VCRDBOL MVOLRCR -.0365 + VCRDBOL MVOLHVO -.143 + VCRDBOL UBALKWH .302 + VCRDBOL UBALH2O .150 + VCRDBOL UBALSTM .003 + VCRDBOL UBALFUL .0587 + VCRDBOL PROFIT -12.8 + VCRDCOL MVOLCOL 1. + VCRDCOL MVOLLNC -.2931 + VCRDCOL MVOLSRK -.1170 + VCRDCOL MVOLSRD -.0649 + VCRDCOL MVOLVBC -.18 + VCRDCOL MVOLRCR -.1233 + VCRDCOL MVOLHVO -.2217 + VCRDCOL UBALKWH .384 + VCRDCOL UBALH2O .185 + VCRDCOL UBALSTM .003 + VCRDCOL UBALFUL .1053 + VCRDCOL PROFIT -11.48 + VSGPLNC MVOLLNC 1. + VSGPLNC MVOLC3S -.0112 + VSGPLNC MVOLNC4 -.0378 + VSGPLNC MVOLLSR -.1502 + VSGPLNC MVOLHSR -.7953 + VSGPLNC MVOLIC4 -.0099 + VSGPLNC UBALKWH .721 + VSGPLNC UBALH2O .185 + VSGPLNC UBALSTM .013 + VSGPLNC UBALFUL .0488 + VSGPLNC VCAPSGP 1. + VSGPLNB MVOLLNB 1. + VSGPLNB MVOLC3S -.0277 + VSGPLNB MVOLNC4 -.0563 + VSGPLNB MVOLLSR -.199 + VSGPLNB MVOLHSR -.6873 + VSGPLNB MVOLIC4 -.017 + VSGPLNB UBALKWH .495 + VSGPLNB UBALH2O .209 + VSGPLNB UBALSTM .013 + VSGPLNB UBALFUL .0506 + VSGPLNB VCAPSGP 1. + VSGPLHG MVOLLHG 1.0 + VSGPLHG MVOLC3S -.175 + VSGPLHG MVOLNC4 -.27 + VSGPLHG MVOLLSR -.028 + VSGPLHG MVOLIC4 -.455 + VSGPLHG UBALKWH .495 + VSGPLHG UBALH2O .209 + VSGPLHG UBALSTM .013 + VSGPLHG UBALFUL .0448 + VSGPB95 MVOLB95 1. + VSGPB95 MVOLC3S -.2836 + VSGPB95 MVOLNC4 -.3285 + VSGPB95 MVOLLSR -.0241 + VSGPB95 MVOLIC4 -.2502 + VSGPB95 UBALKWH .495 + VSGPB95 UBALH2O .209 + VSGPB95 UBALSTM .013 + VSGPB95 UBALFUL .0506 + VSGPB90 MVOLB90 1. + VSGPB90 MVOLC3S -.271 + VSGPB90 MVOLNC4 -.3289 + VSGPB90 MVOLLSR -.0255 + VSGPB90 MVOLIC4 -.2656 + VSGPB90 UBALKWH .495 + VSGPB90 UBALH2O .209 + VSGPB90 UBALSTM .013 + VSGPB90 UBALFUL .0506 + VH2RHSR MVOLHSR 1. + VH2RHSR MVOLRFG -1. + VH2RHSR MSCFHYL .0327 + VH2RHSR UBALKWH .793 + VH2RHSR UBALH2O .045 + VH2RHSR UBALFUL .094 + VH2RHSR PROFIT -.0176 + VRFFRF1 MVOLRFG 1.0 + VRFFRF1 MVOLR90 -1.0 + VRFFRF2 MVOLRFG 1.0 + VRFFRF2 MVOLR95 -1.0 + VRFFHH1 MVOLR90 -1.0 + VRFFHH1 MVOLHHG 1.0 + VRFFHH2 MVOLR95 -1.0 + VRFFHH2 MVOLHHG 1.0 + VRFGR90 MVOLR90 1.0 + VRFGR90 MVOLB90 -.0404 + VRFGR90 MVOLF90 -0.8564 + VRFGR90 MSCFHYL -0.8239 + VRFGR90 UBALKWH .792 + VRFGR90 UBALH2O .297 + VRFGR90 UBALSTM 0.0063 + VRFGR90 UBALFUL -0.156 + VRFGR90 VCAPRFG 1.0 + VRFGR90 PROFIT -0.1512 + VRFGR95 MVOLR95 1.0 + VRFGR95 MVOLB95 -0.0588 + VRFGR95 MVOLF95 -0.8145 + VRFGR95 MSCFHYL -.7689 + VRFGR95 UBALKWH 1.03 + VRFGR95 UBALH2O .387 + VRFGR95 UBALSTM 0.008 + VRFGR95 UBALFUL -.2112 + VRFGR95 VCAPRFG 1.3 + VRFGR95 PROFIT -0.304 + VHOLLCO MVOLLCO 1.0 + VHOLLCO MVOLHHG -.6627 + VHOLLCO MVOLLHG -0.2414 + VHOLLCO MVOLHCD -.2930 + VHOLLCO MSCFHYL 2.3 + VHOLLCO UBALFUL -.2054 + VHOLLCO UBALH2O 0.826 + VHOLLCO UBALKWH 14.61 + VHOLLCO VCAPHOL 1.0 + VHOLLCO PROFIT -0.2112 + VHOLSRD MVOLSRD 1.0 + VHOLSRD MVOLHHG -.6627 + VHOLSRD MVOLLHG -0.2414 + VHOLSRD MVOLHCD -.2930 + VHOLSRD MSCFHYL 2.3 + VHOLSRD UBALFUL -.2054 + VHOLSRD UBALH2O 0.826 + VHOLSRD UBALKWH 14.61 + VHOLSRD VCAPHOL 1.0 + VHOLSRD PROFIT -0.2112 + VHOLRCR MVOLRCR 1.0 + VHOLRCR MVOLHHG -.5875 + VHOLRCR MVOLLHG -0.3321 + VHOLRCR MVOLHCD -.3620 + VHOLRCR MSCFHYL 2.3 + VHOLRCR UBALFUL -.2054 + VHOLRCR UBALH2O 0.826 + VHOLRCR UBALKWH 14.61 + VHOLRCR VCAPHOL 1.0 + VHOLRCR PROFIT -0.2112 + VHOLHVO MVOLHVO 1.0 + VHOLHVO MVOLHHG -.5875 + VHOLHVO MVOLLHG -0.3321 + VHOLHVO MVOLHCD -.3620 + VHOLHVO MSCFHYL 2.3 + VHOLHVO UBALFUL -.2054 + VHOLHVO UBALH2O 0.826 + VHOLHVO UBALKWH 14.61 + VHOLHVO VCAPHVO 1.0 + VHOLHVO VCAPHOL 1.0 + VHOLHVO PROFIT -0.2112 + VCCUSRK MVOLSRK 1.0 + VCCUSRK MVOLNC4 -0.0184 + VCCUSRK MVOLC3S -0.0303 + VCCUSRK MVOLIC4 -0.0564 + VCCUSRK MVOLC3U -0.0655 + VCCUSRK MVOLC4U -0.0780 + VCCUSRK MVOLFCG -0.4750 + VCCUSRK MVOLLCO -0.3050 + VCCUSRK UBALSTM -.0654 + VCCUSRK UBALFUL -.2703 + VCCUSRK UBALH2O .632 + VCCUSRK UBALKWH .6807 + VCCUSRK VCAPCCU 1. + VCCUSRK PROFIT -.2112 + VCCUSRD MVOLSRD 1. + VCCUSRD MVOLNC4 -.0184 + VCCUSRD MVOLC3S -.0303 + VCCUSRD MVOLIC4 -.0564 + VCCUSRD MVOLC3U -.0655 + VCCUSRD MVOLC4U -.0780 + VCCUSRD MVOLFCG -.4750 + VCCUSRD MVOLLCO -.3050 + VCCUSRD UBALSTM -.0654 + VCCUSRD UBALFUL -.2703 + VCCUSRD UBALH2O 0.632 + VCCUSRD UBALKWH .6807 + VCCUSRD VCAPCCU 1. + VCCUSRD PROFIT -.2112 + VCCURCR MVOLRCR 1.0 + VCCURCR MVOLNC4 -.0185 + VCCURCR MVOLC3S -.0328 + VCCURCR MVOLIC4 -.0568 + VCCURCR MVOLC3U -.0658 + VCCURCR MVOLC4U -.0806 + VCCURCR MVOLFCG -.4934 + VCCURCR MVOLLCO -.2922 + VCCURCR MVOLSLR -.0096 + VCCURCR UBALSTM -.0654 + VCCURCR UBALFUL -.2703 + VCCURCR UBALH2O 0.632 + VCCURCR UBALKWH .6807 + VCCURCR VCAPCCU 1. + VCCURCR PROFIT -.2112 + VCCUHVO MVOLHVO 1.0 + VCCUHVO MVOLNC4 -.0185 + VCCUHVO MVOLC3S -.0328 + VCCUHVO MVOLIC4 -.0568 + VCCUHVO MVOLC3U -.0658 + VCCUHVO MVOLC4U -.0806 + VCCUHVO MVOLFCG -.4934 + VCCUHVO MVOLLCO -.2922 + VCCUHVO MVOLSLR -.0096 + VCCUHVO UBALSTM -.0654 + VCCUHVO UBALFUL -.2703 + VCCUHVO UBALH2O 0.632 + VCCUHVO UBALKWH .6807 + VCCUHVO VCAPHVO 1. + VCCUHVO VCAPCCU 1. + VCCUHVO PROFIT -.2112 + VALKLA3 MVOLIC4 .7600 + VALKLA3 MVOLC3U .5714 + VALKLA3 MVOLLA3 -1.0 + VALKLA3 UBALSTM .1869 + VALKLA3 UBALFUL .2796 + VALKLA3 UBALH2O 2.241 + VALKLA3 UBALKWH 2.766 + VALKLA3 VCAPALK 1.0 + VALKLA3 PROFIT -.512 + VALKLA4 MVOLIC4 .6571 + VALKLA4 MVOLC4U .5714 + VALKLA4 MVOLC3S -.0571 + VALKLA4 MVOLNC4 -.0114 + VALKLA4 MVOLLA4 -1.0 + VALKLA4 UBALSTM .1724 + VALKLA4 UBALFUL .2579 + VALKLA4 UBALH2O 2.067 + VALKLA4 UBALKWH 2.552 + VALKLA4 VCAPALK 1.0 + VALKLA4 PROFIT -.472 + VALKIC4 MVOLIC4 1.0 + VALKIC4 MVOLNC4 -1.0 + VALKC3U MVOLC3U 1.0 + VALKC3U MVOLC3S -1.0 + VALKC4U MVOLC4U 1.0 + VALKC4U MVOLNC4 -1.0 + UTILC3S MVOLC3S 1. + UTILC3S UBALFUL -3.814 + UTILNC4 MVOLNC4 1. + UTILNC4 UBALFUL -4.316 + UTILIC4 MVOLIC4 1. + UTILIC4 UBALFUL -4.153 + UTILC3U MVOLC3U 1. + UTILC3U UBALFUL -3.808 + UTILC4U MVOLC4U 1. + UTILC4U UBALFUL -4.44 + UTILHYL MSCFHYL 1. + UTILHYL UBALFUL -.305 + UTILSTM UBALSTM -1. + UTILSTM UBALFUL 1.42 + UTILSTM PROFIT -.16 + PURCPC4 MVOLIC4 -.5 + PURCPC4 MVOLNC4 -.5 + PURCPC4 PROFIT -12. + PURCH2O UBALH2O -1. + PURCH2O PROFIT -.0528 + PURCKWH UBALKWH -1. + PURCKWH PROFIT -.04 + PURCFUL UBALFUL -1. + PURCFUL PROFIT -1.6 + PURCFLR UBALFUL 1. + BLPGC3S MVOLC3S 1.0 + BLPGC3S EVOLLPG -1.0 + BLPGNC4 MVOLNC4 1.0 + BLPGNC4 EVOLLPG -1.0 + SELLLPG EVOLLPG 1.0 + SELLLPG PROFIT 11.0 + BUP4LSR MVOLLSR 1.0 + BUP4LSR EVOLJP4 -1.0 + BUP4LSR XRVXJP4 14.0 + BUP4LSR XRVNJP4 -14.0 + BUP4HSR MVOLHSR 1.0 + BUP4HSR EVOLJP4 -1.0 + BUP4HSR XRVXJP4 0.8 + BUP4HSR XRVNJP4 -0.8 + SELLJP4 EVOLJP4 1.0 + SELLJP4 XRVXJP4 -3.0 + SELLJP4 XRVNJP4 2.0 + SELLJP4 PROFIT 16.8 + BDSLSRK MVOLSRK 1.0 + BDSLSRK EVOLDSL -1.0 + BDSLSRD MVOLSRD 1.0 + BDSLSRD EVOLDSL -1.0 + SELLDSL EVOLDSL 1.0 + SELLDSL PROFIT 14.4 + BPRELSR MVOLLSR 1. + BPRELSR XLPRPRE -7.95 + BPRELSR XHPRPRE -8.70 + BPRELSR XTELPRE -3.00 + BPRELSR XRVPPRE 14.00 + BPRELSR X200PRE 1. + BPRELSR X230PRE -1. + BPRELSR EVOLPRE -1. + BPREHCD MVOLHCD 1.0 + BPREHCD XLPRPRE -8.84 + BPREHCD XHPRPRE -9.45 + BPREHCD XTELPRE -3.00 + BPREHCD XRVPPRE 12.00 + BPREHCD X200PRE 1. + BPREHCD X230PRE -1. + BPREHCD EVOLPRE -1. + BPREF95 MVOLF95 1.0 + BPREF95 XLPRPRE -9.43 + BPREF95 XHPRPRE -9.57 + BPREF95 XTELPRE -3. + BPREF95 XRVPPRE 3.5 + BPREF95 X200PRE .233 + BPREF95 X230PRE -.358 + BPREF95 EVOLPRE -1. + BPREF90 MVOLF90 1.0 + BPREF90 XLPRPRE -9.03 + BPREF90 XHPRPRE -9.32 + BPREF90 XTELPRE -3.0 + BPREF90 XRVPPRE 3.5 + BPREF90 X200PRE .205 + BPREF90 X230PRE -.333 + BPREF90 EVOLPRE -1. + BPREFCG MVOLFCG 1.0 + BPREFCG XLPRPRE -9.23 + BPREFCG XHPRPRE -9.22 + BPREFCG XTELPRE -3. + BPREFCG XRVPPRE 6. + BPREFCG X200PRE .381 + BPREFCG X230PRE -.509 + BPREFCG EVOLPRE -1. + BPRELA3 MVOLLA3 1.0 + BPRELA3 XLPRPRE -9.4 + BPRELA3 XHPRPRE -9.85 + BPRELA3 XTELPRE -3.0 + BPRELA3 XRVPPRE 2.5 + BPRELA3 X200PRE 0.39 + BPRELA3 X230PRE -0.77 + BPRELA3 EVOLPRE -1.0 + BPRELA4 MVOLLA4 1.0 + BPRELA4 XLPRPRE -9.74 + BPRELA4 XHPRPRE -10.1 + BPRELA4 XTELPRE -3.0 + BPRELA4 XRVPPRE 3.3 + BPRELA4 X200PRE 0.233 + BPRELA4 X230PRE -0.58 + BPRELA4 EVOLPRE -1.0 + BPRENC4 MVOLNC4 1.0 + BPRENC4 XLPRPRE -9.74 + BPRENC4 XHPRPRE -9.9 + BPRENC4 XTELPRE -3.0 + BPRENC4 XRVPPRE 66.0 + BPRENC4 X200PRE 1.0 + BPRENC4 X230PRE -1.0 + BPRENC4 EVOLPRE -1.0 + BPRETEL XLPRPRE -0.493 + BPRETEL XHPRPRE -0.165 + BPRETEL XTELPRE 1.0 + BPRETEL PROFIT -0.3696 + SELLPRE XLPRPRE 10.03 + SELLPRE XHPRPRE 10.03 + SELLPRE XRVPPRE -9.5 + SELLPRE X200PRE -0.5 + SELLPRE X230PRE 0.5 + SELLPRE XPSCPRE 0.64 + SELLPRE XRSCREG 0.35 + SELLPRE EVOLPRE 1.0 + SELLPRE PROFIT 21.44 + BINTLSR MVOLLSR 1.0 + BINTLSR XLPRINT -7.98 + BINTLSR XHPRINT -8.58 + BINTLSR XTELINT -3.0 + BINTLSR XRVPINT 14.0 + BINTLSR X200INT 1.0 + BINTLSR X230INT -1.0 + BINTLSR EVOLINT -1.0 + BINTHCD MVOLHCD 1. + BINTHCD XLPRINT -8.87 + BINTHCD XHPRINT -9.33 + BINTHCD XTELINT -3.0 + BINTHCD XRVPINT 12.0 + BINTHCD X200INT 1.0 + BINTHCD X230INT -1. + BINTHCD EVOLINT -1.0 + BINTF95 MVOLF95 1. + BINTF95 XLPRINT -9.46 + BINTF95 XHPRINT -9.45 + BINTF95 XTELINT -3.0 + BINTF95 XRVPINT 3.5 + BINTF95 X200INT .233 + BINTF95 X230INT -.358 + BINTF95 EVOLINT -1.0 + BINTF90 MVOLF90 1. + BINTF90 XLPRINT -9.06 + BINTF90 XHPRINT -9.20 + BINTF90 XTELINT -3.0 + BINTF90 XRVPINT 3.5 + BINTF90 X200INT .205 + BINTF90 X230INT -.333 + BINTF90 EVOLINT -1.0 + BINTFCG MVOLFCG 1. + BINTFCG XLPRINT -9.26 + BINTFCG XHPRINT -9.13 + BINTFCG XTELINT -3.0 + BINTFCG XRVPINT 6. + BINTFCG X200INT .318 + BINTFCG X230INT -.509 + BINTFCG EVOLINT -1.0 + BINTNC4 MVOLNC4 1. + BINTNC4 XLPRINT -9.77 + BINTNC4 XHPRINT -9.78 + BINTNC4 XTELINT -3.0 + BINTNC4 XRVPINT 66. + BINTNC4 X200INT 1.0 + BINTNC4 X230INT -1. + BINTNC4 EVOLINT -1.0 + BINTTEL XLPRINT -.435 + BINTTEL XHPRINT -.208 + BINTTEL XTELINT 1. + BINTTEL PROFIT -.3696 + SELLINT XLPRINT 9.65 + SELLINT XHPRINT 9.65 + SELLINT XRVPINT -9.5 + SELLINT X200INT -0.5 + SELLINT X230INT 0.5 + SELLINT XPSCPRE -.36 + SELLINT XRSCREG 0.35 + SELLINT EVOLINT 1.0 + SELLINT PROFIT 20.32 + BREGLSR MVOLLSR 1.0 + BREGLSR XLPRREG -7.99 + BREGLSR XHPRREG -8.59 + BREGLSR XTELREG -3.0 + BREGLSR XRVPREG 14.0 + BREGLSR X200REG 1.0 + BREGLSR X230REG -1.0 + BREGLSR EVOLREG -1.0 + BREGHCD MVOLHCD 1.0 + BREGHCD XLPRREG -8.88 + BREGHCD XHPRREG -9.34 + BREGHCD XTELREG -3.0 + BREGHCD XRVPREG 12.0 + BREGHCD X200REG 1.0 + BREGHCD X230REG -1.0 + BREGHCD EVOLREG -1.0 + BREGF95 MVOLF95 1.0 + BREGF95 XLPRREG -9.47 + BREGF95 XHPRREG -9.46 + BREGF95 XTELREG -3.0 + BREGF95 XRVPREG 3.5 + BREGF95 X200REG .233 + BREGF95 X230REG -0.358 + BREGF95 EVOLREG -1.0 + BREGF90 MVOLF90 1.0 + BREGF90 XLPRREG -9.07 + BREGF90 XHPRREG -9.21 + BREGF90 XTELREG -3.0 + BREGF90 XRVPREG 3.5 + BREGF90 X200REG .205 + BREGF90 X230REG -0.333 + BREGF90 EVOLREG -1.0 + BREGFCG MVOLFCG 1.0 + BREGFCG XLPRREG -9.27 + BREGFCG XHPRREG -9.14 + BREGFCG XTELREG -3.0 + BREGFCG XRVPREG 6.0 + BREGFCG X200REG 0.318 + BREGFCG X230REG -0.509 + BREGFCG EVOLREG -1.0 + BREGNC4 MVOLNC4 1.0 + BREGNC4 XLPRREG -9.78 + BREGNC4 XHPRREG -9.79 + BREGNC4 XTELREG -3.0 + BREGNC4 XRVPREG 66.0 + BREGNC4 X200REG 1.0 + BREGNC4 X230REG -1.0 + BREGNC4 EVOLREG -1.0 + BREGTEL XLPRREG -0.426 + BREGTEL XHPRREG -.204 + BREGTEL XTELREG 1.0 + BREGTEL PROFIT -0.3696 + SELLREG XLPRREG 9.05 + SELLREG XHPRREG 9.05 + SELLREG XRVPREG -9.5 + SELLREG X200REG -0.5 + SELLREG X230REG 0.5 + SELLREG XPSCPRE -0.36 + SELLREG XRSCREG -0.65 + SELLREG EVOLREG 1.0 + SELLREG PROFIT 18.04 + BRSDVBB MVOLVBB 1.0 + BRSDVBB EVOLRSD -1.0 + BRSDVBB XVISRSD 10.1 + BRSDVBC MVOLVBC 1.0 + BRSDVBC EVOLRSD -1.0 + BRSDVBC XVISRSD 12.63 + BRSDRCR MVOLRCR 1.0 + BRSDRCR EVOLRSD -1.0 + BRSDRCR XVISRSD 6.9 + BRSDHVO MVOLHVO 1.0 + BRSDHVO EVOLRSD -1.0 + BRSDHVO XVISRSD 8.05 + BRSDHVO VCAPHVO 1.0 + BRSDSLR MVOLSLR 1.0 + BRSDSLR EVOLRSD -1.0 + BRSDSLR XVISRSD 8.05 + BRSDLCO MVOLLCO 1.0 + BRSDLCO EVOLRSD -1.0 + BRSDLCO XVISRSD 4.4 + SELLRSD EVOLRSD 1.0 + SELLRSD XVISRSD -10.1 + SELLRSD PROFIT 8.00 +RHS + LIMITMAX MVOLBOL 26.316 + LIMITMAX MVOLCOL 21.052 + LIMITMAX VCAPSGP 23.25 + LIMITMAX VCAPHVO 5.25 + LIMITMAX VCAPRFG 13.455 + LIMITMAX VCAPHOL 3.87 + LIMITMAX VCAPCCU 7.26 + LIMITMAX VCAPALK 10. +ENDATA diff --git a/src/tests/util/lp/plan.mps b/src/tests/util/lp/plan.mps new file mode 100644 index 0000000000..b6bb094583 --- /dev/null +++ b/src/tests/util/lp/plan.mps @@ -0,0 +1,54 @@ +*000000001111111111222222222233333333334444444444555555555566 +*234567890123456789012345678901234567890123456789012345678901 +NAME PLAN +ROWS + N VALUE + E YIELD + L FE + L CU + L MN + L MG + G AL + L SI +COLUMNS + BIN1 VALUE .03000 YIELD 1.00000 + FE .15000 CU .03000 + MN .02000 MG .02000 + AL .70000 SI .02000 + BIN2 VALUE .08000 YIELD 1.00000 + FE .04000 CU .05000 + MN .04000 MG .03000 + AL .75000 SI .06000 + BIN3 VALUE .17000 YIELD 1.00000 + FE .02000 CU .08000 + MN .01000 AL .80000 + SI .08000 + BIN4 VALUE .12000 YIELD 1.00000 + FE .04000 CU .02000 + MN .02000 AL .75000 + SI .12000 + BIN5 VALUE .15000 YIELD 1.00000 + FE .02000 CU .06000 + MN .02000 MG .01000 + AL .80000 SI .02000 + ALUM VALUE .21000 YIELD 1.00000 + FE .01000 CU .01000 + AL .97000 SI .01000 + SILICON VALUE .38000 YIELD 1.00000 + FE .03000 SI .97000 +RHS + RHS1 YIELD 2000.00000 FE 60.00000 + CU 100.00000 MN 40.00000 + SI 300.00000 + MG 30.00000 AL 1500.00000 +RANGES + RNG1 SI 50.00000 +BOUNDS + UP BND1 BIN1 200.00000 + UP BIN2 2500.00000 + LO BIN3 400.00000 + UP BIN3 800.00000 + LO BIN4 100.00000 + UP BIN4 700.00000 + UP BIN5 1500.00000 +ENDATA diff --git a/src/tests/util/lp/run_netlib.sh b/src/tests/util/lp/run_netlib.sh new file mode 100755 index 0000000000..5008be8579 --- /dev/null +++ b/src/tests/util/lp/run_netlib.sh @@ -0,0 +1,57 @@ +#!/bin/bash +failures=0 +successes=0 +inconclusive=0 +total=0 +if [ $# -eq 1 ]; then + mpq_option=$1 + if [ $mpq_option != "--mpq" ]; then + echo "Usage: run_netlib.sh [--mpq]" + exit 1 + fi +else + mpq_option="none" + if [ $# -ne 0 ] ; then + echo "Too many arguments. Usage: run_netlib.sh [--mpq]" + exit 1 + fi +fi + +date + +function analyze_run_result() { + status=$? + if [ $status -ne 0 ]; then + if [ $status -ne 2 ]; then + let "failures += 1" + echo "Failure" + else + echo "Inconclusive" + let "inconclusive += 1" + fi + else + let "successes += 1" + echo "Success" + fi +} + +for f in test_files/netlib/*.SIF ; do + let "total += 2" + echo "processing "$f" for minimum" + ./compare_with_glpk.sh --min $f + analyze_run_result + + echo "processing "$f" for maximum" + ./compare_with_glpk.sh --max $f + analyze_run_result + + if [ $mpq_option == "--mpq" ]; then + let "total += 1" + echo "processing "$f" for rationals for minimum" + ./compare_with_glpk.sh --min --mpq $f + analyze_run_result + fi +done + +echo "Total runs="$total", failures="$failures", successes="$successes", inconclusive="$inconclusive +date diff --git a/src/tests/util/lp/samp1.mps b/src/tests/util/lp/samp1.mps new file mode 100644 index 0000000000..dd60d18437 --- /dev/null +++ b/src/tests/util/lp/samp1.mps @@ -0,0 +1,29 @@ +NAME SAMP1 +ROWS + N Z + G R1 + G R2 + G R3 +COLUMNS + X1 R1 2.0 R2 1.0 + X1 R3 5.0 Z 3.0 + MARK0001 'MARKER' 'INTORG' + X2 R1 -1.0 R2 -1.0 + X2 R3 3.0 Z 7.0 + X3 R1 1.0 R2 -6.0 + X3 Z -1.0 + MARK0002 'MARKER' 'INTEND' + X4 R1 -1.0 R2 4.0 + X4 R3 1.0 Z 1.0 +RHS + RHS1 R1 1.0 + RHS1 R2 8.0 + RHS1 R3 5.0 +BOUNDS + UP BND1 X1 4.0 + LO BND1 X2 2.0 + UP BND1 X2 5.0 + UP BND1 X3 1.0 + LO BND1 X4 3.0 + UP BND1 X4 8.0 +ENDATA diff --git a/src/tests/util/lp/samp2.mps b/src/tests/util/lp/samp2.mps new file mode 100644 index 0000000000..d2da1a31dd --- /dev/null +++ b/src/tests/util/lp/samp2.mps @@ -0,0 +1,27 @@ +NAME SAMP2 +ROWS + N Z + G R1 + G R2 + G R3 +COLUMNS + X1 R1 2.0 R2 1.0 + X1 R3 5.0 Z 3.0 + X2 R1 -1.0 R2 -1.0 + X2 R3 3.0 Z 7.0 + X3 R1 1.0 R2 -6.0 + X3 Z -1.0 + X4 R1 -1.0 R2 4.0 + X4 R3 1.0 Z 1.0 +RHS + RHS1 R1 1.0 + RHS1 R2 8.0 + RHS1 R3 5.0 +BOUNDS + UP BND1 X1 4.0 + LO BND1 X2 2.0 + UI BND1 X2 5.0 + BV BND1 X3 + LO BND1 X4 3.0 + UP BND1 X4 8.0 +ENDATA diff --git a/src/tests/util/lp/smt_reader.h b/src/tests/util/lp/smt_reader.h new file mode 100644 index 0000000000..87b06b204d --- /dev/null +++ b/src/tests/util/lp/smt_reader.h @@ -0,0 +1,382 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once + +// reads an MPS file reperesenting a Mixed Integer Program +#include +#include +#include +#include "util/lp/lp_primal_simplex.h" +#include "util/lp/lp_dual_simplex.h" +#include "util/lp/lar_solver.h" +#include +#include +#include +#include +#include +#include "tests/util/lp/mps_reader.h" +#include "util/lp/lar_constraints.h" +#include +#include +namespace lean { + using namespace std; + + template + T from_string(const std::string& str) { + std::istringstream ss(str); + T ret; + ss >> ret; + return ret; + } + + class smt_reader { + public: + struct lisp_elem { + string m_head; + vector m_elems; + void print() { + if (m_elems.size()) { + cout << '('; + cout << m_head << ' '; + for (auto & el : m_elems) + el.print(); + + cout << ')'; + } else { + cout << " " << m_head; + } + } + unsigned size() const { return m_elems.size(); } + bool is_simple() const { return size() == 0; } + }; + struct formula_constraint { + lconstraint_kind m_kind; + vector> m_coeffs; + mpq m_right_side = numeric_traits::zero(); + void add_pair(mpq c, string name) { + m_coeffs.push_back(make_pair(c, name)); + } + }; + + lisp_elem m_formula_lisp_elem; + + vector m_constraints; + string m_file_name; + ifstream m_file_stream; + string m_line; + bool m_is_OK = true; + unsigned m_line_number = 0; + + smt_reader(string file_name): + m_file_name(file_name), m_file_stream(file_name) { + } + + void set_error() { + cout << "setting error" << endl; + m_is_OK = false; + } + + bool is_ok() { + return m_is_OK; + } + + bool prefix(const char * pr) { + return m_line.find(pr) == 0; + } + + int first_separator() { + unsigned blank_pos = m_line.find(' '); + unsigned br_pos = m_line.find('('); + unsigned reverse_br_pos = m_line.find(')'); + return min(blank_pos, min(br_pos, reverse_br_pos)); + } + + void fill_lisp_elem(lisp_elem & lm) { + if (m_line[0] == '(') + fill_nested_elem(lm); + else + fill_simple_elem(lm); + } + + void fill_simple_elem(lisp_elem & lm) { + int separator = first_separator(); + lean_assert(-1 != separator && separator != 0); + lm.m_head = m_line.substr(0, separator); + m_line = m_line.substr(separator); + } + + void fill_nested_elem(lisp_elem & lm) { + lean_assert(m_line[0] == '('); + m_line = m_line.substr(1); + int separator = first_separator(); + lm.m_head = m_line.substr(0, separator); + m_line = m_line.substr(lm.m_head.size()); + eat_blanks(); + while (m_line.size()) { + if (m_line[0] == '(') { + lisp_elem el; + fill_nested_elem(el); + lm.m_elems.push_back(el); + } else { + if (m_line[0] == ')') { + m_line = m_line.substr(1); + break; + } + lisp_elem el; + fill_simple_elem(el); + lm.m_elems.push_back(el); + } + eat_blanks(); + } + } + + void eat_blanks() { + while (m_line.size()) { + if (m_line[0] == ' ') + m_line = m_line.substr(1); + else + break; + } + } + + void fill_formula_elem() { + fill_lisp_elem(m_formula_lisp_elem); + } + + void parse_line() { + if (m_line.find(":formula") == 0) { + int first_br = m_line.find('('); + if (first_br == -1) { + cout << "empty formula" << endl; + return; + } + m_line = m_line.substr(first_br); + fill_formula_elem(); + } + } + + void set_constraint_kind(formula_constraint & c, lisp_elem & el) { + if (el.m_head == "=") { + c.m_kind = EQ; + } else if (el.m_head == ">=") { + c.m_kind = GE; + } else if (el.m_head == "<=") { + c.m_kind = LE; + } else if (el.m_head == ">") { + c.m_kind = GT; + } else if (el.m_head == "<") { + c.m_kind = LT; + } else { + cout << "kind " << el.m_head << " is not supported " << endl; + set_error(); + } + } + + void adjust_rigth_side(formula_constraint & /* c*/, lisp_elem & /*el*/) { + // lean_assert(el.m_head == "0"); // do nothing for the time being + } + + void set_constraint_coeffs(formula_constraint & c, lisp_elem & el) { + lean_assert(el.m_elems.size() == 2); + set_constraint_coeffs_on_coeff_element(c, el.m_elems[0]); + adjust_rigth_side(c, el.m_elems[1]); + } + + + bool is_integer(string & s) { + if (s.size() == 0) return false; + return atoi(s.c_str()) != 0 || isdigit(s.c_str()[0]); + } + + void add_complex_sum_elem(formula_constraint & c, lisp_elem & el) { + if (el.m_head == "*") { + add_mult_elem(c, el.m_elems); + } else if (el.m_head == "~") { + lisp_elem & minel = el.m_elems[0]; + lean_assert(minel.is_simple()); + c.m_right_side += mpq(str_to_int(minel.m_head)); + } else { + cout << "unexpected input " << el.m_head << endl; + set_error(); + return; + } + } + + string get_name(lisp_elem & name) { + lean_assert(name.is_simple()); + lean_assert(!is_integer(name.m_head)); + return name.m_head; + } + + + void add_mult_elem(formula_constraint & c, vector & els) { + lean_assert(els.size() == 2); + mpq coeff = get_coeff(els[0]); + string col_name = get_name(els[1]); + c.add_pair(coeff, col_name); + } + + mpq get_coeff(lisp_elem & le) { + if (le.is_simple()) { + return mpq(str_to_int(le.m_head)); + } else { + lean_assert(le.m_head == "~"); + lean_assert(le.size() == 1); + lisp_elem & el = le.m_elems[0]; + lean_assert(el.is_simple()); + return -mpq(str_to_int(el.m_head)); + } + } + + int str_to_int(string & s) { + lean_assert(is_integer(s)); + return atoi(s.c_str()); + } + + void add_sum_elem(formula_constraint & c, lisp_elem & el) { + if (el.size()) { + add_complex_sum_elem(c, el); + } else { + lean_assert(is_integer(el.m_head)); + int v = atoi(el.m_head.c_str()); + mpq vr(v); + c.m_right_side -= vr; + } + } + + void add_sum(formula_constraint & c, vector & sum_els) { + for (auto & el : sum_els) + add_sum_elem(c, el); + } + + void set_constraint_coeffs_on_coeff_element(formula_constraint & c, lisp_elem & el) { + if (el.m_head == "*") { + add_mult_elem(c, el.m_elems); + } else if (el.m_head == "+") { + add_sum(c, el.m_elems); + } else { + lean_assert(false); // unexpected input + } + } + + void create_constraint(lisp_elem & el) { + formula_constraint c; + set_constraint_kind(c, el); + set_constraint_coeffs(c, el); + m_constraints.push_back(c); + } + + void fill_constraints() { + if (m_formula_lisp_elem.m_head != "and") { + cout << "unexpected top element " << m_formula_lisp_elem.m_head << endl; + set_error(); + return; + } + for (auto & el : m_formula_lisp_elem.m_elems) + create_constraint(el); + } + + void read() { + if (!m_file_stream.is_open()){ + cout << "cannot open file " << m_file_name << endl; + set_error(); + return; + } + while (m_is_OK && getline(m_file_stream, m_line)) { + parse_line(); + m_line_number++; + } + + m_file_stream.close(); + fill_constraints(); + } + + /* + void fill_lar_solver_on_row(row * row, lar_solver *solver) { + if (row->m_name != m_cost_row_name) { + lar_constraint c(get_lar_relation_from_row(row->m_type), row->m_right_side); + for (auto s : row->m_row_columns) { + var_index i = solver->add_var(s.first); + c.add_variable_to_constraint(i, s.second); + } + solver->add_constraint(&c); + } else { + // ignore the cost row + } + } + + + void fill_lar_solver_on_rows(lar_solver * solver) { + for (auto row_it : m_rows) { + fill_lar_solver_on_row(row_it.second, solver); + } + } + + void create_low_constraint_for_var(column* col, bound * b, lar_solver *solver) { + lar_constraint c(GE, b->m_low); + var_index i = solver->add_var(col->m_name); + c.add_variable_to_constraint(i, numeric_traits::one()); + solver->add_constraint(&c); + } + + void create_upper_constraint_for_var(column* col, bound * b, lar_solver *solver) { + lar_constraint c(LE, b->m_upper); + var_index i = solver->add_var(col->m_name); + c.add_variable_to_constraint(i, numeric_traits::one()); + solver->add_constraint(&c); + } + + void create_equality_contraint_for_var(column* col, bound * b, lar_solver *solver) { + lar_constraint c(EQ, b->m_fixed_value); + var_index i = solver->add_var(col->m_name); + c.add_variable_to_constraint(i, numeric_traits::one()); + solver->add_constraint(&c); + } + + void fill_lar_solver_on_columns(lar_solver * solver) { + for (auto s : m_columns) { + mps_reader::column * col = s.second; + solver->add_var(col->m_name); + auto b = col->m_bound; + if (b == nullptr) return; + + if (b->m_free) continue; + + if (b->m_low_is_set) { + create_low_constraint_for_var(col, b, solver); + } + if (b->m_upper_is_set) { + create_upper_constraint_for_var(col, b, solver); + } + if (b->m_value_is_fixed) { + create_equality_contraint_for_var(col, b, solver); + } + } + } +*/ + void add_constraint_to_solver(lar_solver * solver, formula_constraint & fc) { + buffer> ls; + for (auto & it : fc.m_coeffs) { + ls.push_back(make_pair(it.first, solver->add_var(it.second))); + } + solver->add_constraint(ls, fc.m_kind, fc.m_right_side); + } + + void fill_lar_solver(lar_solver * solver) { + for (formula_constraint & fc : m_constraints) + add_constraint_to_solver(solver, fc); + } + + + lar_solver * create_lar_solver() { + lar_solver * ls = new lar_solver(); + fill_lar_solver(ls); + return ls; + } + }; +} diff --git a/src/tests/util/lp/test_file_reader.h b/src/tests/util/lp/test_file_reader.h new file mode 100644 index 0000000000..8b5513a395 --- /dev/null +++ b/src/tests/util/lp/test_file_reader.h @@ -0,0 +1,74 @@ +/* +Copyright (c) 2013 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Lev Nachmanson +*/ +#pragma once + +// reads a text file +#include +#include +#include +#include +#include +#include +#include "util/lp/lp_solver.h" + +namespace lean { +using namespace std; + +template +struct test_result { + lp_status m_status; + T m_cost; + unordered_map column_values; +}; + +template +class test_file_reader { + struct raw_blob { + vector m_unparsed_strings; + vector m_blobs; + }; + + struct test_file_blob { + string m_name; + string m_content; + unordered_map m_table; + unordered_map m_blobs; + + test_result * get_test_result() { + test_result * tr = new test_result(); + throw "not impl"; + return tr; + } + }; + ifstream m_file_stream; +public: + // constructor + test_file_reader(string file_name) : m_file_stream(file_name) { + if (!m_file_stream.is_open()) { + cout << "cannot open file " << "\'" << file_name << "\'" << endl; + } + } + + raw_blob scan_to_row_blob() { + } + + test_file_blob scan_row_blob_to_test_file_blob(raw_blob rblob) { + } + + test_result * get_test_result() { + if (!m_file_stream.is_open()) { + return nullptr; + } + + raw_blob rblob = scan_to_row_blob(); + + test_file_blob tblob = scan_row_blob_to_test_file_blob(rblob); + + return tblob.get_test_result(); + } +}; +} diff --git a/src/tests/util/lp/test_files/acc-tight5.mps b/src/tests/util/lp/test_files/acc-tight5.mps new file mode 100644 index 0000000000..fcd1653bb6 --- /dev/null +++ b/src/tests/util/lp/test_files/acc-tight5.mps @@ -0,0 +1,23587 @@ +NAME acc-tight5 +ROWS + N r_0 + E r_1 + E r_2 + E r_3 + E r_4 + E r_5 + E r_6 + E r_7 + E r_8 + E r_9 + E r_10 + E r_11 + E r_12 + E r_13 + E r_14 + E r_15 + E r_16 + E r_17 + E r_18 + E r_19 + E r_20 + E r_21 + E r_22 + E r_23 + E r_24 + E r_25 + E r_26 + E r_27 + E r_28 + E r_29 + E r_30 + E r_31 + E r_32 + E r_33 + E r_34 + E r_35 + E r_36 + E r_37 + E r_38 + E r_39 + E r_40 + E r_41 + E r_42 + E r_43 + E r_44 + E r_45 + E r_46 + E r_47 + E r_48 + E r_49 + E r_50 + E r_51 + E r_52 + E r_53 + E r_54 + E r_55 + E r_56 + E r_57 + E r_58 + E r_59 + E r_60 + E r_61 + E r_62 + E r_63 + E r_64 + E r_65 + E r_66 + E r_67 + E r_68 + E r_69 + E r_70 + E r_71 + E r_72 + E r_73 + E r_74 + E r_75 + E r_76 + E r_77 + E r_78 + E r_79 + E r_80 + E r_81 + E r_82 + E r_83 + E r_84 + E r_85 + E r_86 + E r_87 + E r_88 + E r_89 + E r_90 + E r_91 + E r_92 + E r_93 + E r_94 + E r_95 + E r_96 + E r_97 + E r_98 + E r_99 + E r_100 + E r_101 + E r_102 + E r_103 + E r_104 + E r_105 + E r_106 + E r_107 + E r_108 + E r_109 + E r_110 + E r_111 + E r_112 + E r_113 + E r_114 + E r_115 + E r_116 + E r_117 + E r_118 + E r_119 + E r_120 + E r_121 + E r_122 + E r_123 + E r_124 + E r_125 + E r_126 + E r_127 + E r_128 + E r_129 + E r_130 + E r_131 + E r_132 + E r_133 + E r_134 + E r_135 + E r_136 + E r_137 + E r_138 + E r_139 + E r_140 + E r_141 + E r_142 + E r_143 + E r_144 + E r_145 + E r_146 + E r_147 + E r_148 + E r_149 + L r_150 + L r_151 + L r_152 + L r_153 + L r_154 + L r_155 + L r_156 + L r_157 + L r_158 + L r_159 + L r_160 + L r_161 + L r_162 + L r_163 + L r_164 + L r_165 + L r_166 + L r_167 + L r_168 + L r_169 + L r_170 + L r_171 + L r_172 + L r_173 + L r_174 + L r_175 + L r_176 + L r_177 + L r_178 + L r_179 + L r_180 + L r_181 + L r_182 + L r_183 + L r_184 + L r_185 + L r_186 + L r_187 + L r_188 + L r_189 + L r_190 + L r_191 + L r_192 + L r_193 + L r_194 + L r_195 + L r_196 + L r_197 + L r_198 + L r_199 + L r_200 + L r_201 + L r_202 + L r_203 + L r_204 + L r_205 + L r_206 + L r_207 + L r_208 + L r_209 + L r_210 + L r_211 + L r_212 + L r_213 + L r_214 + L r_215 + L r_216 + L r_217 + L r_218 + L r_219 + L r_220 + L r_221 + L r_222 + L r_223 + L r_224 + L r_225 + L r_226 + L r_227 + L r_228 + L r_229 + L r_230 + L r_231 + L r_232 + L r_233 + L r_234 + L r_235 + L r_236 + L r_237 + L r_238 + L r_239 + L r_240 + L r_241 + L r_242 + L r_243 + L r_244 + L r_245 + L r_246 + L r_247 + L r_248 + L r_249 + L r_250 + L r_251 + L r_252 + L r_253 + L r_254 + L r_255 + L r_256 + L r_257 + L r_258 + L r_259 + L r_260 + L r_261 + L r_262 + L r_263 + L r_264 + L r_265 + L r_266 + L r_267 + L r_268 + L r_269 + L r_270 + L r_271 + L r_272 + L r_273 + L r_274 + L r_275 + L r_276 + L r_277 + L r_278 + L r_279 + L r_280 + L r_281 + L r_282 + L r_283 + L r_284 + L r_285 + L r_286 + L r_287 + L r_288 + L r_289 + L r_290 + L r_291 + L r_292 + L r_293 + L r_294 + L r_295 + L r_296 + L r_297 + L r_298 + L r_299 + L r_300 + L r_301 + G r_302 + G r_303 + G r_304 + G r_305 + G r_306 + G r_307 + G r_308 + G r_309 + G r_310 + G r_311 + G r_312 + G r_313 + G r_314 + G r_315 + G r_316 + G r_317 + G r_318 + G r_319 + G r_320 + G r_321 + G r_322 + G r_323 + G r_324 + G r_325 + G r_326 + G r_327 + G r_328 + G r_329 + G r_330 + G r_331 + G r_332 + G r_333 + G r_334 + G r_335 + G r_336 + G r_337 + G r_338 + G r_339 + G r_340 + G r_341 + G r_342 + G r_343 + G r_344 + G r_345 + G r_346 + G r_347 + G r_348 + G r_349 + G r_350 + G r_351 + G r_352 + G r_353 + G r_354 + G r_355 + G r_356 + G r_357 + G r_358 + G r_359 + G r_360 + G r_361 + G r_362 + G r_363 + G r_364 + G r_365 + G r_366 + G r_367 + G r_368 + G r_369 + G r_370 + G r_371 + G r_372 + G r_373 + G r_374 + G r_375 + G r_376 + G r_377 + G r_378 + G r_379 + G r_380 + G r_381 + G r_382 + G r_383 + G r_384 + G r_385 + G r_386 + G r_387 + G r_388 + G r_389 + G r_390 + G r_391 + G r_392 + G r_393 + G r_394 + G r_395 + G r_396 + G r_397 + G r_398 + G r_399 + G r_400 + G r_401 + G r_402 + G r_403 + G r_404 + G r_405 + G r_406 + G r_407 + G r_408 + G r_409 + G r_410 + G r_411 + G r_412 + G r_413 + G r_414 + G r_415 + G r_416 + G r_417 + G r_418 + G r_419 + G r_420 + G r_421 + G r_422 + G r_423 + G r_424 + G r_425 + G r_426 + G r_427 + G r_428 + G r_429 + G r_430 + G r_431 + G r_432 + G r_433 + G r_434 + G r_435 + G r_436 + G r_437 + G r_438 + G r_439 + G r_440 + G r_441 + G r_442 + G r_443 + G r_444 + G r_445 + G r_446 + G r_447 + G r_448 + G r_449 + G r_450 + G r_451 + G r_452 + G r_453 + G r_454 + G r_455 + G r_456 + G r_457 + G r_458 + G r_459 + G r_460 + G r_461 + G r_462 + G r_463 + G r_464 + G r_465 + G r_466 + G r_467 + G r_468 + G r_469 + G r_470 + G r_471 + G r_472 + G r_473 + G r_474 + G r_475 + G r_476 + G r_477 + G r_478 + G r_479 + G r_480 + G r_481 + G r_482 + G r_483 + G r_484 + G r_485 + G r_486 + G r_487 + G r_488 + G r_489 + G r_490 + G r_491 + G r_492 + G r_493 + G r_494 + G r_495 + G r_496 + G r_497 + G r_498 + G r_499 + G r_500 + G r_501 + G r_502 + G r_503 + G r_504 + G r_505 + G r_506 + G r_507 + G r_508 + G r_509 + G r_510 + G r_511 + G r_512 + G r_513 + G r_514 + G r_515 + G r_516 + G r_517 + G r_518 + G r_519 + G r_520 + G r_521 + G r_522 + G r_523 + G r_524 + G r_525 + G r_526 + G r_527 + G r_528 + G r_529 + G r_530 + G r_531 + G r_532 + G r_533 + G r_534 + G r_535 + G r_536 + G r_537 + G r_538 + G r_539 + G r_540 + G r_541 + G r_542 + G r_543 + G r_544 + G r_545 + G r_546 + G r_547 + G r_548 + G r_549 + G r_550 + G r_551 + G r_552 + G r_553 + G r_554 + G r_555 + G r_556 + G r_557 + G r_558 + G r_559 + G r_560 + G r_561 + G r_562 + G r_563 + G r_564 + G r_565 + G r_566 + G r_567 + G r_568 + G r_569 + G r_570 + G r_571 + G r_572 + G r_573 + G r_574 + G r_575 + G r_576 + G r_577 + G r_578 + G r_579 + G r_580 + G r_581 + G r_582 + G r_583 + G r_584 + G r_585 + G r_586 + G r_587 + G r_588 + G r_589 + G r_590 + G r_591 + G r_592 + G r_593 + G r_594 + G r_595 + G r_596 + G r_597 + G r_598 + G r_599 + G r_600 + G r_601 + G r_602 + G r_603 + G r_604 + G r_605 + G r_606 + G r_607 + G r_608 + G r_609 + G r_610 + G r_611 + G r_612 + G r_613 + G r_614 + G r_615 + G r_616 + G r_617 + G r_618 + G r_619 + G r_620 + G r_621 + G r_622 + G r_623 + G r_624 + G r_625 + G r_626 + G r_627 + G r_628 + G r_629 + G r_630 + G r_631 + G r_632 + G r_633 + G r_634 + G r_635 + G r_636 + G r_637 + G r_638 + G r_639 + G r_640 + G r_641 + G r_642 + G r_643 + G r_644 + G r_645 + G r_646 + G r_647 + G r_648 + G r_649 + G r_650 + G r_651 + G r_652 + G r_653 + G r_654 + G r_655 + G r_656 + G r_657 + G r_658 + G r_659 + G r_660 + G r_661 + G r_662 + G r_663 + G r_664 + G r_665 + G r_666 + G r_667 + G r_668 + G r_669 + G r_670 + G r_671 + G r_672 + G r_673 + G r_674 + G r_675 + G r_676 + G r_677 + G r_678 + G r_679 + G r_680 + G r_681 + G r_682 + G r_683 + G r_684 + G r_685 + G r_686 + G r_687 + G r_688 + G r_689 + G r_690 + G r_691 + G r_692 + G r_693 + G r_694 + G r_695 + G r_696 + G r_697 + G r_698 + G r_699 + G r_700 + G r_701 + G r_702 + G r_703 + G r_704 + G r_705 + G r_706 + G r_707 + G r_708 + G r_709 + G r_710 + G r_711 + G r_712 + G r_713 + G r_714 + G r_715 + G r_716 + G r_717 + G r_718 + G r_719 + G r_720 + G r_721 + G r_722 + G r_723 + G r_724 + G r_725 + G r_726 + G r_727 + G r_728 + G r_729 + G r_730 + G r_731 + G r_732 + G r_733 + G r_734 + G r_735 + G r_736 + G r_737 + G r_738 + G r_739 + G r_740 + G r_741 + G r_742 + G r_743 + G r_744 + G r_745 + G r_746 + G r_747 + G r_748 + G r_749 + G r_750 + G r_751 + G r_752 + G r_753 + G r_754 + G r_755 + G r_756 + G r_757 + G r_758 + G r_759 + G r_760 + G r_761 + G r_762 + G r_763 + G r_764 + G r_765 + G r_766 + G r_767 + G r_768 + G r_769 + G r_770 + G r_771 + G r_772 + G r_773 + G r_774 + G r_775 + G r_776 + G r_777 + G r_778 + G r_779 + G r_780 + G r_781 + G r_782 + G r_783 + G r_784 + G r_785 + G r_786 + G r_787 + G r_788 + G r_789 + G r_790 + G r_791 + G r_792 + G r_793 + G r_794 + G r_795 + G r_796 + G r_797 + G r_798 + G r_799 + G r_800 + G r_801 + G r_802 + G r_803 + G r_804 + G r_805 + G r_806 + G r_807 + G r_808 + G r_809 + G r_810 + G r_811 + G r_812 + G r_813 + G r_814 + G r_815 + G r_816 + G r_817 + G r_818 + G r_819 + G r_820 + G r_821 + G r_822 + G r_823 + G r_824 + G r_825 + G r_826 + G r_827 + G r_828 + G r_829 + G r_830 + G r_831 + G r_832 + G r_833 + G r_834 + G r_835 + G r_836 + G r_837 + G r_838 + G r_839 + G r_840 + G r_841 + G r_842 + G r_843 + G r_844 + G r_845 + G r_846 + G r_847 + G r_848 + G r_849 + G r_850 + G r_851 + G r_852 + G r_853 + G r_854 + G r_855 + G r_856 + G r_857 + G r_858 + G r_859 + G r_860 + G r_861 + G r_862 + G r_863 + G r_864 + G r_865 + G r_866 + G r_867 + G r_868 + G r_869 + G r_870 + G r_871 + G r_872 + G r_873 + G r_874 + G r_875 + G r_876 + G r_877 + G r_878 + G r_879 + G r_880 + G r_881 + G r_882 + G r_883 + G r_884 + G r_885 + G r_886 + G r_887 + G r_888 + G r_889 + G r_890 + G r_891 + G r_892 + G r_893 + G r_894 + G r_895 + G r_896 + G r_897 + G r_898 + G r_899 + G r_900 + G r_901 + G r_902 + G r_903 + G r_904 + G r_905 + G r_906 + G r_907 + G r_908 + G r_909 + G r_910 + G r_911 + G r_912 + G r_913 + G r_914 + G r_915 + G r_916 + G r_917 + G r_918 + G r_919 + G r_920 + G r_921 + G r_922 + G r_923 + G r_924 + G r_925 + G r_926 + G r_927 + G r_928 + G r_929 + G r_930 + G r_931 + G r_932 + G r_933 + G r_934 + G r_935 + G r_936 + G r_937 + G r_938 + G r_939 + G r_940 + G r_941 + G r_942 + G r_943 + G r_944 + G r_945 + G r_946 + G r_947 + G r_948 + G r_949 + G r_950 + G r_951 + G r_952 + G r_953 + G r_954 + G r_955 + G r_956 + G r_957 + G r_958 + G r_959 + G r_960 + G r_961 + G r_962 + G r_963 + G r_964 + G r_965 + G r_966 + G r_967 + G r_968 + G r_969 + G r_970 + G r_971 + G r_972 + G r_973 + G r_974 + G r_975 + G r_976 + G r_977 + G r_978 + G r_979 + G r_980 + G r_981 + G r_982 + G r_983 + G r_984 + G r_985 + G r_986 + G r_987 + G r_988 + G r_989 + G r_990 + G r_991 + G r_992 + G r_993 + G r_994 + G r_995 + G r_996 + G r_997 + G r_998 + G r_999 + G r_1000 + G r_1001 + G r_1002 + G r_1003 + G r_1004 + G r_1005 + G r_1006 + G r_1007 + G r_1008 + G r_1009 + G r_1010 + G r_1011 + G r_1012 + G r_1013 + G r_1014 + G r_1015 + G r_1016 + G r_1017 + G r_1018 + G r_1019 + G r_1020 + G r_1021 + G r_1022 + G r_1023 + G r_1024 + G r_1025 + G r_1026 + G r_1027 + G r_1028 + G r_1029 + G r_1030 + G r_1031 + G r_1032 + G r_1033 + G r_1034 + G r_1035 + G r_1036 + G r_1037 + G r_1038 + G r_1039 + G r_1040 + G r_1041 + G r_1042 + G r_1043 + G r_1044 + G r_1045 + G r_1046 + G r_1047 + G r_1048 + G r_1049 + G r_1050 + G r_1051 + G r_1052 + G r_1053 + G r_1054 + G r_1055 + G r_1056 + G r_1057 + G r_1058 + G r_1059 + G r_1060 + G r_1061 + G r_1062 + G r_1063 + G r_1064 + G r_1065 + G r_1066 + G r_1067 + G r_1068 + G r_1069 + G r_1070 + G r_1071 + G r_1072 + G r_1073 + G r_1074 + G r_1075 + G r_1076 + G r_1077 + G r_1078 + G r_1079 + G r_1080 + G r_1081 + G r_1082 + G r_1083 + G r_1084 + G r_1085 + G r_1086 + G r_1087 + G r_1088 + G r_1089 + G r_1090 + G r_1091 + G r_1092 + G r_1093 + G r_1094 + G r_1095 + G r_1096 + G r_1097 + G r_1098 + G r_1099 + G r_1100 + G r_1101 + G r_1102 + G r_1103 + G r_1104 + G r_1105 + G r_1106 + G r_1107 + G r_1108 + G r_1109 + G r_1110 + G r_1111 + G r_1112 + G r_1113 + G r_1114 + G r_1115 + G r_1116 + G r_1117 + G r_1118 + G r_1119 + G r_1120 + G r_1121 + G r_1122 + G r_1123 + G r_1124 + G r_1125 + G r_1126 + G r_1127 + G r_1128 + G r_1129 + G r_1130 + G r_1131 + G r_1132 + G r_1133 + G r_1134 + G r_1135 + G r_1136 + G r_1137 + G r_1138 + G r_1139 + G r_1140 + G r_1141 + G r_1142 + G r_1143 + G r_1144 + G r_1145 + G r_1146 + G r_1147 + G r_1148 + G r_1149 + G r_1150 + G r_1151 + G r_1152 + G r_1153 + G r_1154 + G r_1155 + G r_1156 + G r_1157 + G r_1158 + G r_1159 + G r_1160 + G r_1161 + G r_1162 + G r_1163 + G r_1164 + G r_1165 + G r_1166 + G r_1167 + G r_1168 + G r_1169 + G r_1170 + G r_1171 + G r_1172 + G r_1173 + G r_1174 + G r_1175 + G r_1176 + G r_1177 + G r_1178 + G r_1179 + G r_1180 + G r_1181 + G r_1182 + G r_1183 + G r_1184 + G r_1185 + G r_1186 + G r_1187 + G r_1188 + G r_1189 + G r_1190 + G r_1191 + G r_1192 + G r_1193 + G r_1194 + G r_1195 + G r_1196 + G r_1197 + G r_1198 + G r_1199 + G r_1200 + G r_1201 + G r_1202 + G r_1203 + G r_1204 + G r_1205 + G r_1206 + G r_1207 + G r_1208 + G r_1209 + G r_1210 + G r_1211 + G r_1212 + G r_1213 + G r_1214 + G r_1215 + G r_1216 + G r_1217 + G r_1218 + G r_1219 + G r_1220 + G r_1221 + G r_1222 + G r_1223 + G r_1224 + G r_1225 + G r_1226 + G r_1227 + G r_1228 + G r_1229 + G r_1230 + G r_1231 + G r_1232 + G r_1233 + G r_1234 + G r_1235 + G r_1236 + G r_1237 + G r_1238 + G r_1239 + G r_1240 + G r_1241 + G r_1242 + G r_1243 + G r_1244 + G r_1245 + G r_1246 + G r_1247 + G r_1248 + G r_1249 + G r_1250 + G r_1251 + G r_1252 + G r_1253 + G r_1254 + G r_1255 + G r_1256 + G r_1257 + G r_1258 + G r_1259 + G r_1260 + G r_1261 + G r_1262 + G r_1263 + G r_1264 + G r_1265 + G r_1266 + G r_1267 + G r_1268 + G r_1269 + G r_1270 + G r_1271 + G r_1272 + G r_1273 + G r_1274 + G r_1275 + G r_1276 + G r_1277 + G r_1278 + G r_1279 + G r_1280 + G r_1281 + G r_1282 + G r_1283 + G r_1284 + G r_1285 + G r_1286 + G r_1287 + G r_1288 + G r_1289 + G r_1290 + G r_1291 + G r_1292 + G r_1293 + G r_1294 + G r_1295 + G r_1296 + G r_1297 + G r_1298 + G r_1299 + G r_1300 + G r_1301 + G r_1302 + G r_1303 + G r_1304 + G r_1305 + G r_1306 + G r_1307 + G r_1308 + G r_1309 + G r_1310 + G r_1311 + G r_1312 + G r_1313 + G r_1314 + G r_1315 + G r_1316 + G r_1317 + G r_1318 + G r_1319 + G r_1320 + G r_1321 + G r_1322 + G r_1323 + G r_1324 + G r_1325 + G r_1326 + G r_1327 + G r_1328 + G r_1329 + G r_1330 + G r_1331 + G r_1332 + G r_1333 + G r_1334 + G r_1335 + G r_1336 + G r_1337 + G r_1338 + G r_1339 + G r_1340 + G r_1341 + G r_1342 + G r_1343 + G r_1344 + G r_1345 + G r_1346 + G r_1347 + G r_1348 + G r_1349 + G r_1350 + G r_1351 + G r_1352 + G r_1353 + G r_1354 + G r_1355 + G r_1356 + G r_1357 + G r_1358 + G r_1359 + G r_1360 + G r_1361 + G r_1362 + G r_1363 + G r_1364 + G r_1365 + G r_1366 + G r_1367 + E r_1368 + E r_1369 + E r_1370 + E r_1371 + E r_1372 + E r_1373 + E r_1374 + E r_1375 + E r_1376 + E r_1377 + E r_1378 + E r_1379 + E r_1380 + E r_1381 + E r_1382 + E r_1383 + E r_1384 + E r_1385 + E r_1386 + E r_1387 + E r_1388 + E r_1389 + E r_1390 + E r_1391 + E r_1392 + E r_1393 + E r_1394 + E r_1395 + E r_1396 + E r_1397 + E r_1398 + E r_1399 + E r_1400 + E r_1401 + E r_1402 + E r_1403 + E r_1404 + E r_1405 + E r_1406 + E r_1407 + E r_1408 + E r_1409 + E r_1410 + E r_1411 + E r_1412 + E r_1413 + E r_1414 + E r_1415 + E r_1416 + E r_1417 + E r_1418 + E r_1419 + E r_1420 + E r_1421 + E r_1422 + E r_1423 + E r_1424 + E r_1425 + E r_1426 + E r_1427 + E r_1428 + E r_1429 + E r_1430 + E r_1431 + E r_1432 + E r_1433 + E r_1434 + E r_1435 + E r_1436 + E r_1437 + G r_1438 + G r_1439 + G r_1440 + G r_1441 + G r_1442 + G r_1443 + G r_1444 + G r_1445 + G r_1446 + G r_1447 + G r_1448 + G r_1449 + G r_1450 + G r_1451 + G r_1452 + G r_1453 + G r_1454 + G r_1455 + G r_1456 + G r_1457 + G r_1458 + G r_1459 + G r_1460 + G r_1461 + G r_1462 + G r_1463 + G r_1464 + G r_1465 + G r_1466 + G r_1467 + G r_1468 + G r_1469 + G r_1470 + G r_1471 + G r_1472 + G r_1473 + G r_1474 + G r_1475 + G r_1476 + G r_1477 + G r_1478 + G r_1479 + G r_1480 + G r_1481 + G r_1482 + G r_1483 + G r_1484 + G r_1485 + G r_1486 + G r_1487 + G r_1488 + G r_1489 + G r_1490 + G r_1491 + G r_1492 + G r_1493 + G r_1494 + G r_1495 + G r_1496 + G r_1497 + G r_1498 + G r_1499 + G r_1500 + G r_1501 + G r_1502 + G r_1503 + G r_1504 + G r_1505 + G r_1506 + G r_1507 + G r_1508 + G r_1509 + G r_1510 + G r_1511 + G r_1512 + G r_1513 + G r_1514 + G r_1515 + G r_1516 + G r_1517 + G r_1518 + G r_1519 + G r_1520 + G r_1521 + G r_1522 + G r_1523 + G r_1524 + G r_1525 + G r_1526 + G r_1527 + G r_1528 + G r_1529 + G r_1530 + G r_1531 + G r_1532 + G r_1533 + G r_1534 + G r_1535 + G r_1536 + G r_1537 + G r_1538 + G r_1539 + G r_1540 + G r_1541 + G r_1542 + G r_1543 + G r_1544 + G r_1545 + G r_1546 + G r_1547 + G r_1548 + G r_1549 + G r_1550 + G r_1551 + G r_1552 + G r_1553 + G r_1554 + G r_1555 + G r_1556 + G r_1557 + G r_1558 + G r_1559 + G r_1560 + G r_1561 + G r_1562 + G r_1563 + G r_1564 + G r_1565 + G r_1566 + G r_1567 + G r_1568 + G r_1569 + G r_1570 + G r_1571 + G r_1572 + G r_1573 + G r_1574 + G r_1575 + G r_1576 + G r_1577 + G r_1578 + G r_1579 + G r_1580 + G r_1581 + G r_1582 + G r_1583 + G r_1584 + G r_1585 + G r_1586 + G r_1587 + G r_1588 + G r_1589 + G r_1590 + G r_1591 + G r_1592 + G r_1593 + G r_1594 + G r_1595 + G r_1596 + G r_1597 + G r_1598 + G r_1599 + G r_1600 + G r_1601 + G r_1602 + G r_1603 + G r_1604 + G r_1605 + G r_1606 + G r_1607 + G r_1608 + G r_1609 + G r_1610 + G r_1611 + G r_1612 + G r_1613 + G r_1614 + G r_1615 + G r_1616 + G r_1617 + G r_1618 + G r_1619 + G r_1620 + G r_1621 + G r_1622 + G r_1623 + G r_1624 + G r_1625 + G r_1626 + G r_1627 + G r_1628 + G r_1629 + G r_1630 + G r_1631 + G r_1632 + G r_1633 + G r_1634 + G r_1635 + G r_1636 + G r_1637 + G r_1638 + G r_1639 + G r_1640 + G r_1641 + G r_1642 + G r_1643 + G r_1644 + G r_1645 + G r_1646 + G r_1647 + G r_1648 + G r_1649 + G r_1650 + G r_1651 + G r_1652 + G r_1653 + G r_1654 + G r_1655 + G r_1656 + G r_1657 + G r_1658 + G r_1659 + G r_1660 + G r_1661 + G r_1662 + G r_1663 + G r_1664 + G r_1665 + G r_1666 + G r_1667 + G r_1668 + G r_1669 + G r_1670 + G r_1671 + G r_1672 + G r_1673 + G r_1674 + G r_1675 + G r_1676 + G r_1677 + G r_1678 + G r_1679 + G r_1680 + G r_1681 + G r_1682 + G r_1683 + G r_1684 + G r_1685 + G r_1686 + G r_1687 + G r_1688 + G r_1689 + G r_1690 + G r_1691 + G r_1692 + G r_1693 + G r_1694 + G r_1695 + G r_1696 + G r_1697 + G r_1698 + G r_1699 + G r_1700 + G r_1701 + G r_1702 + G r_1703 + G r_1704 + G r_1705 + G r_1706 + G r_1707 + G r_1708 + G r_1709 + G r_1710 + G r_1711 + G r_1712 + G r_1713 + G r_1714 + G r_1715 + G r_1716 + G r_1717 + G r_1718 + G r_1719 + G r_1720 + G r_1721 + G r_1722 + G r_1723 + G r_1724 + G r_1725 + G r_1726 + G r_1727 + G r_1728 + G r_1729 + G r_1730 + G r_1731 + G r_1732 + G r_1733 + G r_1734 + G r_1735 + G r_1736 + G r_1737 + G r_1738 + G r_1739 + G r_1740 + G r_1741 + G r_1742 + G r_1743 + G r_1744 + G r_1745 + G r_1746 + G r_1747 + G r_1748 + G r_1749 + G r_1750 + G r_1751 + G r_1752 + G r_1753 + G r_1754 + G r_1755 + G r_1756 + G r_1757 + G r_1758 + G r_1759 + G r_1760 + G r_1761 + G r_1762 + G r_1763 + G r_1764 + G r_1765 + G r_1766 + G r_1767 + G r_1768 + G r_1769 + G r_1770 + G r_1771 + G r_1772 + G r_1773 + G r_1774 + G r_1775 + G r_1776 + G r_1777 + G r_1778 + G r_1779 + G r_1780 + G r_1781 + G r_1782 + G r_1783 + G r_1784 + G r_1785 + G r_1786 + G r_1787 + G r_1788 + G r_1789 + G r_1790 + G r_1791 + G r_1792 + G r_1793 + G r_1794 + G r_1795 + G r_1796 + G r_1797 + G r_1798 + G r_1799 + G r_1800 + G r_1801 + G r_1802 + G r_1803 + G r_1804 + G r_1805 + G r_1806 + G r_1807 + G r_1808 + G r_1809 + G r_1810 + G r_1811 + G r_1812 + G r_1813 + G r_1814 + G r_1815 + G r_1816 + G r_1817 + G r_1818 + G r_1819 + G r_1820 + G r_1821 + G r_1822 + G r_1823 + G r_1824 + G r_1825 + G r_1826 + G r_1827 + G r_1828 + G r_1829 + G r_1830 + G r_1831 + G r_1832 + G r_1833 + G r_1834 + G r_1835 + G r_1836 + G r_1837 + G r_1838 + G r_1839 + G r_1840 + G r_1841 + G r_1842 + G r_1843 + G r_1844 + G r_1845 + G r_1846 + G r_1847 + G r_1848 + G r_1849 + G r_1850 + G r_1851 + G r_1852 + G r_1853 + G r_1854 + G r_1855 + G r_1856 + G r_1857 + G r_1858 + G r_1859 + G r_1860 + G r_1861 + G r_1862 + G r_1863 + G r_1864 + G r_1865 + G r_1866 + G r_1867 + G r_1868 + G r_1869 + G r_1870 + G r_1871 + G r_1872 + G r_1873 + G r_1874 + G r_1875 + G r_1876 + G r_1877 + G r_1878 + G r_1879 + G r_1880 + G r_1881 + G r_1882 + G r_1883 + G r_1884 + G r_1885 + G r_1886 + G r_1887 + G r_1888 + G r_1889 + G r_1890 + G r_1891 + G r_1892 + G r_1893 + G r_1894 + G r_1895 + G r_1896 + G r_1897 + G r_1898 + G r_1899 + G r_1900 + G r_1901 + G r_1902 + G r_1903 + G r_1904 + G r_1905 + G r_1906 + G r_1907 + G r_1908 + G r_1909 + G r_1910 + G r_1911 + G r_1912 + G r_1913 + G r_1914 + G r_1915 + G r_1916 + G r_1917 + G r_1918 + G r_1919 + G r_1920 + G r_1921 + G r_1922 + G r_1923 + G r_1924 + G r_1925 + G r_1926 + G r_1927 + G r_1928 + G r_1929 + G r_1930 + G r_1931 + G r_1932 + G r_1933 + G r_1934 + G r_1935 + G r_1936 + G r_1937 + G r_1938 + G r_1939 + G r_1940 + G r_1941 + G r_1942 + G r_1943 + G r_1944 + G r_1945 + G r_1946 + G r_1947 + G r_1948 + G r_1949 + G r_1950 + G r_1951 + G r_1952 + G r_1953 + G r_1954 + G r_1955 + G r_1956 + G r_1957 + G r_1958 + G r_1959 + G r_1960 + G r_1961 + G r_1962 + G r_1963 + G r_1964 + G r_1965 + G r_1966 + G r_1967 + G r_1968 + G r_1969 + G r_1970 + G r_1971 + G r_1972 + G r_1973 + G r_1974 + G r_1975 + G r_1976 + G r_1977 + G r_1978 + G r_1979 + G r_1980 + G r_1981 + G r_1982 + G r_1983 + G r_1984 + G r_1985 + G r_1986 + G r_1987 + G r_1988 + G r_1989 + G r_1990 + G r_1991 + G r_1992 + G r_1993 + G r_1994 + G r_1995 + G r_1996 + G r_1997 + G r_1998 + G r_1999 + G r_2000 + G r_2001 + G r_2002 + G r_2003 + G r_2004 + G r_2005 + G r_2006 + G r_2007 + G r_2008 + G r_2009 + G r_2010 + G r_2011 + G r_2012 + G r_2013 + G r_2014 + G r_2015 + G r_2016 + G r_2017 + G r_2018 + G r_2019 + G r_2020 + E r_2021 + L r_2022 + E r_2023 + E r_2024 + E r_2025 + E r_2026 + E r_2027 + E r_2028 + E r_2029 + E r_2030 + E r_2031 + E r_2032 + E r_2033 + E r_2034 + E r_2035 + E r_2036 + E r_2037 + E r_2038 + E r_2039 + E r_2040 + E r_2041 + E r_2042 + E r_2043 + E r_2044 + E r_2045 + E r_2046 + E r_2047 + E r_2048 + E r_2049 + E r_2050 + E r_2051 + E r_2052 + E r_2053 + E r_2054 + E r_2055 + E r_2056 + E r_2057 + E r_2058 + E r_2059 + E r_2060 + G r_2061 + G r_2062 + G r_2063 + G r_2064 + G r_2065 + G r_2066 + G r_2067 + L r_2068 + L r_2069 + L r_2070 + L r_2071 + L r_2072 + L r_2073 + L r_2074 + L r_2075 + L r_2076 + L r_2077 + L r_2078 + L r_2079 + L r_2080 + L r_2081 + L r_2082 + L r_2083 + L r_2084 + L r_2085 + L r_2086 + L r_2087 + L r_2088 + L r_2089 + L r_2090 + L r_2091 + L r_2092 + L r_2093 + L r_2094 + L r_2095 + L r_2096 + L r_2097 + L r_2098 + L r_2099 + L r_2100 + L r_2101 + L r_2102 + L r_2103 + L r_2104 + L r_2105 + L r_2106 + L r_2107 + L r_2108 + L r_2109 + L r_2110 + L r_2111 + L r_2112 + L r_2113 + L r_2114 + L r_2115 + L r_2116 + L r_2117 + L r_2118 + L r_2119 + L r_2120 + L r_2121 + L r_2122 + L r_2123 + L r_2124 + L r_2125 + L r_2126 + L r_2127 + L r_2128 + L r_2129 + L r_2130 + L r_2131 + L r_2132 + L r_2133 + L r_2134 + L r_2135 + L r_2136 + L r_2137 + L r_2138 + L r_2139 + L r_2140 + L r_2141 + L r_2142 + L r_2143 + L r_2144 + L r_2145 + L r_2146 + L r_2147 + L r_2148 + L r_2149 + L r_2150 + L r_2151 + L r_2152 + L r_2153 + L r_2154 + L r_2155 + L r_2156 + L r_2157 + L r_2158 + L r_2159 + L r_2160 + L r_2161 + L r_2162 + L r_2163 + L r_2164 + L r_2165 + L r_2166 + L r_2167 + L r_2168 + L r_2169 + L r_2170 + L r_2171 + L r_2172 + L r_2173 + L r_2174 + L r_2175 + L r_2176 + L r_2177 + L r_2178 + L r_2179 + L r_2180 + L r_2181 + L r_2182 + L r_2183 + L r_2184 + L r_2185 + L r_2186 + L r_2187 + L r_2188 + L r_2189 + L r_2190 + L r_2191 + L r_2192 + L r_2193 + L r_2194 + L r_2195 + L r_2196 + L r_2197 + L r_2198 + L r_2199 + L r_2200 + L r_2201 + L r_2202 + L r_2203 + L r_2204 + L r_2205 + L r_2206 + L r_2207 + L r_2208 + L r_2209 + L r_2210 + L r_2211 + L r_2212 + L r_2213 + L r_2214 + L r_2215 + L r_2216 + L r_2217 + L r_2218 + L r_2219 + L r_2220 + L r_2221 + L r_2222 + L r_2223 + L r_2224 + L r_2225 + L r_2226 + L r_2227 + L r_2228 + L r_2229 + L r_2230 + L r_2231 + L r_2232 + L r_2233 + L r_2234 + L r_2235 + L r_2236 + L r_2237 + L r_2238 + L r_2239 + L r_2240 + L r_2241 + L r_2242 + L r_2243 + L r_2244 + L r_2245 + L r_2246 + L r_2247 + L r_2248 + L r_2249 + L r_2250 + L r_2251 + L r_2252 + L r_2253 + L r_2254 + L r_2255 + L r_2256 + L r_2257 + L r_2258 + L r_2259 + L r_2260 + L r_2261 + L r_2262 + L r_2263 + L r_2264 + L r_2265 + L r_2266 + L r_2267 + L r_2268 + L r_2269 + L r_2270 + L r_2271 + L r_2272 + L r_2273 + L r_2274 + L r_2275 + L r_2276 + L r_2277 + L r_2278 + L r_2279 + L r_2280 + L r_2281 + L r_2282 + L r_2283 + L r_2284 + L r_2285 + L r_2286 + L r_2287 + L r_2288 + L r_2289 + L r_2290 + L r_2291 + L r_2292 + L r_2293 + L r_2294 + L r_2295 + L r_2296 + L r_2297 + L r_2298 + L r_2299 + L r_2300 + L r_2301 + L r_2302 + L r_2303 + L r_2304 + L r_2305 + L r_2306 + L r_2307 + L r_2308 + L r_2309 + L r_2310 + L r_2311 + L r_2312 + L r_2313 + L r_2314 + L r_2315 + L r_2316 + L r_2317 + L r_2318 + L r_2319 + L r_2320 + L r_2321 + L r_2322 + L r_2323 + L r_2324 + L r_2325 + L r_2326 + L r_2327 + L r_2328 + L r_2329 + L r_2330 + L r_2331 + L r_2332 + L r_2333 + L r_2334 + L r_2335 + L r_2336 + L r_2337 + L r_2338 + L r_2339 + L r_2340 + L r_2341 + L r_2342 + L r_2343 + L r_2344 + L r_2345 + L r_2346 + L r_2347 + L r_2348 + L r_2349 + L r_2350 + L r_2351 + L r_2352 + L r_2353 + L r_2354 + L r_2355 + L r_2356 + L r_2357 + L r_2358 + L r_2359 + L r_2360 + L r_2361 + L r_2362 + L r_2363 + L r_2364 + L r_2365 + L r_2366 + L r_2367 + L r_2368 + L r_2369 + L r_2370 + L r_2371 + L r_2372 + L r_2373 + L r_2374 + L r_2375 + L r_2376 + L r_2377 + L r_2378 + L r_2379 + L r_2380 + L r_2381 + L r_2382 + L r_2383 + L r_2384 + L r_2385 + L r_2386 + L r_2387 + L r_2388 + L r_2389 + L r_2390 + L r_2391 + L r_2392 + L r_2393 + L r_2394 + L r_2395 + L r_2396 + L r_2397 + L r_2398 + L r_2399 + L r_2400 + L r_2401 + L r_2402 + L r_2403 + L r_2404 + L r_2405 + L r_2406 + L r_2407 + L r_2408 + L r_2409 + L r_2410 + L r_2411 + L r_2412 + L r_2413 + L r_2414 + L r_2415 + L r_2416 + L r_2417 + L r_2418 + L r_2419 + L r_2420 + L r_2421 + L r_2422 + L r_2423 + L r_2424 + L r_2425 + L r_2426 + L r_2427 + L r_2428 + L r_2429 + L r_2430 + L r_2431 + L r_2432 + L r_2433 + L r_2434 + L r_2435 + L r_2436 + L r_2437 + L r_2438 + L r_2439 + L r_2440 + L r_2441 + L r_2442 + L r_2443 + L r_2444 + L r_2445 + L r_2446 + L r_2447 + L r_2448 + L r_2449 + L r_2450 + L r_2451 + L r_2452 + L r_2453 + L r_2454 + L r_2455 + L r_2456 + L r_2457 + L r_2458 + L r_2459 + L r_2460 + L r_2461 + L r_2462 + L r_2463 + L r_2464 + L r_2465 + L r_2466 + L r_2467 + L r_2468 + L r_2469 + L r_2470 + L r_2471 + L r_2472 + L r_2473 + L r_2474 + L r_2475 + L r_2476 + L r_2477 + L r_2478 + L r_2479 + L r_2480 + L r_2481 + L r_2482 + L r_2483 + L r_2484 + L r_2485 + L r_2486 + L r_2487 + L r_2488 + L r_2489 + L r_2490 + L r_2491 + L r_2492 + L r_2493 + L r_2494 + L r_2495 + L r_2496 + L r_2497 + L r_2498 + L r_2499 + L r_2500 + L r_2501 + L r_2502 + L r_2503 + L r_2504 + L r_2505 + L r_2506 + L r_2507 + L r_2508 + L r_2509 + L r_2510 + L r_2511 + L r_2512 + L r_2513 + L r_2514 + L r_2515 + L r_2516 + L r_2517 + L r_2518 + L r_2519 + L r_2520 + L r_2521 + L r_2522 + L r_2523 + L r_2524 + L r_2525 + L r_2526 + L r_2527 + L r_2528 + L r_2529 + L r_2530 + L r_2531 + L r_2532 + L r_2533 + L r_2534 + L r_2535 + L r_2536 + L r_2537 + L r_2538 + L r_2539 + L r_2540 + L r_2541 + L r_2542 + L r_2543 + L r_2544 + L r_2545 + L r_2546 + L r_2547 + L r_2548 + L r_2549 + L r_2550 + L r_2551 + L r_2552 + L r_2553 + L r_2554 + L r_2555 + L r_2556 + L r_2557 + L r_2558 + L r_2559 + L r_2560 + L r_2561 + L r_2562 + L r_2563 + L r_2564 + L r_2565 + L r_2566 + L r_2567 + L r_2568 + L r_2569 + L r_2570 + L r_2571 + L r_2572 + L r_2573 + L r_2574 + L r_2575 + L r_2576 + L r_2577 + L r_2578 + L r_2579 + L r_2580 + L r_2581 + L r_2582 + L r_2583 + L r_2584 + L r_2585 + L r_2586 + L r_2587 + L r_2588 + L r_2589 + L r_2590 + L r_2591 + L r_2592 + L r_2593 + L r_2594 + L r_2595 + L r_2596 + L r_2597 + L r_2598 + L r_2599 + L r_2600 + L r_2601 + L r_2602 + L r_2603 + L r_2604 + L r_2605 + L r_2606 + L r_2607 + L r_2608 + L r_2609 + L r_2610 + L r_2611 + L r_2612 + L r_2613 + L r_2614 + L r_2615 + L r_2616 + L r_2617 + L r_2618 + L r_2619 + L r_2620 + L r_2621 + L r_2622 + L r_2623 + L r_2624 + L r_2625 + L r_2626 + L r_2627 + L r_2628 + L r_2629 + L r_2630 + L r_2631 + L r_2632 + L r_2633 + L r_2634 + L r_2635 + L r_2636 + L r_2637 + L r_2638 + L r_2639 + L r_2640 + L r_2641 + L r_2642 + L r_2643 + L r_2644 + L r_2645 + L r_2646 + L r_2647 + L r_2648 + L r_2649 + L r_2650 + L r_2651 + L r_2652 + L r_2653 + L r_2654 + L r_2655 + L r_2656 + L r_2657 + L r_2658 + L r_2659 + L r_2660 + L r_2661 + L r_2662 + L r_2663 + L r_2664 + L r_2665 + L r_2666 + L r_2667 + L r_2668 + L r_2669 + L r_2670 + L r_2671 + L r_2672 + L r_2673 + L r_2674 + L r_2675 + L r_2676 + L r_2677 + L r_2678 + L r_2679 + L r_2680 + L r_2681 + L r_2682 + L r_2683 + L r_2684 + L r_2685 + L r_2686 + L r_2687 + L r_2688 + L r_2689 + L r_2690 + L r_2691 + L r_2692 + L r_2693 + L r_2694 + L r_2695 + L r_2696 + L r_2697 + L r_2698 + L r_2699 + L r_2700 + L r_2701 + L r_2702 + L r_2703 + L r_2704 + L r_2705 + L r_2706 + L r_2707 + L r_2708 + L r_2709 + L r_2710 + L r_2711 + L r_2712 + L r_2713 + L r_2714 + L r_2715 + L r_2716 + L r_2717 + L r_2718 + L r_2719 + L r_2720 + L r_2721 + L r_2722 + L r_2723 + L r_2724 + L r_2725 + L r_2726 + L r_2727 + L r_2728 + L r_2729 + L r_2730 + L r_2731 + L r_2732 + L r_2733 + L r_2734 + L r_2735 + L r_2736 + L r_2737 + L r_2738 + L r_2739 + L r_2740 + L r_2741 + L r_2742 + L r_2743 + L r_2744 + L r_2745 + L r_2746 + L r_2747 + L r_2748 + L r_2749 + L r_2750 + L r_2751 + L r_2752 + L r_2753 + L r_2754 + L r_2755 + L r_2756 + L r_2757 + L r_2758 + L r_2759 + L r_2760 + L r_2761 + L r_2762 + L r_2763 + L r_2764 + L r_2765 + L r_2766 + L r_2767 + L r_2768 + L r_2769 + L r_2770 + L r_2771 + L r_2772 + L r_2773 + L r_2774 + L r_2775 + L r_2776 + L r_2777 + L r_2778 + L r_2779 + L r_2780 + L r_2781 + L r_2782 + L r_2783 + L r_2784 + L r_2785 + L r_2786 + L r_2787 + L r_2788 + L r_2789 + L r_2790 + L r_2791 + L r_2792 + L r_2793 + L r_2794 + L r_2795 + L r_2796 + L r_2797 + L r_2798 + L r_2799 + L r_2800 + L r_2801 + L r_2802 + L r_2803 + L r_2804 + L r_2805 + L r_2806 + L r_2807 + E r_2808 + E r_2809 + E r_2810 + E r_2811 + E r_2812 + E r_2813 + E r_2814 + E r_2815 + E r_2816 + E r_2817 + E r_2818 + E r_2819 + E r_2820 + E r_2821 + E r_2822 + E r_2823 + G r_2824 + G r_2825 + G r_2826 + G r_2827 + G r_2828 + G r_2829 + G r_2830 + G r_2831 + G r_2832 + G r_2833 + G r_2834 + G r_2835 + G r_2836 + L r_2837 + L r_2838 + L r_2839 + L r_2840 + L r_2841 + L r_2842 + L r_2843 + L r_2844 + L r_2845 + L r_2846 + L r_2847 + L r_2848 + L r_2849 + L r_2850 + L r_2851 + L r_2852 + L r_2853 + L r_2854 + L r_2855 + L r_2856 + L r_2857 + L r_2858 + L r_2859 + L r_2860 + L r_2861 + L r_2862 + L r_2863 + L r_2864 + L r_2865 + L r_2866 + L r_2867 + L r_2868 + L r_2869 + L r_2870 + L r_2871 + L r_2872 + L r_2873 + L r_2874 + L r_2875 + L r_2876 + L r_2877 + L r_2878 + L r_2879 + L r_2880 + L r_2881 + L r_2882 + L r_2883 + L r_2884 + L r_2885 + L r_2886 + L r_2887 + L r_2888 + L r_2889 + L r_2890 + L r_2891 + L r_2892 + L r_2893 + L r_2894 + L r_2895 + L r_2896 + L r_2897 + L r_2898 + L r_2899 + L r_2900 + L r_2901 + L r_2902 + L r_2903 + L r_2904 + L r_2905 + L r_2906 + L r_2907 + L r_2908 + L r_2909 + L r_2910 + L r_2911 + L r_2912 + L r_2913 + L r_2914 + L r_2915 + L r_2916 + L r_2917 + L r_2918 + L r_2919 + L r_2920 + L r_2921 + L r_2922 + L r_2923 + L r_2924 + L r_2925 + L r_2926 + L r_2927 + L r_2928 + L r_2929 + L r_2930 + L r_2931 + L r_2932 + L r_2933 + L r_2934 + L r_2935 + L r_2936 + L r_2937 + L r_2938 + L r_2939 + L r_2940 + L r_2941 + L r_2942 + L r_2943 + L r_2944 + L r_2945 + L r_2946 + L r_2947 + L r_2948 + L r_2949 + L r_2950 + L r_2951 + L r_2952 + L r_2953 + L r_2954 + L r_2955 + L r_2956 + L r_2957 + L r_2958 + L r_2959 + L r_2960 + L r_2961 + L r_2962 + L r_2963 + L r_2964 + L r_2965 + L r_2966 + L r_2967 + L r_2968 + L r_2969 + L r_2970 + L r_2971 + L r_2972 + L r_2973 + L r_2974 + L r_2975 + L r_2976 + L r_2977 + L r_2978 + L r_2979 + L r_2980 + L r_2981 + L r_2982 + L r_2983 + L r_2984 + L r_2985 + L r_2986 + L r_2987 + L r_2988 + L r_2989 + L r_2990 + L r_2991 + L r_2992 + L r_2993 + L r_2994 + L r_2995 + L r_2996 + L r_2997 + L r_2998 + L r_2999 + L r_3000 + L r_3001 + L r_3002 + L r_3003 + L r_3004 + L r_3005 + L r_3006 + L r_3007 + L r_3008 + L r_3009 + L r_3010 + L r_3011 + L r_3012 + L r_3013 + L r_3014 + L r_3015 + L r_3016 + L r_3017 + L r_3018 + L r_3019 + L r_3020 + L r_3021 + L r_3022 + L r_3023 + L r_3024 + L r_3025 + L r_3026 + L r_3027 + L r_3028 + L r_3029 + L r_3030 + L r_3031 + L r_3032 + L r_3033 + L r_3034 + L r_3035 + L r_3036 + L r_3037 + L r_3038 + L r_3039 + L r_3040 + L r_3041 + L r_3042 + L r_3043 + L r_3044 + L r_3045 + L r_3046 + L r_3047 + L r_3048 + L r_3049 + E r_3050 + E r_3051 + E r_3052 +COLUMNS + MARK0000 'MARKER' 'INTORG' + v10 r_1 1 + v10 r_1975 -1 + v10 r_2021 1 + v10 r_2029 1 + v10 r_2630 1 + v10 r_2631 1 + v10 r_2754 1 + v10 r_2817 1 + v10 r_2824 1 + v11 r_2 1 + v11 r_428 1 + v11 r_519 1 + v11 r_644 1 + v11 r_769 1 + v11 r_898 1 + v11 r_1003 1 + v11 r_1132 1 + v11 r_1261 1 + v11 r_2045 1 + v11 r_2275 1 + v11 r_2276 1 + v11 r_2277 1 + v11 r_2460 -1 + v11 r_2461 -1 + v11 r_2630 1 + v11 r_2631 1 + v11 r_2632 1 + v12 r_2 1 + v12 r_170 1 + v12 r_303 -1 + v12 r_1368 1 + v12 r_1439 -1 + v12 r_2068 1 + v12 r_2069 1 + v12 r_2070 1 + v12 r_2838 1 + v12 r_2839 1 + v12 r_2954 1 + v12 r_2955 1 + v12 r_2956 1 + v13 r_2 1 + v13 r_184 1 + v13 r_316 -1 + v13 r_1369 1 + v13 r_1445 -1 + v13 r_2068 1 + v13 r_2069 1 + v13 r_2070 1 + v14 r_2 1 + v14 r_202 1 + v14 r_333 -1 + v14 r_1370 1 + v14 r_1453 -1 + v14 r_2068 1 + v14 r_2069 1 + v14 r_2070 1 + v15 r_2 1 + v15 r_220 1 + v15 r_350 -1 + v15 r_1371 1 + v15 r_1461 -1 + v15 r_2068 1 + v15 r_2069 1 + v15 r_2070 1 + v16 r_2 1 + v16 r_238 1 + v16 r_367 -1 + v16 r_1372 1 + v16 r_1469 -1 + v16 r_2068 1 + v16 r_2069 1 + v16 r_2070 1 + v16 r_2838 1 + v16 r_2839 1 + v16 r_2954 1 + v16 r_2955 1 + v16 r_2956 1 + v17 r_2 1 + v17 r_254 1 + v17 r_382 -1 + v17 r_1373 1 + v17 r_1476 -1 + v17 r_2068 1 + v17 r_2069 1 + v17 r_2070 1 + v18 r_2 1 + v18 r_272 1 + v18 r_399 -1 + v18 r_1374 1 + v18 r_1484 -1 + v18 r_2068 1 + v18 r_2069 1 + v18 r_2070 1 + v19 r_2 1 + v19 r_289 1 + v19 r_416 -1 + v19 r_1375 1 + v19 r_1492 -1 + v19 r_2068 1 + v19 r_2069 1 + v19 r_2070 1 + v19 r_2954 1 + v19 r_2955 1 + v19 r_2956 1 + v20 r_2 1 + v20 r_1976 -1 + v20 r_2021 1 + v20 r_2030 1 + v20 r_2630 1 + v20 r_2631 1 + v20 r_2632 1 + v21 r_3 1 + v21 r_429 1 + v21 r_520 1 + v21 r_645 1 + v21 r_770 1 + v21 r_899 1 + v21 r_1004 1 + v21 r_1133 1 + v21 r_1262 1 + v21 r_2046 1 + v21 r_2276 1 + v21 r_2277 1 + v21 r_2278 1 + v21 r_2403 1 + v21 r_2404 1 + v21 r_2460 -1 + v21 r_2461 -1 + v21 r_2462 -1 + v21 r_2582 -1 + v21 r_2583 -1 + v21 r_2630 1 + v21 r_2631 1 + v21 r_2632 1 + v21 r_2633 1 + v21 r_2754 1 + v21 r_2755 1 + v21 r_2808 1 + v21 r_2824 1 + v22 r_3 1 + v22 r_171 1 + v22 r_304 -1 + v22 r_1368 1 + v22 r_1440 -1 + v22 r_2069 1 + v22 r_2070 1 + v22 r_2071 1 + v22 r_2212 1 + v22 r_2213 1 + v22 r_2839 1 + v22 r_2840 1 + v22 r_2955 1 + v22 r_2956 1 + v22 r_2957 1 + v23 r_3 1 + v23 r_185 1 + v23 r_317 -1 + v23 r_1369 1 + v23 r_1446 -1 + v23 r_2069 1 + v23 r_2070 1 + v23 r_2071 1 + v23 r_2212 1 + v23 r_2213 1 + v24 r_3 1 + v24 r_203 1 + v24 r_334 -1 + v24 r_1370 1 + v24 r_1454 -1 + v24 r_2069 1 + v24 r_2070 1 + v24 r_2071 1 + v24 r_2212 1 + v24 r_2213 1 + v25 r_3 1 + v25 r_221 1 + v25 r_351 -1 + v25 r_1371 1 + v25 r_1462 -1 + v25 r_2069 1 + v25 r_2070 1 + v25 r_2071 1 + v25 r_2212 1 + v25 r_2213 1 + v26 r_3 1 + v26 r_239 1 + v26 r_368 -1 + v26 r_1372 1 + v26 r_1470 -1 + v26 r_2069 1 + v26 r_2070 1 + v26 r_2071 1 + v26 r_2212 1 + v26 r_2213 1 + v26 r_2839 1 + v26 r_2840 1 + v26 r_2955 1 + v26 r_2956 1 + v26 r_2957 1 + v27 r_3 1 + v27 r_255 1 + v27 r_383 -1 + v27 r_1373 1 + v27 r_1477 -1 + v27 r_2069 1 + v27 r_2070 1 + v27 r_2071 1 + v27 r_2212 1 + v27 r_2213 1 + v28 r_3 1 + v28 r_273 1 + v28 r_400 -1 + v28 r_1374 1 + v28 r_1485 -1 + v28 r_2069 1 + v28 r_2070 1 + v28 r_2071 1 + v28 r_2212 1 + v28 r_2213 1 + v29 r_3 1 + v29 r_290 1 + v29 r_417 -1 + v29 r_1375 1 + v29 r_1493 -1 + v29 r_2069 1 + v29 r_2070 1 + v29 r_2071 1 + v29 r_2212 1 + v29 r_2213 1 + v29 r_2955 1 + v29 r_2956 1 + v29 r_2957 1 + v30 r_3 1 + v30 r_1977 -1 + v30 r_2021 1 + v30 r_2031 1 + v30 r_2630 1 + v30 r_2631 1 + v30 r_2632 1 + v30 r_2633 1 + v30 r_2754 1 + v30 r_2755 1 + v30 r_2817 1 + v30 r_2824 1 + v31 r_4 1 + v31 r_430 1 + v31 r_521 1 + v31 r_646 1 + v31 r_771 1 + v31 r_900 1 + v31 r_1005 1 + v31 r_1134 1 + v31 r_1263 1 + v31 r_2047 1 + v31 r_2277 1 + v31 r_2278 1 + v31 r_2279 1 + v31 r_2460 -1 + v31 r_2461 -1 + v31 r_2462 -1 + v31 r_2463 -1 + v31 r_2630 1 + v31 r_2631 1 + v31 r_2632 1 + v31 r_2633 1 + v31 r_2634 1 + v32 r_4 1 + v32 r_172 1 + v32 r_305 -1 + v32 r_1368 1 + v32 r_1441 -1 + v32 r_2070 1 + v32 r_2071 1 + v32 r_2072 1 + v32 r_2840 1 + v32 r_2841 1 + v32 r_2956 1 + v32 r_2957 1 + v32 r_2958 1 + v33 r_4 1 + v33 r_186 1 + v33 r_318 -1 + v33 r_1369 1 + v33 r_1447 -1 + v33 r_2070 1 + v33 r_2071 1 + v33 r_2072 1 + v34 r_4 1 + v34 r_204 1 + v34 r_335 -1 + v34 r_1370 1 + v34 r_1455 -1 + v34 r_2070 1 + v34 r_2071 1 + v34 r_2072 1 + v35 r_4 1 + v35 r_222 1 + v35 r_352 -1 + v35 r_1371 1 + v35 r_1463 -1 + v35 r_2070 1 + v35 r_2071 1 + v35 r_2072 1 + v36 r_4 1 + v36 r_240 1 + v36 r_369 -1 + v36 r_1372 1 + v36 r_1471 -1 + v36 r_2070 1 + v36 r_2071 1 + v36 r_2072 1 + v36 r_2840 1 + v36 r_2841 1 + v36 r_2956 1 + v36 r_2957 1 + v36 r_2958 1 + v37 r_4 1 + v37 r_256 1 + v37 r_384 -1 + v37 r_1373 1 + v37 r_1478 -1 + v37 r_2070 1 + v37 r_2071 1 + v37 r_2072 1 + v38 r_4 1 + v38 r_274 1 + v38 r_401 -1 + v38 r_1374 1 + v38 r_1486 -1 + v38 r_2070 1 + v38 r_2071 1 + v38 r_2072 1 + v39 r_4 1 + v39 r_291 1 + v39 r_418 -1 + v39 r_1375 1 + v39 r_1494 -1 + v39 r_2070 1 + v39 r_2071 1 + v39 r_2072 1 + v39 r_2956 1 + v39 r_2957 1 + v39 r_2958 1 + v40 r_4 1 + v40 r_1978 -1 + v40 r_2021 1 + v40 r_2032 1 + v40 r_2630 1 + v40 r_2631 1 + v40 r_2632 1 + v40 r_2633 1 + v40 r_2634 1 + v41 r_5 1 + v41 r_431 1 + v41 r_522 1 + v41 r_647 1 + v41 r_772 1 + v41 r_901 1 + v41 r_1006 1 + v41 r_1135 1 + v41 r_1264 1 + v41 r_2048 1 + v41 r_2278 1 + v41 r_2279 1 + v41 r_2280 1 + v41 r_2403 1 + v41 r_2404 1 + v41 r_2405 1 + v41 r_2461 -1 + v41 r_2462 -1 + v41 r_2463 -1 + v41 r_2464 -1 + v41 r_2582 -1 + v41 r_2583 -1 + v41 r_2584 -1 + v41 r_2631 1 + v41 r_2632 1 + v41 r_2633 1 + v41 r_2634 1 + v41 r_2635 1 + v41 r_2754 1 + v41 r_2755 1 + v41 r_2756 1 + v41 r_2808 1 + v41 r_2824 1 + v42 r_5 1 + v42 r_173 1 + v42 r_306 -1 + v42 r_1368 1 + v42 r_1442 -1 + v42 r_2071 1 + v42 r_2072 1 + v42 r_2073 1 + v42 r_2212 1 + v42 r_2213 1 + v42 r_2214 1 + v42 r_2841 1 + v42 r_2842 1 + v42 r_2957 1 + v42 r_2958 1 + v42 r_2959 1 + v43 r_5 1 + v43 r_187 1 + v43 r_319 -1 + v43 r_1369 1 + v43 r_1448 -1 + v43 r_2071 1 + v43 r_2072 1 + v43 r_2073 1 + v43 r_2212 1 + v43 r_2213 1 + v43 r_2214 1 + v44 r_5 1 + v44 r_205 1 + v44 r_336 -1 + v44 r_1370 1 + v44 r_1456 -1 + v44 r_2071 1 + v44 r_2072 1 + v44 r_2073 1 + v44 r_2212 1 + v44 r_2213 1 + v44 r_2214 1 + v45 r_5 1 + v45 r_223 1 + v45 r_353 -1 + v45 r_1371 1 + v45 r_1464 -1 + v45 r_2071 1 + v45 r_2072 1 + v45 r_2073 1 + v45 r_2212 1 + v45 r_2213 1 + v45 r_2214 1 + v46 r_5 1 + v46 r_241 1 + v46 r_370 -1 + v46 r_1372 1 + v46 r_1472 -1 + v46 r_2071 1 + v46 r_2072 1 + v46 r_2073 1 + v46 r_2212 1 + v46 r_2213 1 + v46 r_2214 1 + v46 r_2841 1 + v46 r_2842 1 + v46 r_2957 1 + v46 r_2958 1 + v46 r_2959 1 + v47 r_5 1 + v47 r_257 1 + v47 r_385 -1 + v47 r_1373 1 + v47 r_1479 -1 + v47 r_2071 1 + v47 r_2072 1 + v47 r_2073 1 + v47 r_2212 1 + v47 r_2213 1 + v47 r_2214 1 + v48 r_5 1 + v48 r_275 1 + v48 r_402 -1 + v48 r_1374 1 + v48 r_1487 -1 + v48 r_2071 1 + v48 r_2072 1 + v48 r_2073 1 + v48 r_2212 1 + v48 r_2213 1 + v48 r_2214 1 + v49 r_5 1 + v49 r_292 1 + v49 r_419 -1 + v49 r_1375 1 + v49 r_1495 -1 + v49 r_2071 1 + v49 r_2072 1 + v49 r_2073 1 + v49 r_2212 1 + v49 r_2213 1 + v49 r_2214 1 + v49 r_2957 1 + v49 r_2958 1 + v49 r_2959 1 + v50 r_5 1 + v50 r_1979 -1 + v50 r_2021 1 + v50 r_2033 1 + v50 r_2631 1 + v50 r_2632 1 + v50 r_2633 1 + v50 r_2634 1 + v50 r_2635 1 + v50 r_2754 1 + v50 r_2755 1 + v50 r_2756 1 + v50 r_2817 1 + v50 r_2824 1 + v51 r_6 1 + v51 r_523 1 + v51 r_648 1 + v51 r_773 1 + v51 r_902 1 + v51 r_1007 1 + v51 r_1136 1 + v51 r_1265 1 + v51 r_2049 1 + v51 r_2279 1 + v51 r_2280 1 + v51 r_2281 1 + v51 r_2462 -1 + v51 r_2463 -1 + v51 r_2464 -1 + v51 r_2465 -1 + v51 r_2632 1 + v51 r_2633 1 + v51 r_2634 1 + v51 r_2635 1 + v51 r_2636 1 + v52 r_6 1 + v52 r_188 1 + v52 r_320 -1 + v52 r_1369 1 + v52 r_1449 -1 + v52 r_2072 1 + v52 r_2073 1 + v52 r_2074 1 + v53 r_6 1 + v53 r_206 1 + v53 r_337 -1 + v53 r_1370 1 + v53 r_1457 -1 + v53 r_2072 1 + v53 r_2073 1 + v53 r_2074 1 + v54 r_6 1 + v54 r_224 1 + v54 r_354 -1 + v54 r_1371 1 + v54 r_1465 -1 + v54 r_2072 1 + v54 r_2073 1 + v54 r_2074 1 + v55 r_6 1 + v55 r_242 1 + v55 r_371 -1 + v55 r_1372 1 + v55 r_1473 -1 + v55 r_2072 1 + v55 r_2073 1 + v55 r_2074 1 + v55 r_2842 1 + v55 r_2843 1 + v55 r_2958 1 + v55 r_2959 1 + v55 r_2960 1 + v56 r_6 1 + v56 r_258 1 + v56 r_386 -1 + v56 r_1373 1 + v56 r_1480 -1 + v56 r_2072 1 + v56 r_2073 1 + v56 r_2074 1 + v57 r_6 1 + v57 r_276 1 + v57 r_403 -1 + v57 r_1374 1 + v57 r_1488 -1 + v57 r_2072 1 + v57 r_2073 1 + v57 r_2074 1 + v58 r_6 1 + v58 r_293 1 + v58 r_420 -1 + v58 r_1375 1 + v58 r_1496 -1 + v58 r_2072 1 + v58 r_2073 1 + v58 r_2074 1 + v58 r_2958 1 + v58 r_2959 1 + v58 r_2960 1 + v59 r_7 1 + v59 r_432 1 + v59 r_524 1 + v59 r_649 1 + v59 r_774 1 + v59 r_903 1 + v59 r_1008 1 + v59 r_1137 1 + v59 r_2050 1 + v59 r_2280 1 + v59 r_2281 1 + v59 r_2282 1 + v59 r_2404 1 + v59 r_2405 1 + v59 r_2406 1 + v59 r_2463 -1 + v59 r_2464 -1 + v59 r_2465 -1 + v59 r_2466 -1 + v59 r_2582 -1 + v59 r_2583 -1 + v59 r_2584 -1 + v59 r_2585 -1 + v59 r_2633 1 + v59 r_2634 1 + v59 r_2635 1 + v59 r_2636 1 + v59 r_2637 1 + v59 r_2754 1 + v59 r_2755 1 + v59 r_2756 1 + v59 r_2757 1 + v59 r_2808 1 + v59 r_2824 1 + v60 r_7 1 + v60 r_174 1 + v60 r_307 -1 + v60 r_1368 1 + v60 r_1498 1 + v60 r_2073 1 + v60 r_2074 1 + v60 r_2075 1 + v60 r_2213 1 + v60 r_2214 1 + v60 r_2215 1 + v60 r_2843 1 + v60 r_2844 1 + v60 r_2959 1 + v60 r_2960 1 + v60 r_2961 1 + v61 r_7 1 + v61 r_189 1 + v61 r_321 -1 + v61 r_1369 1 + v61 r_2073 1 + v61 r_2074 1 + v61 r_2075 1 + v61 r_2213 1 + v61 r_2214 1 + v61 r_2215 1 + v62 r_7 1 + v62 r_207 1 + v62 r_338 -1 + v62 r_1370 1 + v62 r_2073 1 + v62 r_2074 1 + v62 r_2075 1 + v62 r_2213 1 + v62 r_2214 1 + v62 r_2215 1 + v63 r_7 1 + v63 r_225 1 + v63 r_355 -1 + v63 r_1371 1 + v63 r_1666 1 + v63 r_2073 1 + v63 r_2074 1 + v63 r_2075 1 + v63 r_2213 1 + v63 r_2214 1 + v63 r_2215 1 + v64 r_7 1 + v64 r_243 1 + v64 r_372 -1 + v64 r_1372 1 + v64 r_1733 1 + v64 r_2073 1 + v64 r_2074 1 + v64 r_2075 1 + v64 r_2213 1 + v64 r_2214 1 + v64 r_2215 1 + v64 r_2843 1 + v64 r_2844 1 + v64 r_2959 1 + v64 r_2960 1 + v64 r_2961 1 + v65 r_7 1 + v65 r_259 1 + v65 r_387 -1 + v65 r_1373 1 + v65 r_1788 1 + v65 r_2073 1 + v65 r_2074 1 + v65 r_2075 1 + v65 r_2213 1 + v65 r_2214 1 + v65 r_2215 1 + v66 r_7 1 + v66 r_277 1 + v66 r_404 -1 + v66 r_1374 1 + v66 r_1855 1 + v66 r_2073 1 + v66 r_2074 1 + v66 r_2075 1 + v66 r_2213 1 + v66 r_2214 1 + v66 r_2215 1 + v67 r_8 1 + v67 r_433 1 + v67 r_525 1 + v67 r_650 1 + v67 r_775 1 + v67 r_904 1 + v67 r_1009 1 + v67 r_1138 1 + v67 r_1266 1 + v67 r_2051 1 + v67 r_2281 1 + v67 r_2282 1 + v67 r_2283 1 + v67 r_2464 -1 + v67 r_2465 -1 + v67 r_2466 -1 + v67 r_2467 -1 + v67 r_2634 1 + v67 r_2635 1 + v67 r_2636 1 + v67 r_2637 1 + v67 r_2638 1 + v68 r_8 1 + v68 r_175 1 + v68 r_308 -1 + v68 r_1368 1 + v68 r_1499 1 + v68 r_2074 1 + v68 r_2075 1 + v68 r_2076 1 + v68 r_2844 1 + v68 r_2845 1 + v68 r_2960 1 + v68 r_2961 1 + v68 r_2962 1 + v69 r_8 1 + v69 r_190 1 + v69 r_322 -1 + v69 r_1369 1 + v69 r_1546 1 + v69 r_2074 1 + v69 r_2075 1 + v69 r_2076 1 + v70 r_8 1 + v70 r_208 1 + v70 r_339 -1 + v70 r_1370 1 + v70 r_1606 1 + v70 r_2074 1 + v70 r_2075 1 + v70 r_2076 1 + v71 r_8 1 + v71 r_226 1 + v71 r_356 -1 + v71 r_1371 1 + v71 r_1667 1 + v71 r_2074 1 + v71 r_2075 1 + v71 r_2076 1 + v72 r_8 1 + v72 r_244 1 + v72 r_373 -1 + v72 r_1372 1 + v72 r_1734 1 + v72 r_2074 1 + v72 r_2075 1 + v72 r_2076 1 + v72 r_2844 1 + v72 r_2845 1 + v72 r_2960 1 + v72 r_2961 1 + v72 r_2962 1 + v73 r_8 1 + v73 r_260 1 + v73 r_388 -1 + v73 r_1373 1 + v73 r_1789 1 + v73 r_2074 1 + v73 r_2075 1 + v73 r_2076 1 + v74 r_8 1 + v74 r_278 1 + v74 r_405 -1 + v74 r_1374 1 + v74 r_1856 1 + v74 r_2074 1 + v74 r_2075 1 + v74 r_2076 1 + v75 r_8 1 + v75 r_294 1 + v75 r_421 -1 + v75 r_1375 1 + v75 r_1922 1 + v75 r_2074 1 + v75 r_2075 1 + v75 r_2076 1 + v75 r_2960 1 + v75 r_2961 1 + v75 r_2962 1 + v76 r_8 1 + v76 r_1975 1 + v76 r_2021 1 + v76 r_2034 1 + v76 r_2634 1 + v76 r_2635 1 + v76 r_2636 1 + v76 r_2637 1 + v76 r_2638 1 + v77 r_9 1 + v77 r_434 1 + v77 r_526 1 + v77 r_651 1 + v77 r_776 1 + v77 r_905 1 + v77 r_1010 1 + v77 r_1139 1 + v77 r_2052 1 + v77 r_2282 1 + v77 r_2283 1 + v77 r_2284 1 + v77 r_2405 1 + v77 r_2406 1 + v77 r_2407 1 + v77 r_2465 -1 + v77 r_2466 -1 + v77 r_2467 -1 + v77 r_2468 -1 + v77 r_2583 -1 + v77 r_2584 -1 + v77 r_2585 -1 + v77 r_2586 -1 + v77 r_2635 1 + v77 r_2636 1 + v77 r_2637 1 + v77 r_2638 1 + v77 r_2639 1 + v77 r_2755 1 + v77 r_2756 1 + v77 r_2757 1 + v77 r_2758 1 + v77 r_2808 1 + v77 r_2824 1 + v78 r_9 1 + v78 r_176 1 + v78 r_309 -1 + v78 r_1368 1 + v78 r_1443 -1 + v78 r_2075 1 + v78 r_2076 1 + v78 r_2077 1 + v78 r_2214 1 + v78 r_2215 1 + v78 r_2216 1 + v78 r_2845 1 + v78 r_2846 1 + v78 r_2961 1 + v78 r_2962 1 + v78 r_2963 1 + v79 r_9 1 + v79 r_191 1 + v79 r_323 -1 + v79 r_1369 1 + v79 r_1450 -1 + v79 r_2075 1 + v79 r_2076 1 + v79 r_2077 1 + v79 r_2214 1 + v79 r_2215 1 + v79 r_2216 1 + v80 r_9 1 + v80 r_209 1 + v80 r_340 -1 + v80 r_1370 1 + v80 r_1458 -1 + v80 r_2075 1 + v80 r_2076 1 + v80 r_2077 1 + v80 r_2214 1 + v80 r_2215 1 + v80 r_2216 1 + v81 r_9 1 + v81 r_227 1 + v81 r_357 -1 + v81 r_1371 1 + v81 r_1466 -1 + v81 r_2075 1 + v81 r_2076 1 + v81 r_2077 1 + v81 r_2214 1 + v81 r_2215 1 + v81 r_2216 1 + v82 r_9 1 + v82 r_245 1 + v82 r_374 -1 + v82 r_1372 1 + v82 r_1474 -1 + v82 r_2075 1 + v82 r_2076 1 + v82 r_2077 1 + v82 r_2214 1 + v82 r_2215 1 + v82 r_2216 1 + v82 r_2845 1 + v82 r_2846 1 + v82 r_2961 1 + v82 r_2962 1 + v82 r_2963 1 + v83 r_9 1 + v83 r_261 1 + v83 r_389 -1 + v83 r_1373 1 + v83 r_1481 -1 + v83 r_2075 1 + v83 r_2076 1 + v83 r_2077 1 + v83 r_2214 1 + v83 r_2215 1 + v83 r_2216 1 + v84 r_9 1 + v84 r_279 1 + v84 r_406 -1 + v84 r_1374 1 + v84 r_1489 -1 + v84 r_2075 1 + v84 r_2076 1 + v84 r_2077 1 + v84 r_2214 1 + v84 r_2215 1 + v84 r_2216 1 + v85 r_9 1 + v85 r_295 1 + v85 r_1375 1 + v85 r_1497 -1 + v85 r_2075 1 + v85 r_2076 1 + v85 r_2077 1 + v85 r_2214 1 + v85 r_2215 1 + v85 r_2216 1 + v85 r_2961 1 + v85 r_2962 1 + v85 r_2963 1 + v86 r_9 1 + v86 r_1980 -1 + v86 r_2021 1 + v86 r_2035 1 + v86 r_2635 1 + v86 r_2636 1 + v86 r_2637 1 + v86 r_2638 1 + v86 r_2639 1 + v86 r_2755 1 + v86 r_2756 1 + v86 r_2757 1 + v86 r_2758 1 + v86 r_2817 1 + v86 r_2824 1 + v87 r_10 1 + v87 r_527 1 + v87 r_652 1 + v87 r_777 1 + v87 r_1011 1 + v87 r_1140 1 + v87 r_1267 1 + v87 r_2053 1 + v87 r_2283 1 + v87 r_2284 1 + v87 r_2285 1 + v87 r_2466 -1 + v87 r_2467 -1 + v87 r_2468 -1 + v87 r_2469 -1 + v87 r_2636 1 + v87 r_2637 1 + v87 r_2638 1 + v87 r_2639 1 + v87 r_2640 1 + v88 r_10 1 + v88 r_192 1 + v88 r_324 -1 + v88 r_1369 1 + v88 r_1451 -1 + v88 r_2076 1 + v88 r_2077 1 + v88 r_2078 1 + v89 r_10 1 + v89 r_210 1 + v89 r_341 -1 + v89 r_1370 1 + v89 r_1459 -1 + v89 r_2076 1 + v89 r_2077 1 + v89 r_2078 1 + v90 r_10 1 + v90 r_228 1 + v90 r_358 -1 + v90 r_1371 1 + v90 r_1467 -1 + v90 r_2076 1 + v90 r_2077 1 + v90 r_2078 1 + v91 r_10 1 + v91 r_262 1 + v91 r_390 -1 + v91 r_1373 1 + v91 r_1482 -1 + v91 r_2076 1 + v91 r_2077 1 + v91 r_2078 1 + v92 r_10 1 + v92 r_280 1 + v92 r_407 -1 + v92 r_1374 1 + v92 r_1490 -1 + v92 r_2076 1 + v92 r_2077 1 + v92 r_2078 1 + v93 r_10 1 + v93 r_1981 -1 + v93 r_2021 1 + v93 r_2036 1 + v93 r_2636 1 + v93 r_2637 1 + v93 r_2638 1 + v93 r_2639 1 + v93 r_2640 1 + v94 r_11 1 + v94 r_435 1 + v94 r_528 1 + v94 r_653 1 + v94 r_778 1 + v94 r_906 1 + v94 r_1012 1 + v94 r_1141 1 + v94 r_1268 1 + v94 r_2054 1 + v94 r_2284 1 + v94 r_2285 1 + v94 r_2286 1 + v94 r_2406 1 + v94 r_2407 1 + v94 r_2408 1 + v94 r_2467 -1 + v94 r_2468 -1 + v94 r_2469 -1 + v94 r_2470 -1 + v94 r_2584 -1 + v94 r_2585 -1 + v94 r_2586 -1 + v94 r_2587 -1 + v94 r_2637 1 + v94 r_2638 1 + v94 r_2639 1 + v94 r_2640 1 + v94 r_2641 1 + v94 r_2756 1 + v94 r_2757 1 + v94 r_2758 1 + v94 r_2759 1 + v94 r_2808 1 + v95 r_11 1 + v95 r_177 1 + v95 r_310 -1 + v95 r_1368 1 + v95 r_1500 1 + v95 r_2077 1 + v95 r_2078 1 + v95 r_2079 1 + v95 r_2215 1 + v95 r_2216 1 + v95 r_2217 1 + v95 r_2847 1 + v95 r_2848 1 + v95 r_2963 1 + v95 r_2964 1 + v95 r_2965 1 + v96 r_11 1 + v96 r_193 1 + v96 r_325 -1 + v96 r_1369 1 + v96 r_1547 1 + v96 r_2077 1 + v96 r_2078 1 + v96 r_2079 1 + v96 r_2215 1 + v96 r_2216 1 + v96 r_2217 1 + v97 r_11 1 + v97 r_211 1 + v97 r_342 -1 + v97 r_1370 1 + v97 r_1607 1 + v97 r_2077 1 + v97 r_2078 1 + v97 r_2079 1 + v97 r_2215 1 + v97 r_2216 1 + v97 r_2217 1 + v98 r_11 1 + v98 r_229 1 + v98 r_359 -1 + v98 r_1371 1 + v98 r_1668 1 + v98 r_2077 1 + v98 r_2078 1 + v98 r_2079 1 + v98 r_2215 1 + v98 r_2216 1 + v98 r_2217 1 + v99 r_11 1 + v99 r_246 1 + v99 r_375 -1 + v99 r_1372 1 + v99 r_1735 1 + v99 r_2077 1 + v99 r_2078 1 + v99 r_2079 1 + v99 r_2215 1 + v99 r_2216 1 + v99 r_2217 1 + v99 r_2847 1 + v99 r_2848 1 + v99 r_2963 1 + v99 r_2964 1 + v99 r_2965 1 + v1000 r_112 1 + v1000 r_178 1 + v1000 r_1029 -1 + v1000 r_1415 1 + v1000 r_1529 1 + v1000 r_2174 1 + v1000 r_2175 1 + v1000 r_2176 1 + v1000 r_2916 1 + v1000 r_2917 1 + v1000 r_3028 1 + v1000 r_3029 1 + v1000 r_3030 1 + v1001 r_112 1 + v1001 r_194 1 + v1001 r_1044 -1 + v1001 r_1416 1 + v1001 r_1585 1 + v1001 r_2174 1 + v1001 r_2175 1 + v1001 r_2176 1 + v1002 r_112 1 + v1002 r_212 1 + v1002 r_1061 -1 + v1002 r_1417 1 + v1002 r_1645 1 + v1002 r_2174 1 + v1002 r_2175 1 + v1002 r_2176 1 + v1003 r_112 1 + v1003 r_230 1 + v1003 r_1079 -1 + v1003 r_1418 1 + v1003 r_1711 1 + v1003 r_2174 1 + v1003 r_2175 1 + v1003 r_2176 1 + v1004 r_112 1 + v1004 r_247 1 + v1004 r_1096 -1 + v1004 r_1419 1 + v1004 r_1768 1 + v1004 r_2174 1 + v1004 r_2175 1 + v1004 r_2176 1 + v1004 r_2916 1 + v1004 r_2917 1 + v1004 r_3028 1 + v1004 r_3029 1 + v1004 r_3030 1 + v1005 r_112 1 + v1005 r_392 1 + v1005 r_490 1 + v1005 r_608 1 + v1005 r_733 1 + v1005 r_861 1 + v1005 r_969 1 + v1005 r_1242 1 + v1005 r_1349 1 + v1005 r_2055 1 + v1005 r_2371 1 + v1005 r_2372 1 + v1005 r_2373 1 + v1005 r_2551 -1 + v1005 r_2552 -1 + v1005 r_2553 -1 + v1005 r_2554 -1 + v1005 r_2722 1 + v1005 r_2723 1 + v1005 r_2724 1 + v1005 r_2725 1 + v1005 r_2726 1 + v1006 r_112 1 + v1006 r_282 1 + v1006 r_1113 -1 + v1006 r_1420 1 + v1006 r_1909 1 + v1006 r_2174 1 + v1006 r_2175 1 + v1006 r_2176 1 + v1007 r_112 1 + v1007 r_297 1 + v1007 r_1127 -1 + v1007 r_1421 1 + v1007 r_1963 1 + v1007 r_2174 1 + v1007 r_2175 1 + v1007 r_2176 1 + v1007 r_3028 1 + v1007 r_3029 1 + v1007 r_3030 1 + v1008 r_112 1 + v1008 r_2010 1 + v1008 r_2027 1 + v1008 r_2038 1 + v1008 r_2722 1 + v1008 r_2723 1 + v1008 r_2724 1 + v1008 r_2725 1 + v1008 r_2726 1 + v1009 r_113 1 + v1009 r_163 1 + v1009 r_1014 -1 + v1009 r_1414 1 + v1009 r_1478 1 + v1009 r_2175 1 + v1009 r_2176 1 + v1009 r_2177 1 + v1009 r_2258 1 + v1009 r_2259 1 + v1009 r_2260 1 + v1010 r_113 1 + v1010 r_179 1 + v1010 r_1030 -1 + v1010 r_1415 1 + v1010 r_1530 1 + v1010 r_2175 1 + v1010 r_2176 1 + v1010 r_2177 1 + v1010 r_2258 1 + v1010 r_2259 1 + v1010 r_2260 1 + v1010 r_2917 1 + v1010 r_2918 1 + v1010 r_3029 1 + v1010 r_3030 1 + v1010 r_3031 1 + v1011 r_113 1 + v1011 r_195 1 + v1011 r_1045 -1 + v1011 r_1416 1 + v1011 r_1586 1 + v1011 r_2175 1 + v1011 r_2176 1 + v1011 r_2177 1 + v1011 r_2258 1 + v1011 r_2259 1 + v1011 r_2260 1 + v1012 r_113 1 + v1012 r_213 1 + v1012 r_1062 -1 + v1012 r_1417 1 + v1012 r_1646 1 + v1012 r_2175 1 + v1012 r_2176 1 + v1012 r_2177 1 + v1012 r_2258 1 + v1012 r_2259 1 + v1012 r_2260 1 + v1013 r_113 1 + v1013 r_231 1 + v1013 r_1080 -1 + v1013 r_1418 1 + v1013 r_1712 1 + v1013 r_2175 1 + v1013 r_2176 1 + v1013 r_2177 1 + v1013 r_2258 1 + v1013 r_2259 1 + v1013 r_2260 1 + v1014 r_113 1 + v1014 r_248 1 + v1014 r_1097 -1 + v1014 r_1419 1 + v1014 r_1769 1 + v1014 r_2175 1 + v1014 r_2176 1 + v1014 r_2177 1 + v1014 r_2258 1 + v1014 r_2259 1 + v1014 r_2260 1 + v1014 r_2917 1 + v1014 r_2918 1 + v1014 r_3029 1 + v1014 r_3030 1 + v1014 r_3031 1 + v1015 r_113 1 + v1015 r_393 1 + v1015 r_491 1 + v1015 r_609 1 + v1015 r_734 1 + v1015 r_862 1 + v1015 r_970 1 + v1015 r_1243 1 + v1015 r_1350 1 + v1015 r_2056 1 + v1015 r_2372 1 + v1015 r_2373 1 + v1015 r_2374 1 + v1015 r_2446 1 + v1015 r_2447 1 + v1015 r_2448 1 + v1015 r_2552 -1 + v1015 r_2553 -1 + v1015 r_2554 -1 + v1015 r_2555 -1 + v1015 r_2620 -1 + v1015 r_2621 -1 + v1015 r_2622 -1 + v1015 r_2723 1 + v1015 r_2724 1 + v1015 r_2725 1 + v1015 r_2726 1 + v1015 r_2727 1 + v1015 r_2793 1 + v1015 r_2794 1 + v1015 r_2795 1 + v1015 r_2814 1 + v1016 r_113 1 + v1016 r_283 1 + v1016 r_1114 -1 + v1016 r_1420 1 + v1016 r_1910 1 + v1016 r_2175 1 + v1016 r_2176 1 + v1016 r_2177 1 + v1016 r_2258 1 + v1016 r_2259 1 + v1016 r_2260 1 + v1017 r_113 1 + v1017 r_298 1 + v1017 r_1128 -1 + v1017 r_1421 1 + v1017 r_1964 1 + v1017 r_2175 1 + v1017 r_2176 1 + v1017 r_2177 1 + v1017 r_2258 1 + v1017 r_2259 1 + v1017 r_2260 1 + v1017 r_3029 1 + v1017 r_3030 1 + v1017 r_3031 1 + v1018 r_113 1 + v1018 r_2011 1 + v1018 r_2027 1 + v1018 r_2039 1 + v1018 r_2723 1 + v1018 r_2724 1 + v1018 r_2725 1 + v1018 r_2726 1 + v1018 r_2727 1 + v1018 r_2793 1 + v1018 r_2794 1 + v1018 r_2795 1 + v1018 r_2822 1 + v1019 r_114 1 + v1019 r_164 1 + v1019 r_1015 -1 + v1019 r_1414 1 + v1019 r_1479 1 + v1019 r_2176 1 + v1019 r_2177 1 + v1019 r_2178 1 + v1020 r_114 1 + v1020 r_180 1 + v1020 r_1031 -1 + v1020 r_1415 1 + v1020 r_1531 1 + v1020 r_2176 1 + v1020 r_2177 1 + v1020 r_2178 1 + v1020 r_2918 1 + v1020 r_2919 1 + v1020 r_3030 1 + v1020 r_3031 1 + v1020 r_3032 1 + v1021 r_114 1 + v1021 r_196 1 + v1021 r_1046 -1 + v1021 r_1416 1 + v1021 r_1587 1 + v1021 r_2176 1 + v1021 r_2177 1 + v1021 r_2178 1 + v1022 r_114 1 + v1022 r_214 1 + v1022 r_1063 -1 + v1022 r_1417 1 + v1022 r_1647 1 + v1022 r_2176 1 + v1022 r_2177 1 + v1022 r_2178 1 + v1023 r_114 1 + v1023 r_232 1 + v1023 r_1081 -1 + v1023 r_1418 1 + v1023 r_1713 1 + v1023 r_2176 1 + v1023 r_2177 1 + v1023 r_2178 1 + v1024 r_114 1 + v1024 r_249 1 + v1024 r_1098 -1 + v1024 r_1419 1 + v1024 r_1770 1 + v1024 r_2176 1 + v1024 r_2177 1 + v1024 r_2178 1 + v1024 r_2918 1 + v1024 r_2919 1 + v1024 r_3030 1 + v1024 r_3031 1 + v1024 r_3032 1 + v1025 r_114 1 + v1025 r_394 1 + v1025 r_492 1 + v1025 r_610 1 + v1025 r_735 1 + v1025 r_863 1 + v1025 r_971 1 + v1025 r_1244 1 + v1025 r_1351 1 + v1025 r_2057 1 + v1025 r_2373 1 + v1025 r_2374 1 + v1025 r_2375 1 + v1025 r_2553 -1 + v1025 r_2554 -1 + v1025 r_2555 -1 + v1025 r_2556 -1 + v1025 r_2724 1 + v1025 r_2725 1 + v1025 r_2726 1 + v1025 r_2727 1 + v1026 r_114 1 + v1026 r_284 1 + v1026 r_1115 -1 + v1026 r_1420 1 + v1026 r_1911 1 + v1026 r_2176 1 + v1026 r_2177 1 + v1026 r_2178 1 + v1027 r_114 1 + v1027 r_299 1 + v1027 r_1129 -1 + v1027 r_1421 1 + v1027 r_1965 1 + v1027 r_2176 1 + v1027 r_2177 1 + v1027 r_2178 1 + v1027 r_3030 1 + v1027 r_3031 1 + v1027 r_3032 1 + v1028 r_114 1 + v1028 r_2012 1 + v1028 r_2027 1 + v1028 r_2040 1 + v1028 r_2724 1 + v1028 r_2725 1 + v1028 r_2726 1 + v1028 r_2727 1 + v1029 r_115 1 + v1029 r_165 1 + v1029 r_1016 -1 + v1029 r_1414 1 + v1029 r_1480 1 + v1029 r_2177 1 + v1029 r_2178 1 + v1029 r_2179 1 + v1029 r_2259 1 + v1029 r_2260 1 + v1030 r_115 1 + v1030 r_197 1 + v1030 r_1047 -1 + v1030 r_1416 1 + v1030 r_1588 1 + v1030 r_2177 1 + v1030 r_2178 1 + v1030 r_2179 1 + v1030 r_2259 1 + v1030 r_2260 1 + v1031 r_115 1 + v1031 r_215 1 + v1031 r_1064 -1 + v1031 r_1417 1 + v1031 r_1648 1 + v1031 r_2177 1 + v1031 r_2178 1 + v1031 r_2179 1 + v1031 r_2259 1 + v1031 r_2260 1 + v1032 r_115 1 + v1032 r_233 1 + v1032 r_1082 -1 + v1032 r_1418 1 + v1032 r_1714 1 + v1032 r_2177 1 + v1032 r_2178 1 + v1032 r_2179 1 + v1032 r_2259 1 + v1032 r_2260 1 + v1033 r_115 1 + v1033 r_250 1 + v1033 r_1099 -1 + v1033 r_1419 1 + v1033 r_1771 1 + v1033 r_2177 1 + v1033 r_2178 1 + v1033 r_2179 1 + v1033 r_2259 1 + v1033 r_2260 1 + v1033 r_2919 1 + v1033 r_2920 1 + v1033 r_3031 1 + v1033 r_3032 1 + v1033 r_3033 1 + v1034 r_115 1 + v1034 r_395 1 + v1034 r_611 1 + v1034 r_736 1 + v1034 r_864 1 + v1034 r_972 1 + v1034 r_1245 1 + v1034 r_1352 1 + v1034 r_2058 1 + v1034 r_2374 1 + v1034 r_2375 1 + v1034 r_2376 1 + v1034 r_2447 1 + v1034 r_2448 1 + v1034 r_2554 -1 + v1034 r_2555 -1 + v1034 r_2556 -1 + v1034 r_2621 -1 + v1034 r_2622 -1 + v1034 r_2725 1 + v1034 r_2726 1 + v1034 r_2727 1 + v1034 r_2794 1 + v1034 r_2795 1 + v1034 r_2814 1 + v1035 r_115 1 + v1035 r_285 1 + v1035 r_1116 -1 + v1035 r_1420 1 + v1035 r_1912 1 + v1035 r_2177 1 + v1035 r_2178 1 + v1035 r_2179 1 + v1035 r_2259 1 + v1035 r_2260 1 + v1036 r_115 1 + v1036 r_300 1 + v1036 r_1130 -1 + v1036 r_1421 1 + v1036 r_1966 1 + v1036 r_2177 1 + v1036 r_2178 1 + v1036 r_2179 1 + v1036 r_2259 1 + v1036 r_2260 1 + v1036 r_3031 1 + v1036 r_3032 1 + v1036 r_3033 1 + v1037 r_116 1 + v1037 r_166 1 + v1037 r_1017 -1 + v1037 r_1414 1 + v1037 r_1481 1 + v1037 r_2178 1 + v1037 r_2179 1 + v1038 r_116 1 + v1038 r_181 1 + v1038 r_1032 -1 + v1038 r_1415 1 + v1038 r_1532 1 + v1038 r_2178 1 + v1038 r_2179 1 + v1038 r_2920 1 + v1038 r_2921 1 + v1038 r_3032 1 + v1038 r_3033 1 + v1039 r_116 1 + v1039 r_198 1 + v1039 r_1048 -1 + v1039 r_1416 1 + v1039 r_1589 1 + v1039 r_2178 1 + v1039 r_2179 1 + v1040 r_116 1 + v1040 r_216 1 + v1040 r_1065 -1 + v1040 r_1417 1 + v1040 r_1649 1 + v1040 r_2178 1 + v1040 r_2179 1 + v1041 r_116 1 + v1041 r_234 1 + v1041 r_1083 -1 + v1041 r_1418 1 + v1041 r_1715 1 + v1041 r_2178 1 + v1041 r_2179 1 + v1042 r_116 1 + v1042 r_251 1 + v1042 r_1100 -1 + v1042 r_1419 1 + v1042 r_1772 1 + v1042 r_2178 1 + v1042 r_2179 1 + v1042 r_2920 1 + v1042 r_2921 1 + v1042 r_3032 1 + v1042 r_3033 1 + v1043 r_116 1 + v1043 r_396 1 + v1043 r_493 1 + v1043 r_612 1 + v1043 r_737 1 + v1043 r_865 1 + v1043 r_973 1 + v1043 r_1246 1 + v1043 r_1353 1 + v1043 r_2059 1 + v1043 r_2066 1 + v1043 r_2375 1 + v1043 r_2376 1 + v1043 r_2555 -1 + v1043 r_2556 -1 + v1043 r_2726 1 + v1043 r_2727 1 + v1044 r_116 1 + v1044 r_286 1 + v1044 r_1117 -1 + v1044 r_1420 1 + v1044 r_1913 1 + v1044 r_2178 1 + v1044 r_2179 1 + v1045 r_116 1 + v1045 r_2013 1 + v1045 r_2027 1 + v1045 r_2041 1 + v1045 r_2066 1 + v1045 r_2726 1 + v1045 r_2727 1 + v1046 r_117 1 + v1046 r_167 1 + v1046 r_1018 -1 + v1046 r_1414 1 + v1046 r_1482 1 + v1046 r_2179 1 + v1046 r_2260 1 + v1047 r_117 1 + v1047 r_199 1 + v1047 r_1049 -1 + v1047 r_1416 1 + v1047 r_1590 1 + v1047 r_2179 1 + v1047 r_2260 1 + v1048 r_117 1 + v1048 r_217 1 + v1048 r_1066 -1 + v1048 r_1417 1 + v1048 r_1650 1 + v1048 r_2179 1 + v1048 r_2260 1 + v1049 r_117 1 + v1049 r_235 1 + v1049 r_1084 -1 + v1049 r_1418 1 + v1049 r_1716 1 + v1049 r_2179 1 + v1049 r_2260 1 + v1050 r_117 1 + v1050 r_397 1 + v1050 r_613 1 + v1050 r_738 1 + v1050 r_866 1 + v1050 r_1247 1 + v1050 r_2060 1 + v1050 r_2066 1 + v1050 r_2376 1 + v1050 r_2448 1 + v1050 r_2556 -1 + v1050 r_2622 -1 + v1050 r_2727 1 + v1050 r_2795 1 + v1050 r_2814 1 + v1051 r_117 1 + v1051 r_287 1 + v1051 r_1118 -1 + v1051 r_1420 1 + v1051 r_1914 1 + v1051 r_2179 1 + v1051 r_2260 1 + v1052 r_117 1 + v1052 r_301 1 + v1052 r_1421 1 + v1052 r_1967 1 + v1052 r_2179 1 + v1052 r_2260 1 + v1052 r_2832 1 + v1052 r_3033 1 + v1053 r_118 1 + v1053 r_150 1 + v1053 r_1422 1 + v1053 r_1855 -1 + v1053 r_2180 1 + v1054 r_118 1 + v1054 r_168 1 + v1054 r_1148 -1 + v1054 r_1423 1 + v1054 r_1864 -1 + v1054 r_2180 1 + v1054 r_2922 1 + v1054 r_3034 1 + v1055 r_118 1 + v1055 r_182 1 + v1055 r_1424 1 + v1055 r_1871 -1 + v1055 r_2180 1 + v1056 r_118 1 + v1056 r_200 1 + v1056 r_1425 1 + v1056 r_1880 -1 + v1056 r_2180 1 + v1057 r_118 1 + v1057 r_218 1 + v1057 r_1196 -1 + v1057 r_1426 1 + v1057 r_1889 -1 + v1057 r_2180 1 + v1058 r_118 1 + v1058 r_236 1 + v1058 r_1214 -1 + v1058 r_1427 1 + v1058 r_1898 -1 + v1058 r_2180 1 + v1058 r_2922 1 + v1058 r_3034 1 + v1059 r_118 1 + v1059 r_252 1 + v1059 r_1230 -1 + v1059 r_1428 1 + v1059 r_1906 -1 + v1059 r_2180 1 + v1060 r_118 1 + v1060 r_494 1 + v1060 r_867 1 + v1060 r_974 1 + v1060 r_1101 1 + v1060 r_2043 1 + v1060 r_2377 1 + v1060 r_2557 -1 + v1060 r_2728 1 + v1061 r_119 1 + v1061 r_151 1 + v1061 r_1131 -1 + v1061 r_1422 1 + v1061 r_1856 -1 + v1061 r_2180 1 + v1061 r_2181 1 + v1061 r_2261 1 + v1062 r_119 1 + v1062 r_169 1 + v1062 r_1149 -1 + v1062 r_1423 1 + v1062 r_1865 -1 + v1062 r_2180 1 + v1062 r_2181 1 + v1062 r_2261 1 + v1062 r_2922 1 + v1062 r_2923 1 + v1062 r_3034 1 + v1062 r_3035 1 + v1063 r_119 1 + v1063 r_183 1 + v1063 r_1162 -1 + v1063 r_1424 1 + v1063 r_1872 -1 + v1063 r_2180 1 + v1063 r_2181 1 + v1063 r_2261 1 + v1064 r_119 1 + v1064 r_201 1 + v1064 r_1179 -1 + v1064 r_1425 1 + v1064 r_1881 -1 + v1064 r_2180 1 + v1064 r_2181 1 + v1064 r_2261 1 + v1065 r_119 1 + v1065 r_219 1 + v1065 r_1197 -1 + v1065 r_1426 1 + v1065 r_1890 -1 + v1065 r_2180 1 + v1065 r_2181 1 + v1065 r_2261 1 + v1066 r_119 1 + v1066 r_237 1 + v1066 r_1215 -1 + v1066 r_1427 1 + v1066 r_1899 -1 + v1066 r_2180 1 + v1066 r_2181 1 + v1066 r_2261 1 + v1066 r_2922 1 + v1066 r_2923 1 + v1066 r_3034 1 + v1066 r_3035 1 + v1067 r_119 1 + v1067 r_253 1 + v1067 r_1231 -1 + v1067 r_1428 1 + v1067 r_1907 -1 + v1067 r_2180 1 + v1067 r_2181 1 + v1067 r_2261 1 + v1068 r_119 1 + v1068 r_398 1 + v1068 r_495 1 + v1068 r_614 1 + v1068 r_739 1 + v1068 r_868 1 + v1068 r_975 1 + v1068 r_1102 1 + v1068 r_1354 1 + v1068 r_2044 1 + v1068 r_2377 1 + v1068 r_2378 1 + v1068 r_2449 1 + v1068 r_2557 -1 + v1068 r_2558 -1 + v1068 r_2623 -1 + v1068 r_2728 1 + v1068 r_2729 1 + v1068 r_2796 1 + v1068 r_2815 1 + v1068 r_2831 1 + v1069 r_119 1 + v1069 r_288 1 + v1069 r_1248 -1 + v1069 r_1429 1 + v1069 r_1915 -1 + v1069 r_2180 1 + v1069 r_2181 1 + v1069 r_2261 1 + v1069 r_3034 1 + v1069 r_3035 1 + v1070 r_119 1 + v1070 r_2014 -1 + v1070 r_2028 1 + v1070 r_2029 1 + v1070 r_2728 1 + v1070 r_2729 1 + v1070 r_2796 1 + v1070 r_2823 1 + v1070 r_2831 1 + v1071 r_120 1 + v1071 r_152 1 + v1071 r_1132 -1 + v1071 r_1422 1 + v1071 r_1857 -1 + v1071 r_2180 1 + v1071 r_2181 1 + v1071 r_2182 1 + v1072 r_120 1 + v1072 r_170 1 + v1072 r_1150 -1 + v1072 r_1423 1 + v1072 r_1866 -1 + v1072 r_2180 1 + v1072 r_2181 1 + v1072 r_2182 1 + v1072 r_2923 1 + v1072 r_2924 1 + v1072 r_3034 1 + v1072 r_3035 1 + v1072 r_3036 1 + v1073 r_120 1 + v1073 r_184 1 + v1073 r_1163 -1 + v1073 r_1424 1 + v1073 r_1873 -1 + v1073 r_2180 1 + v1073 r_2181 1 + v1073 r_2182 1 + v1074 r_120 1 + v1074 r_202 1 + v1074 r_1180 -1 + v1074 r_1425 1 + v1074 r_1882 -1 + v1074 r_2180 1 + v1074 r_2181 1 + v1074 r_2182 1 + v1075 r_120 1 + v1075 r_220 1 + v1075 r_1198 -1 + v1075 r_1426 1 + v1075 r_1891 -1 + v1075 r_2180 1 + v1075 r_2181 1 + v1075 r_2182 1 + v1076 r_120 1 + v1076 r_238 1 + v1076 r_1216 -1 + v1076 r_1427 1 + v1076 r_1900 -1 + v1076 r_2180 1 + v1076 r_2181 1 + v1076 r_2182 1 + v1076 r_2923 1 + v1076 r_2924 1 + v1076 r_3034 1 + v1076 r_3035 1 + v1076 r_3036 1 + v1077 r_120 1 + v1077 r_254 1 + v1077 r_1232 -1 + v1077 r_1428 1 + v1077 r_1908 -1 + v1077 r_2180 1 + v1077 r_2181 1 + v1077 r_2182 1 + v1078 r_120 1 + v1078 r_399 1 + v1078 r_496 1 + v1078 r_615 1 + v1078 r_740 1 + v1078 r_869 1 + v1078 r_976 1 + v1078 r_1103 1 + v1078 r_1355 1 + v1078 r_2045 1 + v1078 r_2377 1 + v1078 r_2378 1 + v1078 r_2379 1 + v1078 r_2557 -1 + v1078 r_2558 -1 + v1078 r_2559 -1 + v1078 r_2728 1 + v1078 r_2729 1 + v1078 r_2730 1 + v1079 r_120 1 + v1079 r_289 1 + v1079 r_1249 -1 + v1079 r_1429 1 + v1079 r_1916 -1 + v1079 r_2180 1 + v1079 r_2181 1 + v1079 r_2182 1 + v1079 r_3034 1 + v1079 r_3035 1 + v1079 r_3036 1 + v1080 r_120 1 + v1080 r_2015 -1 + v1080 r_2028 1 + v1080 r_2030 1 + v1080 r_2728 1 + v1080 r_2729 1 + v1080 r_2730 1 + v1081 r_121 1 + v1081 r_153 1 + v1081 r_1133 -1 + v1081 r_1422 1 + v1081 r_1858 -1 + v1081 r_2181 1 + v1081 r_2182 1 + v1081 r_2183 1 + v1081 r_2261 1 + v1081 r_2262 1 + v1082 r_121 1 + v1082 r_171 1 + v1082 r_1151 -1 + v1082 r_1423 1 + v1082 r_1867 -1 + v1082 r_2181 1 + v1082 r_2182 1 + v1082 r_2183 1 + v1082 r_2261 1 + v1082 r_2262 1 + v1082 r_2924 1 + v1082 r_2925 1 + v1082 r_3035 1 + v1082 r_3036 1 + v1082 r_3037 1 + v1083 r_121 1 + v1083 r_185 1 + v1083 r_1164 -1 + v1083 r_1424 1 + v1083 r_1874 -1 + v1083 r_2181 1 + v1083 r_2182 1 + v1083 r_2183 1 + v1083 r_2261 1 + v1083 r_2262 1 + v1084 r_121 1 + v1084 r_203 1 + v1084 r_1181 -1 + v1084 r_1425 1 + v1084 r_1883 -1 + v1084 r_2181 1 + v1084 r_2182 1 + v1084 r_2183 1 + v1084 r_2261 1 + v1084 r_2262 1 + v1085 r_121 1 + v1085 r_221 1 + v1085 r_1199 -1 + v1085 r_1426 1 + v1085 r_1892 -1 + v1085 r_2181 1 + v1085 r_2182 1 + v1085 r_2183 1 + v1085 r_2261 1 + v1085 r_2262 1 + v1086 r_121 1 + v1086 r_239 1 + v1086 r_1217 -1 + v1086 r_1427 1 + v1086 r_1901 -1 + v1086 r_2181 1 + v1086 r_2182 1 + v1086 r_2183 1 + v1086 r_2261 1 + v1086 r_2262 1 + v1086 r_2924 1 + v1086 r_2925 1 + v1086 r_3035 1 + v1086 r_3036 1 + v1086 r_3037 1 + v1087 r_121 1 + v1087 r_255 1 + v1087 r_1233 -1 + v1087 r_1428 1 + v1087 r_1909 -1 + v1087 r_2181 1 + v1087 r_2182 1 + v1087 r_2183 1 + v1087 r_2261 1 + v1087 r_2262 1 + v1088 r_121 1 + v1088 r_400 1 + v1088 r_497 1 + v1088 r_616 1 + v1088 r_741 1 + v1088 r_870 1 + v1088 r_977 1 + v1088 r_1104 1 + v1088 r_1356 1 + v1088 r_2046 1 + v1088 r_2378 1 + v1088 r_2379 1 + v1088 r_2380 1 + v1088 r_2449 1 + v1088 r_2450 1 + v1088 r_2557 -1 + v1088 r_2558 -1 + v1088 r_2559 -1 + v1088 r_2560 -1 + v1088 r_2623 -1 + v1088 r_2624 -1 + v1088 r_2728 1 + v1088 r_2729 1 + v1088 r_2730 1 + v1088 r_2731 1 + v1088 r_2796 1 + v1088 r_2797 1 + v1088 r_2815 1 + v1088 r_2831 1 + v1089 r_121 1 + v1089 r_290 1 + v1089 r_1250 -1 + v1089 r_1429 1 + v1089 r_1917 -1 + v1089 r_2181 1 + v1089 r_2182 1 + v1089 r_2183 1 + v1089 r_2261 1 + v1089 r_2262 1 + v1089 r_3035 1 + v1089 r_3036 1 + v1089 r_3037 1 + v1090 r_121 1 + v1090 r_2016 -1 + v1090 r_2028 1 + v1090 r_2031 1 + v1090 r_2728 1 + v1090 r_2729 1 + v1090 r_2730 1 + v1090 r_2731 1 + v1090 r_2796 1 + v1090 r_2797 1 + v1090 r_2823 1 + v1090 r_2831 1 + v1091 r_122 1 + v1091 r_154 1 + v1091 r_1134 -1 + v1091 r_1422 1 + v1091 r_1859 -1 + v1091 r_2182 1 + v1091 r_2183 1 + v1091 r_2184 1 + v1092 r_122 1 + v1092 r_172 1 + v1092 r_1152 -1 + v1092 r_1423 1 + v1092 r_1868 -1 + v1092 r_2182 1 + v1092 r_2183 1 + v1092 r_2184 1 + v1092 r_2925 1 + v1092 r_2926 1 + v1092 r_3036 1 + v1092 r_3037 1 + v1092 r_3038 1 + v1093 r_122 1 + v1093 r_186 1 + v1093 r_1165 -1 + v1093 r_1424 1 + v1093 r_1875 -1 + v1093 r_2182 1 + v1093 r_2183 1 + v1093 r_2184 1 + v1094 r_122 1 + v1094 r_204 1 + v1094 r_1182 -1 + v1094 r_1425 1 + v1094 r_1884 -1 + v1094 r_2182 1 + v1094 r_2183 1 + v1094 r_2184 1 + v1095 r_122 1 + v1095 r_222 1 + v1095 r_1200 -1 + v1095 r_1426 1 + v1095 r_1893 -1 + v1095 r_2182 1 + v1095 r_2183 1 + v1095 r_2184 1 + v1096 r_122 1 + v1096 r_240 1 + v1096 r_1218 -1 + v1096 r_1427 1 + v1096 r_1902 -1 + v1096 r_2182 1 + v1096 r_2183 1 + v1096 r_2184 1 + v1096 r_2925 1 + v1096 r_2926 1 + v1096 r_3036 1 + v1096 r_3037 1 + v1096 r_3038 1 + v1097 r_122 1 + v1097 r_256 1 + v1097 r_1234 -1 + v1097 r_1428 1 + v1097 r_1910 -1 + v1097 r_2182 1 + v1097 r_2183 1 + v1097 r_2184 1 + v1098 r_122 1 + v1098 r_401 1 + v1098 r_498 1 + v1098 r_617 1 + v1098 r_742 1 + v1098 r_871 1 + v1098 r_978 1 + v1098 r_1105 1 + v1098 r_1357 1 + v1098 r_2047 1 + v1098 r_2379 1 + v1098 r_2380 1 + v1098 r_2381 1 + v1098 r_2558 -1 + v1098 r_2559 -1 + v1098 r_2560 -1 + v1098 r_2561 -1 + v1098 r_2728 1 + v1098 r_2729 1 + v1098 r_2730 1 + v1098 r_2731 1 + v1098 r_2732 1 + v1099 r_122 1 + v1099 r_291 1 + v1099 r_1251 -1 + v1099 r_1429 1 + v1099 r_1918 -1 + v1099 r_2182 1 + v1099 r_2183 1 + v1099 r_2184 1 + v1099 r_3036 1 + v1099 r_3037 1 + v1099 r_3038 1 + v1100 r_122 1 + v1100 r_2017 -1 + v1100 r_2028 1 + v1100 r_2032 1 + v1100 r_2728 1 + v1100 r_2729 1 + v1100 r_2730 1 + v1100 r_2731 1 + v1100 r_2732 1 + v1101 r_123 1 + v1101 r_155 1 + v1101 r_1135 -1 + v1101 r_1422 1 + v1101 r_1860 -1 + v1101 r_2183 1 + v1101 r_2184 1 + v1101 r_2185 1 + v1101 r_2261 1 + v1101 r_2262 1 + v1101 r_2263 1 + v1102 r_123 1 + v1102 r_173 1 + v1102 r_1153 -1 + v1102 r_1423 1 + v1102 r_1869 -1 + v1102 r_2183 1 + v1102 r_2184 1 + v1102 r_2185 1 + v1102 r_2261 1 + v1102 r_2262 1 + v1102 r_2263 1 + v1102 r_2926 1 + v1102 r_2927 1 + v1102 r_3037 1 + v1102 r_3038 1 + v1102 r_3039 1 + v1103 r_123 1 + v1103 r_187 1 + v1103 r_1166 -1 + v1103 r_1424 1 + v1103 r_1876 -1 + v1103 r_2183 1 + v1103 r_2184 1 + v1103 r_2185 1 + v1103 r_2261 1 + v1103 r_2262 1 + v1103 r_2263 1 + v1104 r_123 1 + v1104 r_205 1 + v1104 r_1183 -1 + v1104 r_1425 1 + v1104 r_1885 -1 + v1104 r_2183 1 + v1104 r_2184 1 + v1104 r_2185 1 + v1104 r_2261 1 + v1104 r_2262 1 + v1104 r_2263 1 + v1105 r_123 1 + v1105 r_223 1 + v1105 r_1201 -1 + v1105 r_1426 1 + v1105 r_1894 -1 + v1105 r_2183 1 + v1105 r_2184 1 + v1105 r_2185 1 + v1105 r_2261 1 + v1105 r_2262 1 + v1105 r_2263 1 + v1106 r_123 1 + v1106 r_241 1 + v1106 r_1219 -1 + v1106 r_1427 1 + v1106 r_1903 -1 + v1106 r_2183 1 + v1106 r_2184 1 + v1106 r_2185 1 + v1106 r_2261 1 + v1106 r_2262 1 + v1106 r_2263 1 + v1106 r_2926 1 + v1106 r_2927 1 + v1106 r_3037 1 + v1106 r_3038 1 + v1106 r_3039 1 + v1107 r_123 1 + v1107 r_257 1 + v1107 r_1235 -1 + v1107 r_1428 1 + v1107 r_1911 -1 + v1107 r_2183 1 + v1107 r_2184 1 + v1107 r_2185 1 + v1107 r_2261 1 + v1107 r_2262 1 + v1107 r_2263 1 + v1108 r_123 1 + v1108 r_402 1 + v1108 r_499 1 + v1108 r_618 1 + v1108 r_743 1 + v1108 r_872 1 + v1108 r_979 1 + v1108 r_1106 1 + v1108 r_1358 1 + v1108 r_2048 1 + v1108 r_2380 1 + v1108 r_2381 1 + v1108 r_2382 1 + v1108 r_2449 1 + v1108 r_2450 1 + v1108 r_2451 1 + v1108 r_2559 -1 + v1108 r_2560 -1 + v1108 r_2561 -1 + v1108 r_2562 -1 + v1108 r_2623 -1 + v1108 r_2624 -1 + v1108 r_2625 -1 + v1108 r_2729 1 + v1108 r_2730 1 + v1108 r_2731 1 + v1108 r_2732 1 + v1108 r_2733 1 + v1108 r_2796 1 + v1108 r_2797 1 + v1108 r_2798 1 + v1108 r_2815 1 + v1108 r_2831 1 + v1109 r_123 1 + v1109 r_292 1 + v1109 r_1252 -1 + v1109 r_1429 1 + v1109 r_1919 -1 + v1109 r_2183 1 + v1109 r_2184 1 + v1109 r_2185 1 + v1109 r_2261 1 + v1109 r_2262 1 + v1109 r_2263 1 + v1109 r_3037 1 + v1109 r_3038 1 + v1109 r_3039 1 + v1110 r_123 1 + v1110 r_2018 -1 + v1110 r_2028 1 + v1110 r_2033 1 + v1110 r_2729 1 + v1110 r_2730 1 + v1110 r_2731 1 + v1110 r_2732 1 + v1110 r_2733 1 + v1110 r_2796 1 + v1110 r_2797 1 + v1110 r_2798 1 + v1110 r_2823 1 + v1110 r_2831 1 + v1111 r_124 1 + v1111 r_156 1 + v1111 r_1136 -1 + v1111 r_1422 1 + v1111 r_1861 -1 + v1111 r_2184 1 + v1111 r_2185 1 + v1111 r_2186 1 + v1112 r_124 1 + v1112 r_188 1 + v1112 r_1167 -1 + v1112 r_1424 1 + v1112 r_1877 -1 + v1112 r_2184 1 + v1112 r_2185 1 + v1112 r_2186 1 + v1113 r_124 1 + v1113 r_206 1 + v1113 r_1184 -1 + v1113 r_1425 1 + v1113 r_1886 -1 + v1113 r_2184 1 + v1113 r_2185 1 + v1113 r_2186 1 + v1114 r_124 1 + v1114 r_224 1 + v1114 r_1202 -1 + v1114 r_1426 1 + v1114 r_1895 -1 + v1114 r_2184 1 + v1114 r_2185 1 + v1114 r_2186 1 + v1115 r_124 1 + v1115 r_242 1 + v1115 r_1220 -1 + v1115 r_1427 1 + v1115 r_1904 -1 + v1115 r_2184 1 + v1115 r_2185 1 + v1115 r_2186 1 + v1115 r_2927 1 + v1115 r_2928 1 + v1115 r_3038 1 + v1115 r_3039 1 + v1115 r_3040 1 + v1116 r_124 1 + v1116 r_258 1 + v1116 r_1236 -1 + v1116 r_1428 1 + v1116 r_1912 -1 + v1116 r_2184 1 + v1116 r_2185 1 + v1116 r_2186 1 + v1117 r_124 1 + v1117 r_403 1 + v1117 r_619 1 + v1117 r_744 1 + v1117 r_873 1 + v1117 r_980 1 + v1117 r_1107 1 + v1117 r_1359 1 + v1117 r_2049 1 + v1117 r_2381 1 + v1117 r_2382 1 + v1117 r_2383 1 + v1117 r_2560 -1 + v1117 r_2561 -1 + v1117 r_2562 -1 + v1117 r_2563 -1 + v1117 r_2730 1 + v1117 r_2731 1 + v1117 r_2732 1 + v1117 r_2733 1 + v1117 r_2734 1 + v1118 r_124 1 + v1118 r_293 1 + v1118 r_1253 -1 + v1118 r_1429 1 + v1118 r_1920 -1 + v1118 r_2184 1 + v1118 r_2185 1 + v1118 r_2186 1 + v1118 r_3038 1 + v1118 r_3039 1 + v1118 r_3040 1 + v1119 r_125 1 + v1119 r_157 1 + v1119 r_1137 -1 + v1119 r_1422 1 + v1119 r_2185 1 + v1119 r_2186 1 + v1119 r_2187 1 + v1119 r_2262 1 + v1119 r_2263 1 + v1119 r_2264 1 + v1120 r_125 1 + v1120 r_174 1 + v1120 r_1154 -1 + v1120 r_1423 1 + v1120 r_1533 1 + v1120 r_2185 1 + v1120 r_2186 1 + v1120 r_2187 1 + v1120 r_2262 1 + v1120 r_2263 1 + v1120 r_2264 1 + v1120 r_2928 1 + v1120 r_2929 1 + v1120 r_3039 1 + v1120 r_3040 1 + v1120 r_3041 1 + v1121 r_125 1 + v1121 r_189 1 + v1121 r_1168 -1 + v1121 r_1424 1 + v1121 r_2185 1 + v1121 r_2186 1 + v1121 r_2187 1 + v1121 r_2262 1 + v1121 r_2263 1 + v1121 r_2264 1 + v1122 r_125 1 + v1122 r_207 1 + v1122 r_1185 -1 + v1122 r_1425 1 + v1122 r_2185 1 + v1122 r_2186 1 + v1122 r_2187 1 + v1122 r_2262 1 + v1122 r_2263 1 + v1122 r_2264 1 + v1123 r_125 1 + v1123 r_225 1 + v1123 r_1203 -1 + v1123 r_1426 1 + v1123 r_1717 1 + v1123 r_2185 1 + v1123 r_2186 1 + v1123 r_2187 1 + v1123 r_2262 1 + v1123 r_2263 1 + v1123 r_2264 1 + v1124 r_125 1 + v1124 r_243 1 + v1124 r_1221 -1 + v1124 r_1427 1 + v1124 r_1773 1 + v1124 r_2185 1 + v1124 r_2186 1 + v1124 r_2187 1 + v1124 r_2262 1 + v1124 r_2263 1 + v1124 r_2264 1 + v1124 r_2928 1 + v1124 r_2929 1 + v1124 r_3039 1 + v1124 r_3040 1 + v1124 r_3041 1 + v1125 r_125 1 + v1125 r_259 1 + v1125 r_1237 -1 + v1125 r_1428 1 + v1125 r_1839 1 + v1125 r_2185 1 + v1125 r_2186 1 + v1125 r_2187 1 + v1125 r_2262 1 + v1125 r_2263 1 + v1125 r_2264 1 + v1126 r_125 1 + v1126 r_404 1 + v1126 r_500 1 + v1126 r_620 1 + v1126 r_745 1 + v1126 r_874 1 + v1126 r_981 1 + v1126 r_1108 1 + v1126 r_2050 1 + v1126 r_2382 1 + v1126 r_2383 1 + v1126 r_2384 1 + v1126 r_2450 1 + v1126 r_2451 1 + v1126 r_2452 1 + v1126 r_2561 -1 + v1126 r_2562 -1 + v1126 r_2563 -1 + v1126 r_2564 -1 + v1126 r_2623 -1 + v1126 r_2624 -1 + v1126 r_2625 -1 + v1126 r_2626 -1 + v1126 r_2731 1 + v1126 r_2732 1 + v1126 r_2733 1 + v1126 r_2734 1 + v1126 r_2735 1 + v1126 r_2796 1 + v1126 r_2797 1 + v1126 r_2798 1 + v1126 r_2799 1 + v1126 r_2815 1 + v1126 r_2831 1 + v1127 r_126 1 + v1127 r_158 1 + v1127 r_1138 -1 + v1127 r_1422 1 + v1127 r_1483 1 + v1127 r_2186 1 + v1127 r_2187 1 + v1127 r_2188 1 + v1128 r_126 1 + v1128 r_175 1 + v1128 r_1155 -1 + v1128 r_1423 1 + v1128 r_1534 1 + v1128 r_2186 1 + v1128 r_2187 1 + v1128 r_2188 1 + v1128 r_2929 1 + v1128 r_2930 1 + v1128 r_3040 1 + v1128 r_3041 1 + v1128 r_3042 1 + v1129 r_126 1 + v1129 r_190 1 + v1129 r_1169 -1 + v1129 r_1424 1 + v1129 r_1591 1 + v1129 r_2186 1 + v1129 r_2187 1 + v1129 r_2188 1 + v1130 r_126 1 + v1130 r_208 1 + v1130 r_1186 -1 + v1130 r_1425 1 + v1130 r_1651 1 + v1130 r_2186 1 + v1130 r_2187 1 + v1130 r_2188 1 + v1131 r_126 1 + v1131 r_226 1 + v1131 r_1204 -1 + v1131 r_1426 1 + v1131 r_1718 1 + v1131 r_2186 1 + v1131 r_2187 1 + v1131 r_2188 1 + v1132 r_126 1 + v1132 r_244 1 + v1132 r_1222 -1 + v1132 r_1427 1 + v1132 r_1774 1 + v1132 r_2186 1 + v1132 r_2187 1 + v1132 r_2188 1 + v1132 r_2929 1 + v1132 r_2930 1 + v1132 r_3040 1 + v1132 r_3041 1 + v1132 r_3042 1 + v1133 r_126 1 + v1133 r_260 1 + v1133 r_1238 -1 + v1133 r_1428 1 + v1133 r_1840 1 + v1133 r_2186 1 + v1133 r_2187 1 + v1133 r_2188 1 + v1134 r_126 1 + v1134 r_405 1 + v1134 r_501 1 + v1134 r_621 1 + v1134 r_746 1 + v1134 r_875 1 + v1134 r_982 1 + v1134 r_1109 1 + v1134 r_1360 1 + v1134 r_2051 1 + v1134 r_2383 1 + v1134 r_2384 1 + v1134 r_2385 1 + v1134 r_2562 -1 + v1134 r_2563 -1 + v1134 r_2564 -1 + v1134 r_2565 -1 + v1134 r_2732 1 + v1134 r_2733 1 + v1134 r_2734 1 + v1134 r_2735 1 + v1134 r_2736 1 + v1135 r_126 1 + v1135 r_294 1 + v1135 r_1254 -1 + v1135 r_1429 1 + v1135 r_1968 1 + v1135 r_2186 1 + v1135 r_2187 1 + v1135 r_2188 1 + v1135 r_3040 1 + v1135 r_3041 1 + v1135 r_3042 1 + v1136 r_126 1 + v1136 r_2014 1 + v1136 r_2028 1 + v1136 r_2034 1 + v1136 r_2732 1 + v1136 r_2733 1 + v1136 r_2734 1 + v1136 r_2735 1 + v1136 r_2736 1 + v1137 r_127 1 + v1137 r_159 1 + v1137 r_1139 -1 + v1137 r_1422 1 + v1137 r_1862 -1 + v1137 r_2187 1 + v1137 r_2188 1 + v1137 r_2189 1 + v1137 r_2263 1 + v1137 r_2264 1 + v1137 r_2265 1 + v1138 r_127 1 + v1138 r_176 1 + v1138 r_1156 -1 + v1138 r_1423 1 + v1138 r_1870 -1 + v1138 r_2187 1 + v1138 r_2188 1 + v1138 r_2189 1 + v1138 r_2263 1 + v1138 r_2264 1 + v1138 r_2265 1 + v1138 r_2930 1 + v1138 r_2931 1 + v1138 r_3041 1 + v1138 r_3042 1 + v1138 r_3043 1 + v1139 r_127 1 + v1139 r_191 1 + v1139 r_1170 -1 + v1139 r_1424 1 + v1139 r_1878 -1 + v1139 r_2187 1 + v1139 r_2188 1 + v1139 r_2189 1 + v1139 r_2263 1 + v1139 r_2264 1 + v1139 r_2265 1 + v1140 r_127 1 + v1140 r_209 1 + v1140 r_1187 -1 + v1140 r_1425 1 + v1140 r_1887 -1 + v1140 r_2187 1 + v1140 r_2188 1 + v1140 r_2189 1 + v1140 r_2263 1 + v1140 r_2264 1 + v1140 r_2265 1 + v1141 r_127 1 + v1141 r_227 1 + v1141 r_1205 -1 + v1141 r_1426 1 + v1141 r_1896 -1 + v1141 r_2187 1 + v1141 r_2188 1 + v1141 r_2189 1 + v1141 r_2263 1 + v1141 r_2264 1 + v1141 r_2265 1 + v1142 r_127 1 + v1142 r_245 1 + v1142 r_1223 -1 + v1142 r_1427 1 + v1142 r_1905 -1 + v1142 r_2187 1 + v1142 r_2188 1 + v1142 r_2189 1 + v1142 r_2263 1 + v1142 r_2264 1 + v1142 r_2265 1 + v1142 r_2930 1 + v1142 r_2931 1 + v1142 r_3041 1 + v1142 r_3042 1 + v1142 r_3043 1 + v1143 r_127 1 + v1143 r_261 1 + v1143 r_1239 -1 + v1143 r_1428 1 + v1143 r_1913 -1 + v1143 r_2187 1 + v1143 r_2188 1 + v1143 r_2189 1 + v1143 r_2263 1 + v1143 r_2264 1 + v1143 r_2265 1 + v1144 r_127 1 + v1144 r_406 1 + v1144 r_502 1 + v1144 r_622 1 + v1144 r_747 1 + v1144 r_876 1 + v1144 r_983 1 + v1144 r_1110 1 + v1144 r_2052 1 + v1144 r_2384 1 + v1144 r_2385 1 + v1144 r_2386 1 + v1144 r_2451 1 + v1144 r_2452 1 + v1144 r_2453 1 + v1144 r_2563 -1 + v1144 r_2564 -1 + v1144 r_2565 -1 + v1144 r_2566 -1 + v1144 r_2624 -1 + v1144 r_2625 -1 + v1144 r_2626 -1 + v1144 r_2627 -1 + v1144 r_2733 1 + v1144 r_2734 1 + v1144 r_2735 1 + v1144 r_2736 1 + v1144 r_2737 1 + v1144 r_2797 1 + v1144 r_2798 1 + v1144 r_2799 1 + v1144 r_2800 1 + v1144 r_2815 1 + v1144 r_2831 1 + v1145 r_127 1 + v1145 r_295 1 + v1145 r_1429 1 + v1145 r_1921 -1 + v1145 r_2187 1 + v1145 r_2188 1 + v1145 r_2189 1 + v1145 r_2263 1 + v1145 r_2264 1 + v1145 r_2265 1 + v1145 r_3041 1 + v1145 r_3042 1 + v1145 r_3043 1 + v1146 r_127 1 + v1146 r_2019 -1 + v1146 r_2028 1 + v1146 r_2035 1 + v1146 r_2733 1 + v1146 r_2734 1 + v1146 r_2735 1 + v1146 r_2736 1 + v1146 r_2737 1 + v1146 r_2797 1 + v1146 r_2798 1 + v1146 r_2799 1 + v1146 r_2800 1 + v1146 r_2823 1 + v1146 r_2831 1 + v1147 r_128 1 + v1147 r_160 1 + v1147 r_1140 -1 + v1147 r_1422 1 + v1147 r_1863 -1 + v1147 r_2188 1 + v1147 r_2189 1 + v1147 r_2190 1 + v1148 r_128 1 + v1148 r_192 1 + v1148 r_1171 -1 + v1148 r_1424 1 + v1148 r_1879 -1 + v1148 r_2188 1 + v1148 r_2189 1 + v1148 r_2190 1 + v1149 r_128 1 + v1149 r_210 1 + v1149 r_1188 -1 + v1149 r_1425 1 + v1149 r_1888 -1 + v1149 r_2188 1 + v1149 r_2189 1 + v1149 r_2190 1 + v1150 r_128 1 + v1150 r_228 1 + v1150 r_1206 -1 + v1150 r_1426 1 + v1150 r_1897 -1 + v1150 r_2188 1 + v1150 r_2189 1 + v1150 r_2190 1 + v1151 r_128 1 + v1151 r_262 1 + v1151 r_1240 -1 + v1151 r_1428 1 + v1151 r_1914 -1 + v1151 r_2188 1 + v1151 r_2189 1 + v1151 r_2190 1 + v1152 r_128 1 + v1152 r_407 1 + v1152 r_623 1 + v1152 r_748 1 + v1152 r_877 1 + v1152 r_1111 1 + v1152 r_1361 1 + v1152 r_2053 1 + v1152 r_2385 1 + v1152 r_2386 1 + v1152 r_2387 1 + v1152 r_2564 -1 + v1152 r_2565 -1 + v1152 r_2566 -1 + v1152 r_2567 -1 + v1152 r_2734 1 + v1152 r_2735 1 + v1152 r_2736 1 + v1152 r_2737 1 + v1152 r_2738 1 + v1153 r_128 1 + v1153 r_2020 -1 + v1153 r_2028 1 + v1153 r_2036 1 + v1153 r_2734 1 + v1153 r_2735 1 + v1153 r_2736 1 + v1153 r_2737 1 + v1153 r_2738 1 + v1154 r_129 1 + v1154 r_161 1 + v1154 r_1141 -1 + v1154 r_1422 1 + v1154 r_1484 1 + v1154 r_2189 1 + v1154 r_2190 1 + v1154 r_2191 1 + v1154 r_2264 1 + v1154 r_2265 1 + v1154 r_2266 1 + v1155 r_129 1 + v1155 r_177 1 + v1155 r_1157 -1 + v1155 r_1423 1 + v1155 r_1535 1 + v1155 r_2189 1 + v1155 r_2190 1 + v1155 r_2191 1 + v1155 r_2264 1 + v1155 r_2265 1 + v1155 r_2266 1 + v1155 r_2932 1 + v1155 r_2933 1 + v1155 r_3043 1 + v1155 r_3044 1 + v1155 r_3045 1 + v1156 r_129 1 + v1156 r_193 1 + v1156 r_1172 -1 + v1156 r_1424 1 + v1156 r_1592 1 + v1156 r_2189 1 + v1156 r_2190 1 + v1156 r_2191 1 + v1156 r_2264 1 + v1156 r_2265 1 + v1156 r_2266 1 + v1157 r_129 1 + v1157 r_211 1 + v1157 r_1189 -1 + v1157 r_1425 1 + v1157 r_1652 1 + v1157 r_2189 1 + v1157 r_2190 1 + v1157 r_2191 1 + v1157 r_2264 1 + v1157 r_2265 1 + v1157 r_2266 1 + v1158 r_129 1 + v1158 r_229 1 + v1158 r_1207 -1 + v1158 r_1426 1 + v1158 r_1719 1 + v1158 r_2189 1 + v1158 r_2190 1 + v1158 r_2191 1 + v1158 r_2264 1 + v1158 r_2265 1 + v1158 r_2266 1 + v1159 r_129 1 + v1159 r_246 1 + v1159 r_1224 -1 + v1159 r_1427 1 + v1159 r_1775 1 + v1159 r_2189 1 + v1159 r_2190 1 + v1159 r_2191 1 + v1159 r_2264 1 + v1159 r_2265 1 + v1159 r_2266 1 + v1159 r_2932 1 + v1159 r_2933 1 + v1159 r_3043 1 + v1159 r_3044 1 + v1159 r_3045 1 + v1160 r_129 1 + v1160 r_263 1 + v1160 r_1241 -1 + v1160 r_1428 1 + v1160 r_1841 1 + v1160 r_2189 1 + v1160 r_2190 1 + v1160 r_2191 1 + v1160 r_2264 1 + v1160 r_2265 1 + v1160 r_2266 1 + v1161 r_129 1 + v1161 r_408 1 + v1161 r_503 1 + v1161 r_624 1 + v1161 r_749 1 + v1161 r_878 1 + v1161 r_984 1 + v1161 r_1112 1 + v1161 r_1362 1 + v1161 r_2054 1 + v1161 r_2386 1 + v1161 r_2387 1 + v1161 r_2388 1 + v1161 r_2452 1 + v1161 r_2453 1 + v1161 r_2454 1 + v1161 r_2565 -1 + v1161 r_2566 -1 + v1161 r_2567 -1 + v1161 r_2568 -1 + v1161 r_2625 -1 + v1161 r_2626 -1 + v1161 r_2627 -1 + v1161 r_2628 -1 + v1161 r_2735 1 + v1161 r_2736 1 + v1161 r_2737 1 + v1161 r_2738 1 + v1161 r_2739 1 + v1161 r_2798 1 + v1161 r_2799 1 + v1161 r_2800 1 + v1161 r_2801 1 + v1161 r_2815 1 + v1162 r_129 1 + v1162 r_296 1 + v1162 r_1255 -1 + v1162 r_1429 1 + v1162 r_1969 1 + v1162 r_2189 1 + v1162 r_2190 1 + v1162 r_2191 1 + v1162 r_2264 1 + v1162 r_2265 1 + v1162 r_2266 1 + v1162 r_3043 1 + v1162 r_3044 1 + v1162 r_3045 1 + v1163 r_129 1 + v1163 r_2015 1 + v1163 r_2028 1 + v1163 r_2037 1 + v1163 r_2735 1 + v1163 r_2736 1 + v1163 r_2737 1 + v1163 r_2738 1 + v1163 r_2739 1 + v1163 r_2798 1 + v1163 r_2799 1 + v1163 r_2800 1 + v1163 r_2801 1 + v1163 r_2823 1 + v1164 r_130 1 + v1164 r_162 1 + v1164 r_1142 -1 + v1164 r_1422 1 + v1164 r_1485 1 + v1164 r_2190 1 + v1164 r_2191 1 + v1164 r_2192 1 + v1165 r_130 1 + v1165 r_178 1 + v1165 r_1158 -1 + v1165 r_1423 1 + v1165 r_1536 1 + v1165 r_2190 1 + v1165 r_2191 1 + v1165 r_2192 1 + v1165 r_2933 1 + v1165 r_2934 1 + v1165 r_3044 1 + v1165 r_3045 1 + v1165 r_3046 1 + v1166 r_130 1 + v1166 r_194 1 + v1166 r_1173 -1 + v1166 r_1424 1 + v1166 r_1593 1 + v1166 r_2190 1 + v1166 r_2191 1 + v1166 r_2192 1 + v1167 r_130 1 + v1167 r_212 1 + v1167 r_1190 -1 + v1167 r_1425 1 + v1167 r_1653 1 + v1167 r_2190 1 + v1167 r_2191 1 + v1167 r_2192 1 + v1168 r_130 1 + v1168 r_230 1 + v1168 r_1208 -1 + v1168 r_1426 1 + v1168 r_1720 1 + v1168 r_2190 1 + v1168 r_2191 1 + v1168 r_2192 1 + v1169 r_130 1 + v1169 r_247 1 + v1169 r_1225 -1 + v1169 r_1427 1 + v1169 r_1776 1 + v1169 r_2190 1 + v1169 r_2191 1 + v1169 r_2192 1 + v1169 r_2933 1 + v1169 r_2934 1 + v1169 r_3044 1 + v1169 r_3045 1 + v1169 r_3046 1 + v1170 r_130 1 + v1170 r_264 1 + v1170 r_1242 -1 + v1170 r_1428 1 + v1170 r_1842 1 + v1170 r_2190 1 + v1170 r_2191 1 + v1170 r_2192 1 + v1171 r_130 1 + v1171 r_409 1 + v1171 r_504 1 + v1171 r_625 1 + v1171 r_750 1 + v1171 r_879 1 + v1171 r_985 1 + v1171 r_1113 1 + v1171 r_1363 1 + v1171 r_2055 1 + v1171 r_2387 1 + v1171 r_2388 1 + v1171 r_2389 1 + v1171 r_2566 -1 + v1171 r_2567 -1 + v1171 r_2568 -1 + v1171 r_2569 -1 + v1171 r_2736 1 + v1171 r_2737 1 + v1171 r_2738 1 + v1171 r_2739 1 + v1171 r_2740 1 + v1172 r_130 1 + v1172 r_297 1 + v1172 r_1256 -1 + v1172 r_1429 1 + v1172 r_1970 1 + v1172 r_2190 1 + v1172 r_2191 1 + v1172 r_2192 1 + v1172 r_3044 1 + v1172 r_3045 1 + v1172 r_3046 1 + v1173 r_130 1 + v1173 r_2016 1 + v1173 r_2028 1 + v1173 r_2038 1 + v1173 r_2736 1 + v1173 r_2737 1 + v1173 r_2738 1 + v1173 r_2739 1 + v1173 r_2740 1 + v1174 r_131 1 + v1174 r_163 1 + v1174 r_1143 -1 + v1174 r_1422 1 + v1174 r_1486 1 + v1174 r_2191 1 + v1174 r_2192 1 + v1174 r_2193 1 + v1174 r_2265 1 + v1174 r_2266 1 + v1174 r_2267 1 + v1175 r_131 1 + v1175 r_179 1 + v1175 r_1159 -1 + v1175 r_1423 1 + v1175 r_1537 1 + v1175 r_2191 1 + v1175 r_2192 1 + v1175 r_2193 1 + v1175 r_2265 1 + v1175 r_2266 1 + v1175 r_2267 1 + v1175 r_2934 1 + v1175 r_2935 1 + v1175 r_3045 1 + v1175 r_3046 1 + v1175 r_3047 1 + v1176 r_131 1 + v1176 r_195 1 + v1176 r_1174 -1 + v1176 r_1424 1 + v1176 r_1594 1 + v1176 r_2191 1 + v1176 r_2192 1 + v1176 r_2193 1 + v1176 r_2265 1 + v1176 r_2266 1 + v1176 r_2267 1 + v1177 r_131 1 + v1177 r_213 1 + v1177 r_1191 -1 + v1177 r_1425 1 + v1177 r_1654 1 + v1177 r_2191 1 + v1177 r_2192 1 + v1177 r_2193 1 + v1177 r_2265 1 + v1177 r_2266 1 + v1177 r_2267 1 + v1178 r_131 1 + v1178 r_231 1 + v1178 r_1209 -1 + v1178 r_1426 1 + v1178 r_1721 1 + v1178 r_2191 1 + v1178 r_2192 1 + v1178 r_2193 1 + v1178 r_2265 1 + v1178 r_2266 1 + v1178 r_2267 1 + v1179 r_131 1 + v1179 r_248 1 + v1179 r_1226 -1 + v1179 r_1427 1 + v1179 r_1777 1 + v1179 r_2191 1 + v1179 r_2192 1 + v1179 r_2193 1 + v1179 r_2265 1 + v1179 r_2266 1 + v1179 r_2267 1 + v1179 r_2934 1 + v1179 r_2935 1 + v1179 r_3045 1 + v1179 r_3046 1 + v1179 r_3047 1 + v1180 r_131 1 + v1180 r_265 1 + v1180 r_1243 -1 + v1180 r_1428 1 + v1180 r_1843 1 + v1180 r_2191 1 + v1180 r_2192 1 + v1180 r_2193 1 + v1180 r_2265 1 + v1180 r_2266 1 + v1180 r_2267 1 + v1181 r_131 1 + v1181 r_410 1 + v1181 r_505 1 + v1181 r_626 1 + v1181 r_751 1 + v1181 r_880 1 + v1181 r_986 1 + v1181 r_1114 1 + v1181 r_1364 1 + v1181 r_2056 1 + v1181 r_2388 1 + v1181 r_2389 1 + v1181 r_2390 1 + v1181 r_2453 1 + v1181 r_2454 1 + v1181 r_2455 1 + v1181 r_2567 -1 + v1181 r_2568 -1 + v1181 r_2569 -1 + v1181 r_2570 -1 + v1181 r_2626 -1 + v1181 r_2627 -1 + v1181 r_2628 -1 + v1181 r_2737 1 + v1181 r_2738 1 + v1181 r_2739 1 + v1181 r_2740 1 + v1181 r_2741 1 + v1181 r_2799 1 + v1181 r_2800 1 + v1181 r_2801 1 + v1181 r_2815 1 + v1182 r_131 1 + v1182 r_298 1 + v1182 r_1257 -1 + v1182 r_1429 1 + v1182 r_1971 1 + v1182 r_2191 1 + v1182 r_2192 1 + v1182 r_2193 1 + v1182 r_2265 1 + v1182 r_2266 1 + v1182 r_2267 1 + v1182 r_3045 1 + v1182 r_3046 1 + v1182 r_3047 1 + v1183 r_131 1 + v1183 r_2017 1 + v1183 r_2028 1 + v1183 r_2039 1 + v1183 r_2737 1 + v1183 r_2738 1 + v1183 r_2739 1 + v1183 r_2740 1 + v1183 r_2741 1 + v1183 r_2799 1 + v1183 r_2800 1 + v1183 r_2801 1 + v1183 r_2823 1 + v1184 r_132 1 + v1184 r_164 1 + v1184 r_1144 -1 + v1184 r_1422 1 + v1184 r_1487 1 + v1184 r_2192 1 + v1184 r_2193 1 + v1184 r_2194 1 + v1185 r_132 1 + v1185 r_180 1 + v1185 r_1160 -1 + v1185 r_1423 1 + v1185 r_1538 1 + v1185 r_2192 1 + v1185 r_2193 1 + v1185 r_2194 1 + v1185 r_2935 1 + v1185 r_2936 1 + v1185 r_3046 1 + v1185 r_3047 1 + v1185 r_3048 1 + v1186 r_132 1 + v1186 r_196 1 + v1186 r_1175 -1 + v1186 r_1424 1 + v1186 r_1595 1 + v1186 r_2192 1 + v1186 r_2193 1 + v1186 r_2194 1 + v1187 r_132 1 + v1187 r_214 1 + v1187 r_1192 -1 + v1187 r_1425 1 + v1187 r_1655 1 + v1187 r_2192 1 + v1187 r_2193 1 + v1187 r_2194 1 + v1188 r_132 1 + v1188 r_232 1 + v1188 r_1210 -1 + v1188 r_1426 1 + v1188 r_1722 1 + v1188 r_2192 1 + v1188 r_2193 1 + v1188 r_2194 1 + v1189 r_132 1 + v1189 r_249 1 + v1189 r_1227 -1 + v1189 r_1427 1 + v1189 r_1778 1 + v1189 r_2192 1 + v1189 r_2193 1 + v1189 r_2194 1 + v1189 r_2935 1 + v1189 r_2936 1 + v1189 r_3046 1 + v1189 r_3047 1 + v1189 r_3048 1 + v1190 r_132 1 + v1190 r_266 1 + v1190 r_1244 -1 + v1190 r_1428 1 + v1190 r_1844 1 + v1190 r_2192 1 + v1190 r_2193 1 + v1190 r_2194 1 + v1191 r_132 1 + v1191 r_411 1 + v1191 r_506 1 + v1191 r_627 1 + v1191 r_752 1 + v1191 r_881 1 + v1191 r_987 1 + v1191 r_1115 1 + v1191 r_1365 1 + v1191 r_2057 1 + v1191 r_2389 1 + v1191 r_2390 1 + v1191 r_2391 1 + v1191 r_2568 -1 + v1191 r_2569 -1 + v1191 r_2570 -1 + v1191 r_2571 -1 + v1191 r_2738 1 + v1191 r_2739 1 + v1191 r_2740 1 + v1191 r_2741 1 + v1192 r_132 1 + v1192 r_299 1 + v1192 r_1258 -1 + v1192 r_1429 1 + v1192 r_1972 1 + v1192 r_2192 1 + v1192 r_2193 1 + v1192 r_2194 1 + v1192 r_3046 1 + v1192 r_3047 1 + v1192 r_3048 1 + v1193 r_132 1 + v1193 r_2018 1 + v1193 r_2028 1 + v1193 r_2040 1 + v1193 r_2738 1 + v1193 r_2739 1 + v1193 r_2740 1 + v1193 r_2741 1 + v1194 r_133 1 + v1194 r_165 1 + v1194 r_1145 -1 + v1194 r_1422 1 + v1194 r_1488 1 + v1194 r_2193 1 + v1194 r_2194 1 + v1194 r_2195 1 + v1194 r_2266 1 + v1194 r_2267 1 + v1195 r_133 1 + v1195 r_197 1 + v1195 r_1176 -1 + v1195 r_1424 1 + v1195 r_1596 1 + v1195 r_2193 1 + v1195 r_2194 1 + v1195 r_2195 1 + v1195 r_2266 1 + v1195 r_2267 1 + v1196 r_133 1 + v1196 r_215 1 + v1196 r_1193 -1 + v1196 r_1425 1 + v1196 r_1656 1 + v1196 r_2193 1 + v1196 r_2194 1 + v1196 r_2195 1 + v1196 r_2266 1 + v1196 r_2267 1 + v1197 r_133 1 + v1197 r_233 1 + v1197 r_1211 -1 + v1197 r_1426 1 + v1197 r_1723 1 + v1197 r_2193 1 + v1197 r_2194 1 + v1197 r_2195 1 + v1197 r_2266 1 + v1197 r_2267 1 + v1198 r_133 1 + v1198 r_250 1 + v1198 r_1228 -1 + v1198 r_1427 1 + v1198 r_1779 1 + v1198 r_2193 1 + v1198 r_2194 1 + v1198 r_2195 1 + v1198 r_2266 1 + v1198 r_2267 1 + v1198 r_2936 1 + v1198 r_2937 1 + v1198 r_3047 1 + v1198 r_3048 1 + v1198 r_3049 1 + v1199 r_133 1 + v1199 r_267 1 + v1199 r_1245 -1 + v1199 r_1428 1 + v1199 r_1845 1 + v1199 r_2193 1 + v1199 r_2194 1 + v1199 r_2195 1 + v1199 r_2266 1 + v1199 r_2267 1 + v1 r_0 1 + v1 r_1 1 + v1 r_427 1 + v1 r_518 1 + v1 r_643 1 + v1 r_768 1 + v1 r_897 1 + v1 r_1002 1 + v1 r_1131 1 + v1 r_1260 1 + v1 r_2044 1 + v1 r_2275 1 + v1 r_2276 1 + v1 r_2403 1 + v1 r_2460 -1 + v1 r_2582 -1 + v1 r_2630 1 + v1 r_2631 1 + v1 r_2754 1 + v1 r_2808 1 + v1 r_2824 1 + v2 r_1 1 + v2 r_169 1 + v2 r_302 -1 + v2 r_1368 1 + v2 r_1438 -1 + v2 r_2068 1 + v2 r_2069 1 + v2 r_2212 1 + v2 r_2837 1 + v2 r_2838 1 + v2 r_2954 1 + v2 r_2955 1 + v3 r_1 1 + v3 r_183 1 + v3 r_315 -1 + v3 r_1369 1 + v3 r_1444 -1 + v3 r_2068 1 + v3 r_2069 1 + v3 r_2212 1 + v4 r_1 1 + v4 r_201 1 + v4 r_332 -1 + v4 r_1370 1 + v4 r_1452 -1 + v4 r_2068 1 + v4 r_2069 1 + v4 r_2212 1 + v5 r_1 1 + v5 r_219 1 + v5 r_349 -1 + v5 r_1371 1 + v5 r_1460 -1 + v5 r_2068 1 + v5 r_2069 1 + v5 r_2212 1 + v6 r_1 1 + v6 r_237 1 + v6 r_366 -1 + v6 r_1372 1 + v6 r_1468 -1 + v6 r_2068 1 + v6 r_2069 1 + v6 r_2212 1 + v6 r_2837 1 + v6 r_2838 1 + v6 r_2954 1 + v6 r_2955 1 + v6 r_3050 1 + v7 r_1 1 + v7 r_253 1 + v7 r_381 -1 + v7 r_1373 1 + v7 r_1475 -1 + v7 r_2068 1 + v7 r_2069 1 + v7 r_2212 1 + v8 r_1 1 + v8 r_271 1 + v8 r_398 -1 + v8 r_1374 1 + v8 r_1483 -1 + v8 r_2068 1 + v8 r_2069 1 + v8 r_2212 1 + v9 r_1 1 + v9 r_288 1 + v9 r_415 -1 + v9 r_1375 1 + v9 r_1491 -1 + v9 r_2068 1 + v9 r_2069 1 + v9 r_2212 1 + v9 r_2954 1 + v9 r_2955 1 + v1200 r_133 1 + v1200 r_412 1 + v1200 r_628 1 + v1200 r_753 1 + v1200 r_882 1 + v1200 r_988 1 + v1200 r_1116 1 + v1200 r_1366 1 + v1200 r_2058 1 + v1200 r_2390 1 + v1200 r_2391 1 + v1200 r_2392 1 + v1200 r_2454 1 + v1200 r_2455 1 + v1200 r_2569 -1 + v1200 r_2570 -1 + v1200 r_2571 -1 + v1200 r_2627 -1 + v1200 r_2628 -1 + v1200 r_2739 1 + v1200 r_2740 1 + v1200 r_2741 1 + v1200 r_2800 1 + v1200 r_2801 1 + v1200 r_2815 1 + v1201 r_133 1 + v1201 r_300 1 + v1201 r_1259 -1 + v1201 r_1429 1 + v1201 r_1973 1 + v1201 r_2193 1 + v1201 r_2194 1 + v1201 r_2195 1 + v1201 r_2266 1 + v1201 r_2267 1 + v1201 r_3047 1 + v1201 r_3048 1 + v1201 r_3049 1 + v1202 r_134 1 + v1202 r_166 1 + v1202 r_1146 -1 + v1202 r_1422 1 + v1202 r_1489 1 + v1202 r_2194 1 + v1202 r_2195 1 + v1203 r_134 1 + v1203 r_181 1 + v1203 r_1161 -1 + v1203 r_1423 1 + v1203 r_1539 1 + v1203 r_2194 1 + v1203 r_2195 1 + v1203 r_2937 1 + v1203 r_2938 1 + v1203 r_3048 1 + v1203 r_3049 1 + v1204 r_134 1 + v1204 r_198 1 + v1204 r_1177 -1 + v1204 r_1424 1 + v1204 r_1597 1 + v1204 r_2194 1 + v1204 r_2195 1 + v1205 r_134 1 + v1205 r_216 1 + v1205 r_1194 -1 + v1205 r_1425 1 + v1205 r_1657 1 + v1205 r_2194 1 + v1205 r_2195 1 + v1206 r_134 1 + v1206 r_234 1 + v1206 r_1212 -1 + v1206 r_1426 1 + v1206 r_1724 1 + v1206 r_2194 1 + v1206 r_2195 1 + v1207 r_134 1 + v1207 r_251 1 + v1207 r_1229 -1 + v1207 r_1427 1 + v1207 r_1780 1 + v1207 r_2194 1 + v1207 r_2195 1 + v1207 r_2937 1 + v1207 r_2938 1 + v1207 r_3048 1 + v1207 r_3049 1 + v1208 r_134 1 + v1208 r_268 1 + v1208 r_1246 -1 + v1208 r_1428 1 + v1208 r_1846 1 + v1208 r_2194 1 + v1208 r_2195 1 + v1209 r_134 1 + v1209 r_413 1 + v1209 r_507 1 + v1209 r_629 1 + v1209 r_754 1 + v1209 r_883 1 + v1209 r_989 1 + v1209 r_1117 1 + v1209 r_1367 1 + v1209 r_2059 1 + v1209 r_2067 1 + v1209 r_2391 1 + v1209 r_2392 1 + v1209 r_2570 -1 + v1209 r_2571 -1 + v1209 r_2740 1 + v1209 r_2741 1 + v1210 r_134 1 + v1210 r_2019 1 + v1210 r_2028 1 + v1210 r_2041 1 + v1210 r_2067 1 + v1210 r_2740 1 + v1210 r_2741 1 + v1211 r_135 1 + v1211 r_167 1 + v1211 r_1147 -1 + v1211 r_1422 1 + v1211 r_1490 1 + v1211 r_2195 1 + v1211 r_2267 1 + v1212 r_135 1 + v1212 r_199 1 + v1212 r_1178 -1 + v1212 r_1424 1 + v1212 r_1598 1 + v1212 r_2195 1 + v1212 r_2267 1 + v1213 r_135 1 + v1213 r_217 1 + v1213 r_1195 -1 + v1213 r_1425 1 + v1213 r_1658 1 + v1213 r_2195 1 + v1213 r_2267 1 + v1214 r_135 1 + v1214 r_235 1 + v1214 r_1213 -1 + v1214 r_1426 1 + v1214 r_1725 1 + v1214 r_2195 1 + v1214 r_2267 1 + v1214 r_2832 1 + v1215 r_135 1 + v1215 r_269 1 + v1215 r_1247 -1 + v1215 r_1428 1 + v1215 r_1847 1 + v1215 r_2195 1 + v1215 r_2267 1 + v1216 r_135 1 + v1216 r_414 1 + v1216 r_630 1 + v1216 r_755 1 + v1216 r_884 1 + v1216 r_1118 1 + v1216 r_2060 1 + v1216 r_2067 1 + v1216 r_2392 1 + v1216 r_2455 1 + v1216 r_2571 -1 + v1216 r_2628 -1 + v1216 r_2741 1 + v1216 r_2801 1 + v1216 r_2815 1 + v1217 r_135 1 + v1217 r_301 1 + v1217 r_1429 1 + v1217 r_1974 1 + v1217 r_2195 1 + v1217 r_2267 1 + v1217 r_3049 1 + v1218 r_135 1 + v1218 r_2020 1 + v1218 r_2028 1 + v1218 r_2042 1 + v1218 r_2067 1 + v1218 r_2741 1 + v1218 r_2801 1 + v1218 r_2823 1 + v1219 r_136 1 + v1219 r_151 1 + v1219 r_1260 -1 + v1219 r_1430 1 + v1219 r_1922 -1 + v1219 r_2196 1 + v1219 r_2197 1 + v1219 r_2268 1 + v1219 r_2954 1 + v1219 r_2955 1 + v1220 r_136 1 + v1220 r_169 1 + v1220 r_1274 -1 + v1220 r_1431 1 + v1220 r_1929 -1 + v1220 r_2196 1 + v1220 r_2197 1 + v1220 r_2268 1 + v1220 r_2939 1 + v1220 r_2940 1 + v1221 r_136 1 + v1221 r_183 1 + v1221 r_1285 -1 + v1221 r_1432 1 + v1221 r_1934 -1 + v1221 r_2196 1 + v1221 r_2197 1 + v1221 r_2268 1 + v1221 r_2970 1 + v1221 r_2971 1 + v1222 r_136 1 + v1222 r_201 1 + v1222 r_1299 -1 + v1222 r_1433 1 + v1222 r_1941 -1 + v1222 r_2196 1 + v1222 r_2197 1 + v1222 r_2268 1 + v1222 r_2986 1 + v1222 r_2987 1 + v1223 r_136 1 + v1223 r_219 1 + v1223 r_1313 -1 + v1223 r_1434 1 + v1223 r_1948 -1 + v1223 r_2196 1 + v1223 r_2197 1 + v1223 r_2268 1 + v1223 r_3002 1 + v1223 r_3003 1 + v1224 r_136 1 + v1224 r_237 1 + v1224 r_1327 -1 + v1224 r_1435 1 + v1224 r_1955 -1 + v1224 r_2196 1 + v1224 r_2197 1 + v1224 r_2268 1 + v1224 r_2939 1 + v1224 r_2940 1 + v1225 r_136 1 + v1225 r_253 1 + v1225 r_1340 -1 + v1225 r_1436 1 + v1225 r_1961 -1 + v1225 r_2196 1 + v1225 r_2197 1 + v1225 r_2268 1 + v1225 r_3018 1 + v1225 r_3019 1 + v1226 r_136 1 + v1226 r_271 1 + v1226 r_1354 -1 + v1226 r_1437 1 + v1226 r_1968 -1 + v1226 r_2196 1 + v1226 r_2197 1 + v1226 r_2268 1 + v1226 r_3034 1 + v1226 r_3035 1 + v1227 r_136 1 + v1227 r_415 1 + v1227 r_508 1 + v1227 r_631 1 + v1227 r_756 1 + v1227 r_885 1 + v1227 r_990 1 + v1227 r_1119 1 + v1227 r_1248 1 + v1227 r_2044 1 + v1227 r_2393 1 + v1227 r_2456 1 + v1227 r_2572 -1 + v1227 r_2573 -1 + v1227 r_2629 -1 + v1227 r_2742 1 + v1227 r_2743 1 + v1227 r_2802 1 + v1227 r_2816 1 + v1228 r_137 1 + v1228 r_152 1 + v1228 r_1261 -1 + v1228 r_1430 1 + v1228 r_1923 -1 + v1228 r_2196 1 + v1228 r_2197 1 + v1228 r_2198 1 + v1228 r_2954 1 + v1228 r_2955 1 + v1228 r_2956 1 + v1229 r_137 1 + v1229 r_170 1 + v1229 r_1275 -1 + v1229 r_1431 1 + v1229 r_1930 -1 + v1229 r_2196 1 + v1229 r_2197 1 + v1229 r_2198 1 + v1229 r_2940 1 + v1229 r_2941 1 + v1230 r_137 1 + v1230 r_184 1 + v1230 r_1286 -1 + v1230 r_1432 1 + v1230 r_1935 -1 + v1230 r_2196 1 + v1230 r_2197 1 + v1230 r_2198 1 + v1230 r_2970 1 + v1230 r_2971 1 + v1230 r_2972 1 + v1231 r_137 1 + v1231 r_202 1 + v1231 r_1300 -1 + v1231 r_1433 1 + v1231 r_1942 -1 + v1231 r_2196 1 + v1231 r_2197 1 + v1231 r_2198 1 + v1231 r_2986 1 + v1231 r_2987 1 + v1231 r_2988 1 + v1232 r_137 1 + v1232 r_220 1 + v1232 r_1314 -1 + v1232 r_1434 1 + v1232 r_1949 -1 + v1232 r_2196 1 + v1232 r_2197 1 + v1232 r_2198 1 + v1232 r_3002 1 + v1232 r_3003 1 + v1232 r_3004 1 + v1233 r_137 1 + v1233 r_238 1 + v1233 r_1328 -1 + v1233 r_1435 1 + v1233 r_1956 -1 + v1233 r_2196 1 + v1233 r_2197 1 + v1233 r_2198 1 + v1233 r_2940 1 + v1233 r_2941 1 + v1234 r_137 1 + v1234 r_254 1 + v1234 r_1341 -1 + v1234 r_1436 1 + v1234 r_1962 -1 + v1234 r_2196 1 + v1234 r_2197 1 + v1234 r_2198 1 + v1234 r_3018 1 + v1234 r_3019 1 + v1234 r_3020 1 + v1235 r_137 1 + v1235 r_272 1 + v1235 r_1355 -1 + v1235 r_1437 1 + v1235 r_1969 -1 + v1235 r_2196 1 + v1235 r_2197 1 + v1235 r_2198 1 + v1235 r_3034 1 + v1235 r_3035 1 + v1235 r_3036 1 + v1236 r_137 1 + v1236 r_416 1 + v1236 r_509 1 + v1236 r_632 1 + v1236 r_757 1 + v1236 r_886 1 + v1236 r_991 1 + v1236 r_1120 1 + v1236 r_1249 1 + v1236 r_2045 1 + v1236 r_2393 1 + v1236 r_2394 1 + v1236 r_2572 -1 + v1236 r_2573 -1 + v1236 r_2574 -1 + v1236 r_2742 1 + v1236 r_2743 1 + v1236 r_2744 1 + v1237 r_138 1 + v1237 r_153 1 + v1237 r_1262 -1 + v1237 r_1430 1 + v1237 r_1924 -1 + v1237 r_2197 1 + v1237 r_2198 1 + v1237 r_2199 1 + v1237 r_2268 1 + v1237 r_2269 1 + v1237 r_2955 1 + v1237 r_2956 1 + v1237 r_2957 1 + v1238 r_138 1 + v1238 r_171 1 + v1238 r_1276 -1 + v1238 r_1431 1 + v1238 r_1931 -1 + v1238 r_2197 1 + v1238 r_2198 1 + v1238 r_2199 1 + v1238 r_2268 1 + v1238 r_2269 1 + v1238 r_2941 1 + v1238 r_2942 1 + v1239 r_138 1 + v1239 r_185 1 + v1239 r_1287 -1 + v1239 r_1432 1 + v1239 r_1936 -1 + v1239 r_2197 1 + v1239 r_2198 1 + v1239 r_2199 1 + v1239 r_2268 1 + v1239 r_2269 1 + v1239 r_2971 1 + v1239 r_2972 1 + v1239 r_2973 1 + v1240 r_138 1 + v1240 r_203 1 + v1240 r_1301 -1 + v1240 r_1433 1 + v1240 r_1943 -1 + v1240 r_2197 1 + v1240 r_2198 1 + v1240 r_2199 1 + v1240 r_2268 1 + v1240 r_2269 1 + v1240 r_2987 1 + v1240 r_2988 1 + v1240 r_2989 1 + v1241 r_138 1 + v1241 r_221 1 + v1241 r_1315 -1 + v1241 r_1434 1 + v1241 r_1950 -1 + v1241 r_2197 1 + v1241 r_2198 1 + v1241 r_2199 1 + v1241 r_2268 1 + v1241 r_2269 1 + v1241 r_3003 1 + v1241 r_3004 1 + v1241 r_3005 1 + v1242 r_138 1 + v1242 r_239 1 + v1242 r_1329 -1 + v1242 r_1435 1 + v1242 r_1957 -1 + v1242 r_2197 1 + v1242 r_2198 1 + v1242 r_2199 1 + v1242 r_2268 1 + v1242 r_2269 1 + v1242 r_2941 1 + v1242 r_2942 1 + v1243 r_138 1 + v1243 r_255 1 + v1243 r_1342 -1 + v1243 r_1436 1 + v1243 r_1963 -1 + v1243 r_2197 1 + v1243 r_2198 1 + v1243 r_2199 1 + v1243 r_2268 1 + v1243 r_2269 1 + v1243 r_3019 1 + v1243 r_3020 1 + v1243 r_3021 1 + v1244 r_138 1 + v1244 r_273 1 + v1244 r_1356 -1 + v1244 r_1437 1 + v1244 r_1970 -1 + v1244 r_2197 1 + v1244 r_2198 1 + v1244 r_2199 1 + v1244 r_2268 1 + v1244 r_2269 1 + v1244 r_3035 1 + v1244 r_3036 1 + v1244 r_3037 1 + v1245 r_138 1 + v1245 r_417 1 + v1245 r_510 1 + v1245 r_633 1 + v1245 r_758 1 + v1245 r_887 1 + v1245 r_992 1 + v1245 r_1121 1 + v1245 r_1250 1 + v1245 r_2046 1 + v1245 r_2393 1 + v1245 r_2394 1 + v1245 r_2395 1 + v1245 r_2456 1 + v1245 r_2572 -1 + v1245 r_2573 -1 + v1245 r_2574 -1 + v1245 r_2575 -1 + v1245 r_2629 -1 + v1245 r_2742 1 + v1245 r_2743 1 + v1245 r_2744 1 + v1245 r_2745 1 + v1245 r_2802 1 + v1245 r_2803 1 + v1245 r_2816 1 + v1246 r_139 1 + v1246 r_154 1 + v1246 r_1263 -1 + v1246 r_1430 1 + v1246 r_1925 -1 + v1246 r_2198 1 + v1246 r_2199 1 + v1246 r_2200 1 + v1246 r_2956 1 + v1246 r_2957 1 + v1246 r_2958 1 + v1247 r_139 1 + v1247 r_172 1 + v1247 r_1277 -1 + v1247 r_1431 1 + v1247 r_1932 -1 + v1247 r_2198 1 + v1247 r_2199 1 + v1247 r_2200 1 + v1247 r_2942 1 + v1247 r_2943 1 + v1248 r_139 1 + v1248 r_186 1 + v1248 r_1288 -1 + v1248 r_1432 1 + v1248 r_1937 -1 + v1248 r_2198 1 + v1248 r_2199 1 + v1248 r_2200 1 + v1248 r_2972 1 + v1248 r_2973 1 + v1248 r_2974 1 + v1249 r_139 1 + v1249 r_204 1 + v1249 r_1302 -1 + v1249 r_1433 1 + v1249 r_1944 -1 + v1249 r_2198 1 + v1249 r_2199 1 + v1249 r_2200 1 + v1249 r_2988 1 + v1249 r_2989 1 + v1249 r_2990 1 + v1250 r_139 1 + v1250 r_222 1 + v1250 r_1316 -1 + v1250 r_1434 1 + v1250 r_1951 -1 + v1250 r_2198 1 + v1250 r_2199 1 + v1250 r_2200 1 + v1250 r_3004 1 + v1250 r_3005 1 + v1250 r_3006 1 + v1251 r_139 1 + v1251 r_240 1 + v1251 r_1330 -1 + v1251 r_1435 1 + v1251 r_1958 -1 + v1251 r_2198 1 + v1251 r_2199 1 + v1251 r_2200 1 + v1251 r_2942 1 + v1251 r_2943 1 + v1252 r_139 1 + v1252 r_256 1 + v1252 r_1343 -1 + v1252 r_1436 1 + v1252 r_1964 -1 + v1252 r_2198 1 + v1252 r_2199 1 + v1252 r_2200 1 + v1252 r_3020 1 + v1252 r_3021 1 + v1252 r_3022 1 + v1253 r_139 1 + v1253 r_274 1 + v1253 r_1357 -1 + v1253 r_1437 1 + v1253 r_1971 -1 + v1253 r_2198 1 + v1253 r_2199 1 + v1253 r_2200 1 + v1253 r_3036 1 + v1253 r_3037 1 + v1253 r_3038 1 + v1254 r_139 1 + v1254 r_418 1 + v1254 r_511 1 + v1254 r_634 1 + v1254 r_759 1 + v1254 r_888 1 + v1254 r_993 1 + v1254 r_1122 1 + v1254 r_1251 1 + v1254 r_2047 1 + v1254 r_2394 1 + v1254 r_2395 1 + v1254 r_2396 1 + v1254 r_2573 -1 + v1254 r_2574 -1 + v1254 r_2575 -1 + v1254 r_2576 -1 + v1254 r_2742 1 + v1254 r_2743 1 + v1254 r_2744 1 + v1254 r_2745 1 + v1254 r_2746 1 + v1255 r_140 1 + v1255 r_155 1 + v1255 r_1264 -1 + v1255 r_1430 1 + v1255 r_1926 -1 + v1255 r_2199 1 + v1255 r_2200 1 + v1255 r_2201 1 + v1255 r_2268 1 + v1255 r_2269 1 + v1255 r_2270 1 + v1255 r_2957 1 + v1255 r_2958 1 + v1255 r_2959 1 + v1256 r_140 1 + v1256 r_173 1 + v1256 r_1278 -1 + v1256 r_1431 1 + v1256 r_1933 -1 + v1256 r_2199 1 + v1256 r_2200 1 + v1256 r_2201 1 + v1256 r_2268 1 + v1256 r_2269 1 + v1256 r_2270 1 + v1256 r_2943 1 + v1256 r_2944 1 + v1257 r_140 1 + v1257 r_187 1 + v1257 r_1289 -1 + v1257 r_1432 1 + v1257 r_1938 -1 + v1257 r_2199 1 + v1257 r_2200 1 + v1257 r_2201 1 + v1257 r_2268 1 + v1257 r_2269 1 + v1257 r_2270 1 + v1257 r_2973 1 + v1257 r_2974 1 + v1257 r_2975 1 + v1258 r_140 1 + v1258 r_205 1 + v1258 r_1303 -1 + v1258 r_1433 1 + v1258 r_1945 -1 + v1258 r_2199 1 + v1258 r_2200 1 + v1258 r_2201 1 + v1258 r_2268 1 + v1258 r_2269 1 + v1258 r_2270 1 + v1258 r_2989 1 + v1258 r_2990 1 + v1258 r_2991 1 + v1259 r_140 1 + v1259 r_223 1 + v1259 r_1317 -1 + v1259 r_1434 1 + v1259 r_1952 -1 + v1259 r_2199 1 + v1259 r_2200 1 + v1259 r_2201 1 + v1259 r_2268 1 + v1259 r_2269 1 + v1259 r_2270 1 + v1259 r_3005 1 + v1259 r_3006 1 + v1259 r_3007 1 + v1260 r_140 1 + v1260 r_241 1 + v1260 r_1331 -1 + v1260 r_1435 1 + v1260 r_1959 -1 + v1260 r_2199 1 + v1260 r_2200 1 + v1260 r_2201 1 + v1260 r_2268 1 + v1260 r_2269 1 + v1260 r_2270 1 + v1260 r_2943 1 + v1260 r_2944 1 + v1261 r_140 1 + v1261 r_257 1 + v1261 r_1344 -1 + v1261 r_1436 1 + v1261 r_1965 -1 + v1261 r_2199 1 + v1261 r_2200 1 + v1261 r_2201 1 + v1261 r_2268 1 + v1261 r_2269 1 + v1261 r_2270 1 + v1261 r_3021 1 + v1261 r_3022 1 + v1261 r_3023 1 + v1262 r_140 1 + v1262 r_275 1 + v1262 r_1358 -1 + v1262 r_1437 1 + v1262 r_1972 -1 + v1262 r_2199 1 + v1262 r_2200 1 + v1262 r_2201 1 + v1262 r_2268 1 + v1262 r_2269 1 + v1262 r_2270 1 + v1262 r_3037 1 + v1262 r_3038 1 + v1262 r_3039 1 + v1263 r_140 1 + v1263 r_419 1 + v1263 r_512 1 + v1263 r_635 1 + v1263 r_760 1 + v1263 r_889 1 + v1263 r_994 1 + v1263 r_1123 1 + v1263 r_1252 1 + v1263 r_2048 1 + v1263 r_2395 1 + v1263 r_2396 1 + v1263 r_2456 1 + v1263 r_2574 -1 + v1263 r_2575 -1 + v1263 r_2576 -1 + v1263 r_2577 -1 + v1263 r_2629 -1 + v1263 r_2743 1 + v1263 r_2744 1 + v1263 r_2745 1 + v1263 r_2746 1 + v1263 r_2747 1 + v1263 r_2802 1 + v1263 r_2803 1 + v1263 r_2804 1 + v1263 r_2816 1 + v1264 r_141 1 + v1264 r_156 1 + v1264 r_1265 -1 + v1264 r_1430 1 + v1264 r_1927 -1 + v1264 r_2200 1 + v1264 r_2201 1 + v1264 r_2202 1 + v1264 r_2958 1 + v1264 r_2959 1 + v1264 r_2960 1 + v1265 r_141 1 + v1265 r_188 1 + v1265 r_1290 -1 + v1265 r_1432 1 + v1265 r_1939 -1 + v1265 r_2200 1 + v1265 r_2201 1 + v1265 r_2202 1 + v1265 r_2974 1 + v1265 r_2975 1 + v1265 r_2976 1 + v1266 r_141 1 + v1266 r_206 1 + v1266 r_1304 -1 + v1266 r_1433 1 + v1266 r_1946 -1 + v1266 r_2200 1 + v1266 r_2201 1 + v1266 r_2202 1 + v1266 r_2990 1 + v1266 r_2991 1 + v1266 r_2992 1 + v1267 r_141 1 + v1267 r_224 1 + v1267 r_1318 -1 + v1267 r_1434 1 + v1267 r_1953 -1 + v1267 r_2200 1 + v1267 r_2201 1 + v1267 r_2202 1 + v1267 r_3006 1 + v1267 r_3007 1 + v1267 r_3008 1 + v1268 r_141 1 + v1268 r_242 1 + v1268 r_1332 -1 + v1268 r_1435 1 + v1268 r_1960 -1 + v1268 r_2200 1 + v1268 r_2201 1 + v1268 r_2202 1 + v1268 r_2944 1 + v1269 r_141 1 + v1269 r_258 1 + v1269 r_1345 -1 + v1269 r_1436 1 + v1269 r_1966 -1 + v1269 r_2200 1 + v1269 r_2201 1 + v1269 r_2202 1 + v1269 r_3022 1 + v1269 r_3023 1 + v1269 r_3024 1 + v1270 r_141 1 + v1270 r_276 1 + v1270 r_1359 -1 + v1270 r_1437 1 + v1270 r_1973 -1 + v1270 r_2200 1 + v1270 r_2201 1 + v1270 r_2202 1 + v1270 r_3038 1 + v1270 r_3039 1 + v1270 r_3040 1 + v1271 r_141 1 + v1271 r_420 1 + v1271 r_636 1 + v1271 r_761 1 + v1271 r_890 1 + v1271 r_995 1 + v1271 r_1124 1 + v1271 r_1253 1 + v1271 r_2049 1 + v1271 r_2396 1 + v1271 r_2575 -1 + v1271 r_2576 -1 + v1271 r_2577 -1 + v1271 r_2744 1 + v1271 r_2745 1 + v1271 r_2746 1 + v1271 r_2747 1 + v1271 r_2748 1 + v1272 r_142 1 + v1272 r_158 1 + v1272 r_1266 -1 + v1272 r_1430 1 + v1272 r_1491 1 + v1272 r_2202 1 + v1272 r_2203 1 + v1272 r_2204 1 + v1272 r_2960 1 + v1272 r_2961 1 + v1272 r_2962 1 + v1273 r_142 1 + v1273 r_175 1 + v1273 r_1279 -1 + v1273 r_1431 1 + v1273 r_1540 1 + v1273 r_2202 1 + v1273 r_2203 1 + v1273 r_2204 1 + v1273 r_2945 1 + v1273 r_2946 1 + v1274 r_142 1 + v1274 r_190 1 + v1274 r_1291 -1 + v1274 r_1432 1 + v1274 r_1599 1 + v1274 r_2202 1 + v1274 r_2203 1 + v1274 r_2204 1 + v1274 r_2976 1 + v1274 r_2977 1 + v1274 r_2978 1 + v1275 r_142 1 + v1275 r_208 1 + v1275 r_1305 -1 + v1275 r_1433 1 + v1275 r_1659 1 + v1275 r_2202 1 + v1275 r_2203 1 + v1275 r_2204 1 + v1275 r_2992 1 + v1275 r_2993 1 + v1275 r_2994 1 + v1276 r_142 1 + v1276 r_226 1 + v1276 r_1319 -1 + v1276 r_1434 1 + v1276 r_1726 1 + v1276 r_2202 1 + v1276 r_2203 1 + v1276 r_2204 1 + v1276 r_3008 1 + v1276 r_3009 1 + v1276 r_3010 1 + v1277 r_142 1 + v1277 r_244 1 + v1277 r_1333 -1 + v1277 r_1435 1 + v1277 r_1781 1 + v1277 r_2202 1 + v1277 r_2203 1 + v1277 r_2204 1 + v1277 r_2945 1 + v1277 r_2946 1 + v1278 r_142 1 + v1278 r_260 1 + v1278 r_1346 -1 + v1278 r_1436 1 + v1278 r_1848 1 + v1278 r_2202 1 + v1278 r_2203 1 + v1278 r_2204 1 + v1278 r_3024 1 + v1278 r_3025 1 + v1278 r_3026 1 + v1279 r_142 1 + v1279 r_278 1 + v1279 r_1360 -1 + v1279 r_1437 1 + v1279 r_1915 1 + v1279 r_2202 1 + v1279 r_2203 1 + v1279 r_2204 1 + v1279 r_3040 1 + v1279 r_3041 1 + v1279 r_3042 1 + v1280 r_142 1 + v1280 r_421 1 + v1280 r_513 1 + v1280 r_637 1 + v1280 r_762 1 + v1280 r_891 1 + v1280 r_996 1 + v1280 r_1125 1 + v1280 r_1254 1 + v1280 r_2051 1 + v1280 r_2397 1 + v1280 r_2577 -1 + v1280 r_2746 1 + v1280 r_2747 1 + v1280 r_2748 1 + v1280 r_2749 1 + v1280 r_2750 1 + v1281 r_143 1 + v1281 r_160 1 + v1281 r_1267 -1 + v1281 r_1430 1 + v1281 r_1928 -1 + v1281 r_2204 1 + v1281 r_2205 1 + v1281 r_2206 1 + v1281 r_2962 1 + v1281 r_2963 1 + v1281 r_2964 1 + v1282 r_143 1 + v1282 r_192 1 + v1282 r_1292 -1 + v1282 r_1432 1 + v1282 r_1940 -1 + v1282 r_2204 1 + v1282 r_2205 1 + v1282 r_2206 1 + v1282 r_2978 1 + v1282 r_2979 1 + v1282 r_2980 1 + v1283 r_143 1 + v1283 r_210 1 + v1283 r_1306 -1 + v1283 r_1433 1 + v1283 r_1947 -1 + v1283 r_2204 1 + v1283 r_2205 1 + v1283 r_2206 1 + v1283 r_2994 1 + v1283 r_2995 1 + v1283 r_2996 1 + v1284 r_143 1 + v1284 r_228 1 + v1284 r_1320 -1 + v1284 r_1434 1 + v1284 r_1954 -1 + v1284 r_2204 1 + v1284 r_2205 1 + v1284 r_2206 1 + v1284 r_3010 1 + v1284 r_3011 1 + v1284 r_3012 1 + v1285 r_143 1 + v1285 r_262 1 + v1285 r_1347 -1 + v1285 r_1436 1 + v1285 r_1967 -1 + v1285 r_2204 1 + v1285 r_2205 1 + v1285 r_2206 1 + v1285 r_3026 1 + v1285 r_3027 1 + v1285 r_3028 1 + v1286 r_143 1 + v1286 r_280 1 + v1286 r_1361 -1 + v1286 r_1437 1 + v1286 r_1974 -1 + v1286 r_2204 1 + v1286 r_2205 1 + v1286 r_2206 1 + v1286 r_3042 1 + v1286 r_3043 1 + v1286 r_3044 1 + v1287 r_143 1 + v1287 r_2053 1 + v1287 r_2397 1 + v1287 r_2398 1 + v1287 r_2399 1 + v1287 r_2578 -1 + v1287 r_2748 1 + v1287 r_2749 1 + v1287 r_2750 1 + v1287 r_2751 1 + v1287 r_2752 1 + v1288 r_144 1 + v1288 r_161 1 + v1288 r_1268 -1 + v1288 r_1430 1 + v1288 r_1492 1 + v1288 r_2205 1 + v1288 r_2206 1 + v1288 r_2207 1 + v1288 r_2271 1 + v1288 r_2272 1 + v1288 r_2273 1 + v1288 r_2963 1 + v1288 r_2964 1 + v1288 r_2965 1 + v1289 r_144 1 + v1289 r_177 1 + v1289 r_1280 -1 + v1289 r_1431 1 + v1289 r_1541 1 + v1289 r_2205 1 + v1289 r_2206 1 + v1289 r_2207 1 + v1289 r_2271 1 + v1289 r_2272 1 + v1289 r_2273 1 + v1289 r_2834 1 + v1289 r_2947 1 + v1289 r_2948 1 + v1290 r_144 1 + v1290 r_193 1 + v1290 r_1293 -1 + v1290 r_1432 1 + v1290 r_1600 1 + v1290 r_2205 1 + v1290 r_2206 1 + v1290 r_2207 1 + v1290 r_2271 1 + v1290 r_2272 1 + v1290 r_2273 1 + v1290 r_2979 1 + v1290 r_2980 1 + v1290 r_2981 1 + v1291 r_144 1 + v1291 r_211 1 + v1291 r_1307 -1 + v1291 r_1433 1 + v1291 r_1660 1 + v1291 r_2205 1 + v1291 r_2206 1 + v1291 r_2207 1 + v1291 r_2271 1 + v1291 r_2272 1 + v1291 r_2273 1 + v1291 r_2995 1 + v1291 r_2996 1 + v1291 r_2997 1 + v1292 r_144 1 + v1292 r_229 1 + v1292 r_1321 -1 + v1292 r_1434 1 + v1292 r_1727 1 + v1292 r_2205 1 + v1292 r_2206 1 + v1292 r_2207 1 + v1292 r_2271 1 + v1292 r_2272 1 + v1292 r_2273 1 + v1292 r_3011 1 + v1292 r_3012 1 + v1292 r_3013 1 + v1293 r_144 1 + v1293 r_246 1 + v1293 r_1334 -1 + v1293 r_1435 1 + v1293 r_1782 1 + v1293 r_2205 1 + v1293 r_2206 1 + v1293 r_2207 1 + v1293 r_2271 1 + v1293 r_2272 1 + v1293 r_2273 1 + v1293 r_2833 1 + v1293 r_2947 1 + v1293 r_2948 1 + v1294 r_144 1 + v1294 r_263 1 + v1294 r_1348 -1 + v1294 r_1436 1 + v1294 r_1849 1 + v1294 r_2205 1 + v1294 r_2206 1 + v1294 r_2207 1 + v1294 r_2271 1 + v1294 r_2272 1 + v1294 r_2273 1 + v1294 r_3027 1 + v1294 r_3028 1 + v1294 r_3029 1 + v1295 r_144 1 + v1295 r_281 1 + v1295 r_1362 -1 + v1295 r_1437 1 + v1295 r_1916 1 + v1295 r_2205 1 + v1295 r_2206 1 + v1295 r_2207 1 + v1295 r_2271 1 + v1295 r_2272 1 + v1295 r_2273 1 + v1295 r_3043 1 + v1295 r_3044 1 + v1295 r_3045 1 + v1296 r_144 1 + v1296 r_422 1 + v1296 r_514 1 + v1296 r_638 1 + v1296 r_763 1 + v1296 r_892 1 + v1296 r_997 1 + v1296 r_1126 1 + v1296 r_1255 1 + v1296 r_2054 1 + v1296 r_2398 1 + v1296 r_2399 1 + v1296 r_2400 1 + v1296 r_2457 1 + v1296 r_2458 1 + v1296 r_2578 -1 + v1296 r_2579 -1 + v1296 r_2749 1 + v1296 r_2750 1 + v1296 r_2751 1 + v1296 r_2752 1 + v1296 r_2753 1 + v1296 r_2804 1 + v1296 r_2805 1 + v1296 r_2806 1 + v1296 r_2807 1 + v1296 r_2816 1 + v1297 r_145 1 + v1297 r_162 1 + v1297 r_1269 -1 + v1297 r_1430 1 + v1297 r_1493 1 + v1297 r_2206 1 + v1297 r_2207 1 + v1297 r_2208 1 + v1297 r_2964 1 + v1297 r_2965 1 + v1297 r_2966 1 + v1298 r_145 1 + v1298 r_178 1 + v1298 r_1281 -1 + v1298 r_1431 1 + v1298 r_1542 1 + v1298 r_2206 1 + v1298 r_2207 1 + v1298 r_2208 1 + v1298 r_2834 1 + v1298 r_2948 1 + v1298 r_2949 1 + v1299 r_145 1 + v1299 r_194 1 + v1299 r_1294 -1 + v1299 r_1432 1 + v1299 r_1601 1 + v1299 r_2206 1 + v1299 r_2207 1 + v1299 r_2208 1 + v1299 r_2980 1 + v1299 r_2981 1 + v1299 r_2982 1 + v1300 r_145 1 + v1300 r_212 1 + v1300 r_1308 -1 + v1300 r_1433 1 + v1300 r_1661 1 + v1300 r_2206 1 + v1300 r_2207 1 + v1300 r_2208 1 + v1300 r_2996 1 + v1300 r_2997 1 + v1300 r_2998 1 + v1301 r_145 1 + v1301 r_230 1 + v1301 r_1322 -1 + v1301 r_1434 1 + v1301 r_1728 1 + v1301 r_2206 1 + v1301 r_2207 1 + v1301 r_2208 1 + v1301 r_3012 1 + v1301 r_3013 1 + v1301 r_3014 1 + v1302 r_145 1 + v1302 r_247 1 + v1302 r_1335 -1 + v1302 r_1435 1 + v1302 r_1783 1 + v1302 r_2206 1 + v1302 r_2207 1 + v1302 r_2208 1 + v1302 r_2833 1 + v1302 r_2948 1 + v1302 r_2949 1 + v1303 r_145 1 + v1303 r_264 1 + v1303 r_1349 -1 + v1303 r_1436 1 + v1303 r_1850 1 + v1303 r_2206 1 + v1303 r_2207 1 + v1303 r_2208 1 + v1303 r_3028 1 + v1303 r_3029 1 + v1303 r_3030 1 + v1304 r_145 1 + v1304 r_282 1 + v1304 r_1363 -1 + v1304 r_1437 1 + v1304 r_1917 1 + v1304 r_2206 1 + v1304 r_2207 1 + v1304 r_2208 1 + v1304 r_3044 1 + v1304 r_3045 1 + v1304 r_3046 1 + v1305 r_145 1 + v1305 r_423 1 + v1305 r_515 1 + v1305 r_639 1 + v1305 r_764 1 + v1305 r_893 1 + v1305 r_998 1 + v1305 r_1127 1 + v1305 r_1256 1 + v1305 r_2055 1 + v1305 r_2399 1 + v1305 r_2400 1 + v1305 r_2401 1 + v1305 r_2578 -1 + v1305 r_2579 -1 + v1305 r_2580 -1 + v1305 r_2750 1 + v1305 r_2751 1 + v1305 r_2752 1 + v1305 r_2753 1 + v1306 r_146 1 + v1306 r_163 1 + v1306 r_1270 -1 + v1306 r_1430 1 + v1306 r_1494 1 + v1306 r_2207 1 + v1306 r_2208 1 + v1306 r_2209 1 + v1306 r_2272 1 + v1306 r_2273 1 + v1306 r_2274 1 + v1306 r_2965 1 + v1306 r_2966 1 + v1306 r_2967 1 + v1307 r_146 1 + v1307 r_179 1 + v1307 r_1282 -1 + v1307 r_1431 1 + v1307 r_1543 1 + v1307 r_2207 1 + v1307 r_2208 1 + v1307 r_2209 1 + v1307 r_2272 1 + v1307 r_2273 1 + v1307 r_2274 1 + v1307 r_2834 1 + v1307 r_2949 1 + v1307 r_2950 1 + v1308 r_146 1 + v1308 r_195 1 + v1308 r_1295 -1 + v1308 r_1432 1 + v1308 r_1602 1 + v1308 r_2207 1 + v1308 r_2208 1 + v1308 r_2209 1 + v1308 r_2272 1 + v1308 r_2273 1 + v1308 r_2274 1 + v1308 r_2981 1 + v1308 r_2982 1 + v1308 r_2983 1 + v1309 r_146 1 + v1309 r_213 1 + v1309 r_1309 -1 + v1309 r_1433 1 + v1309 r_1662 1 + v1309 r_2207 1 + v1309 r_2208 1 + v1309 r_2209 1 + v1309 r_2272 1 + v1309 r_2273 1 + v1309 r_2274 1 + v1309 r_2997 1 + v1309 r_2998 1 + v1309 r_2999 1 + v1310 r_146 1 + v1310 r_231 1 + v1310 r_1323 -1 + v1310 r_1434 1 + v1310 r_1729 1 + v1310 r_2207 1 + v1310 r_2208 1 + v1310 r_2209 1 + v1310 r_2272 1 + v1310 r_2273 1 + v1310 r_2274 1 + v1310 r_3013 1 + v1310 r_3014 1 + v1310 r_3015 1 + v1311 r_146 1 + v1311 r_248 1 + v1311 r_1336 -1 + v1311 r_1435 1 + v1311 r_1784 1 + v1311 r_2207 1 + v1311 r_2208 1 + v1311 r_2209 1 + v1311 r_2272 1 + v1311 r_2273 1 + v1311 r_2274 1 + v1311 r_2833 1 + v1311 r_2949 1 + v1311 r_2950 1 + v1312 r_146 1 + v1312 r_265 1 + v1312 r_1350 -1 + v1312 r_1436 1 + v1312 r_1851 1 + v1312 r_2207 1 + v1312 r_2208 1 + v1312 r_2209 1 + v1312 r_2272 1 + v1312 r_2273 1 + v1312 r_2274 1 + v1312 r_3029 1 + v1312 r_3030 1 + v1312 r_3031 1 + v1313 r_146 1 + v1313 r_283 1 + v1313 r_1364 -1 + v1313 r_1437 1 + v1313 r_1918 1 + v1313 r_2207 1 + v1313 r_2208 1 + v1313 r_2209 1 + v1313 r_2272 1 + v1313 r_2273 1 + v1313 r_2274 1 + v1313 r_3045 1 + v1313 r_3046 1 + v1313 r_3047 1 + v1314 r_146 1 + v1314 r_424 1 + v1314 r_516 1 + v1314 r_640 1 + v1314 r_765 1 + v1314 r_894 1 + v1314 r_999 1 + v1314 r_1128 1 + v1314 r_1257 1 + v1314 r_2056 1 + v1314 r_2400 1 + v1314 r_2401 1 + v1314 r_2402 1 + v1314 r_2457 1 + v1314 r_2458 1 + v1314 r_2459 1 + v1314 r_2578 -1 + v1314 r_2579 -1 + v1314 r_2580 -1 + v1314 r_2581 -1 + v1314 r_2751 1 + v1314 r_2752 1 + v1314 r_2753 1 + v1314 r_2805 1 + v1314 r_2806 1 + v1314 r_2807 1 + v1314 r_2816 1 + v1315 r_147 1 + v1315 r_164 1 + v1315 r_1271 -1 + v1315 r_1430 1 + v1315 r_1495 1 + v1315 r_2208 1 + v1315 r_2209 1 + v1315 r_2210 1 + v1315 r_2966 1 + v1315 r_2967 1 + v1315 r_2968 1 + v1316 r_147 1 + v1316 r_180 1 + v1316 r_1283 -1 + v1316 r_1431 1 + v1316 r_1544 1 + v1316 r_2208 1 + v1316 r_2209 1 + v1316 r_2210 1 + v1316 r_2834 1 + v1316 r_2950 1 + v1316 r_2951 1 + v1317 r_147 1 + v1317 r_196 1 + v1317 r_1296 -1 + v1317 r_1432 1 + v1317 r_1603 1 + v1317 r_2208 1 + v1317 r_2209 1 + v1317 r_2210 1 + v1317 r_2982 1 + v1317 r_2983 1 + v1317 r_2984 1 + v1318 r_147 1 + v1318 r_214 1 + v1318 r_1310 -1 + v1318 r_1433 1 + v1318 r_1663 1 + v1318 r_2208 1 + v1318 r_2209 1 + v1318 r_2210 1 + v1318 r_2998 1 + v1318 r_2999 1 + v1318 r_3000 1 + v1319 r_147 1 + v1319 r_232 1 + v1319 r_1324 -1 + v1319 r_1434 1 + v1319 r_1730 1 + v1319 r_2208 1 + v1319 r_2209 1 + v1319 r_2210 1 + v1319 r_3014 1 + v1319 r_3015 1 + v1319 r_3016 1 + v1320 r_147 1 + v1320 r_249 1 + v1320 r_1337 -1 + v1320 r_1435 1 + v1320 r_1785 1 + v1320 r_2208 1 + v1320 r_2209 1 + v1320 r_2210 1 + v1320 r_2833 1 + v1320 r_2950 1 + v1320 r_2951 1 + v1321 r_147 1 + v1321 r_266 1 + v1321 r_1351 -1 + v1321 r_1436 1 + v1321 r_1852 1 + v1321 r_2208 1 + v1321 r_2209 1 + v1321 r_2210 1 + v1321 r_3030 1 + v1321 r_3031 1 + v1321 r_3032 1 + v1322 r_147 1 + v1322 r_284 1 + v1322 r_1365 -1 + v1322 r_1437 1 + v1322 r_1919 1 + v1322 r_2208 1 + v1322 r_2209 1 + v1322 r_2210 1 + v1322 r_3046 1 + v1322 r_3047 1 + v1322 r_3048 1 + v1323 r_147 1 + v1323 r_425 1 + v1323 r_517 1 + v1323 r_641 1 + v1323 r_766 1 + v1323 r_895 1 + v1323 r_1000 1 + v1323 r_1129 1 + v1323 r_1258 1 + v1323 r_2057 1 + v1323 r_2401 1 + v1323 r_2402 1 + v1323 r_2579 -1 + v1323 r_2580 -1 + v1323 r_2581 -1 + v1323 r_2752 1 + v1323 r_2753 1 + v1324 r_148 1 + v1324 r_165 1 + v1324 r_1272 -1 + v1324 r_1430 1 + v1324 r_1496 1 + v1324 r_2209 1 + v1324 r_2210 1 + v1324 r_2211 1 + v1324 r_2273 1 + v1324 r_2274 1 + v1324 r_2967 1 + v1324 r_2968 1 + v1324 r_2969 1 + v1325 r_148 1 + v1325 r_197 1 + v1325 r_1297 -1 + v1325 r_1432 1 + v1325 r_1604 1 + v1325 r_2209 1 + v1325 r_2210 1 + v1325 r_2211 1 + v1325 r_2273 1 + v1325 r_2274 1 + v1325 r_2983 1 + v1325 r_2984 1 + v1325 r_2985 1 + v1326 r_148 1 + v1326 r_215 1 + v1326 r_1311 -1 + v1326 r_1433 1 + v1326 r_1664 1 + v1326 r_2209 1 + v1326 r_2210 1 + v1326 r_2211 1 + v1326 r_2273 1 + v1326 r_2274 1 + v1326 r_2999 1 + v1326 r_3000 1 + v1326 r_3001 1 + v1327 r_148 1 + v1327 r_233 1 + v1327 r_1325 -1 + v1327 r_1434 1 + v1327 r_1731 1 + v1327 r_2209 1 + v1327 r_2210 1 + v1327 r_2211 1 + v1327 r_2273 1 + v1327 r_2274 1 + v1327 r_3015 1 + v1327 r_3016 1 + v1327 r_3017 1 + v1328 r_148 1 + v1328 r_250 1 + v1328 r_1338 -1 + v1328 r_1435 1 + v1328 r_1786 1 + v1328 r_2209 1 + v1328 r_2210 1 + v1328 r_2211 1 + v1328 r_2273 1 + v1328 r_2274 1 + v1328 r_2833 1 + v1328 r_2951 1 + v1328 r_2952 1 + v1329 r_148 1 + v1329 r_267 1 + v1329 r_1352 -1 + v1329 r_1436 1 + v1329 r_1853 1 + v1329 r_2209 1 + v1329 r_2210 1 + v1329 r_2211 1 + v1329 r_2273 1 + v1329 r_2274 1 + v1329 r_3031 1 + v1329 r_3032 1 + v1329 r_3033 1 + v1330 r_148 1 + v1330 r_285 1 + v1330 r_1366 -1 + v1330 r_1437 1 + v1330 r_1920 1 + v1330 r_2209 1 + v1330 r_2210 1 + v1330 r_2211 1 + v1330 r_2273 1 + v1330 r_2274 1 + v1330 r_3047 1 + v1330 r_3048 1 + v1330 r_3049 1 + v1331 r_148 1 + v1331 r_426 1 + v1331 r_642 1 + v1331 r_767 1 + v1331 r_896 1 + v1331 r_1001 1 + v1331 r_1130 1 + v1331 r_1259 1 + v1331 r_2058 1 + v1331 r_2402 1 + v1331 r_2458 1 + v1331 r_2459 1 + v1331 r_2580 -1 + v1331 r_2581 -1 + v1331 r_2753 1 + v1331 r_2806 1 + v1331 r_2807 1 + v1331 r_2816 1 + v1332 r_149 1 + v1332 r_166 1 + v1332 r_1273 -1 + v1332 r_1430 1 + v1332 r_1497 1 + v1332 r_2210 1 + v1332 r_2211 1 + v1332 r_2968 1 + v1332 r_2969 1 + v1333 r_149 1 + v1333 r_181 1 + v1333 r_1284 -1 + v1333 r_1431 1 + v1333 r_1545 1 + v1333 r_2210 1 + v1333 r_2211 1 + v1333 r_2834 1 + v1333 r_2952 1 + v1333 r_2953 1 + v1334 r_149 1 + v1334 r_198 1 + v1334 r_1298 -1 + v1334 r_1432 1 + v1334 r_1605 1 + v1334 r_2210 1 + v1334 r_2211 1 + v1334 r_2984 1 + v1334 r_2985 1 + v1335 r_149 1 + v1335 r_216 1 + v1335 r_1312 -1 + v1335 r_1433 1 + v1335 r_1665 1 + v1335 r_2210 1 + v1335 r_2211 1 + v1335 r_3000 1 + v1335 r_3001 1 + v1336 r_149 1 + v1336 r_234 1 + v1336 r_1326 -1 + v1336 r_1434 1 + v1336 r_1732 1 + v1336 r_2210 1 + v1336 r_2211 1 + v1336 r_3016 1 + v1336 r_3017 1 + v1337 r_149 1 + v1337 r_251 1 + v1337 r_1339 -1 + v1337 r_1435 1 + v1337 r_1787 1 + v1337 r_2210 1 + v1337 r_2211 1 + v1337 r_2833 1 + v1337 r_2952 1 + v1337 r_2953 1 + v1338 r_149 1 + v1338 r_268 1 + v1338 r_1353 -1 + v1338 r_1436 1 + v1338 r_1854 1 + v1338 r_2210 1 + v1338 r_2211 1 + v1338 r_3032 1 + v1338 r_3033 1 + v1339 r_149 1 + v1339 r_286 1 + v1339 r_1367 -1 + v1339 r_1437 1 + v1339 r_1921 1 + v1339 r_2210 1 + v1339 r_2211 1 + v1339 r_3048 1 + v1339 r_3049 1 + v100 r_11 1 + v100 r_263 1 + v100 r_391 -1 + v100 r_1373 1 + v100 r_1790 1 + v100 r_2077 1 + v100 r_2078 1 + v100 r_2079 1 + v100 r_2215 1 + v100 r_2216 1 + v100 r_2217 1 + v101 r_11 1 + v101 r_281 1 + v101 r_408 -1 + v101 r_1374 1 + v101 r_1857 1 + v101 r_2077 1 + v101 r_2078 1 + v101 r_2079 1 + v101 r_2215 1 + v101 r_2216 1 + v101 r_2217 1 + v102 r_11 1 + v102 r_296 1 + v102 r_422 -1 + v102 r_1375 1 + v102 r_1923 1 + v102 r_2077 1 + v102 r_2078 1 + v102 r_2079 1 + v102 r_2215 1 + v102 r_2216 1 + v102 r_2217 1 + v102 r_2963 1 + v102 r_2964 1 + v102 r_2965 1 + v103 r_11 1 + v103 r_1976 1 + v103 r_2021 1 + v103 r_2037 1 + v103 r_2637 1 + v103 r_2638 1 + v103 r_2639 1 + v103 r_2640 1 + v103 r_2641 1 + v103 r_2756 1 + v103 r_2757 1 + v103 r_2758 1 + v103 r_2759 1 + v103 r_2817 1 + v104 r_12 1 + v104 r_436 1 + v104 r_529 1 + v104 r_654 1 + v104 r_779 1 + v104 r_907 1 + v104 r_1013 1 + v104 r_1142 1 + v104 r_1269 1 + v104 r_2055 1 + v104 r_2285 1 + v104 r_2286 1 + v104 r_2287 1 + v104 r_2468 -1 + v104 r_2469 -1 + v104 r_2470 -1 + v104 r_2471 -1 + v104 r_2638 1 + v104 r_2639 1 + v104 r_2640 1 + v104 r_2641 1 + v104 r_2642 1 + v105 r_12 1 + v105 r_178 1 + v105 r_311 -1 + v105 r_1368 1 + v105 r_1501 1 + v105 r_2078 1 + v105 r_2079 1 + v105 r_2080 1 + v105 r_2848 1 + v105 r_2849 1 + v105 r_2964 1 + v105 r_2965 1 + v105 r_2966 1 + v106 r_12 1 + v106 r_194 1 + v106 r_326 -1 + v106 r_1369 1 + v106 r_1548 1 + v106 r_2078 1 + v106 r_2079 1 + v106 r_2080 1 + v107 r_12 1 + v107 r_212 1 + v107 r_343 -1 + v107 r_1370 1 + v107 r_1608 1 + v107 r_2078 1 + v107 r_2079 1 + v107 r_2080 1 + v108 r_12 1 + v108 r_230 1 + v108 r_360 -1 + v108 r_1371 1 + v108 r_1669 1 + v108 r_2078 1 + v108 r_2079 1 + v108 r_2080 1 + v109 r_12 1 + v109 r_247 1 + v109 r_376 -1 + v109 r_1372 1 + v109 r_1736 1 + v109 r_2078 1 + v109 r_2079 1 + v109 r_2080 1 + v109 r_2848 1 + v109 r_2849 1 + v109 r_2964 1 + v109 r_2965 1 + v109 r_2966 1 + v110 r_12 1 + v110 r_264 1 + v110 r_392 -1 + v110 r_1373 1 + v110 r_1791 1 + v110 r_2078 1 + v110 r_2079 1 + v110 r_2080 1 + v111 r_12 1 + v111 r_282 1 + v111 r_409 -1 + v111 r_1374 1 + v111 r_1858 1 + v111 r_2078 1 + v111 r_2079 1 + v111 r_2080 1 + v112 r_12 1 + v112 r_297 1 + v112 r_423 -1 + v112 r_1375 1 + v112 r_1924 1 + v112 r_2078 1 + v112 r_2079 1 + v112 r_2080 1 + v112 r_2964 1 + v112 r_2965 1 + v112 r_2966 1 + v113 r_12 1 + v113 r_1977 1 + v113 r_2021 1 + v113 r_2038 1 + v113 r_2638 1 + v113 r_2639 1 + v113 r_2640 1 + v113 r_2641 1 + v113 r_2642 1 + v114 r_13 1 + v114 r_437 1 + v114 r_530 1 + v114 r_655 1 + v114 r_780 1 + v114 r_908 1 + v114 r_1014 1 + v114 r_1143 1 + v114 r_1270 1 + v114 r_2056 1 + v114 r_2286 1 + v114 r_2287 1 + v114 r_2288 1 + v114 r_2407 1 + v114 r_2408 1 + v114 r_2409 1 + v114 r_2469 -1 + v114 r_2470 -1 + v114 r_2471 -1 + v114 r_2472 -1 + v114 r_2585 -1 + v114 r_2586 -1 + v114 r_2587 -1 + v114 r_2639 1 + v114 r_2640 1 + v114 r_2641 1 + v114 r_2642 1 + v114 r_2643 1 + v114 r_2757 1 + v114 r_2758 1 + v114 r_2759 1 + v114 r_2808 1 + v115 r_13 1 + v115 r_179 1 + v115 r_312 -1 + v115 r_1368 1 + v115 r_1502 1 + v115 r_2079 1 + v115 r_2080 1 + v115 r_2081 1 + v115 r_2216 1 + v115 r_2217 1 + v115 r_2218 1 + v115 r_2849 1 + v115 r_2850 1 + v115 r_2965 1 + v115 r_2966 1 + v115 r_2967 1 + v116 r_13 1 + v116 r_195 1 + v116 r_327 -1 + v116 r_1369 1 + v116 r_1549 1 + v116 r_2079 1 + v116 r_2080 1 + v116 r_2081 1 + v116 r_2216 1 + v116 r_2217 1 + v116 r_2218 1 + v117 r_13 1 + v117 r_213 1 + v117 r_344 -1 + v117 r_1370 1 + v117 r_1609 1 + v117 r_2079 1 + v117 r_2080 1 + v117 r_2081 1 + v117 r_2216 1 + v117 r_2217 1 + v117 r_2218 1 + v118 r_13 1 + v118 r_231 1 + v118 r_361 -1 + v118 r_1371 1 + v118 r_1670 1 + v118 r_2079 1 + v118 r_2080 1 + v118 r_2081 1 + v118 r_2216 1 + v118 r_2217 1 + v118 r_2218 1 + v119 r_13 1 + v119 r_248 1 + v119 r_377 -1 + v119 r_1372 1 + v119 r_1737 1 + v119 r_2079 1 + v119 r_2080 1 + v119 r_2081 1 + v119 r_2216 1 + v119 r_2217 1 + v119 r_2218 1 + v119 r_2849 1 + v119 r_2850 1 + v119 r_2965 1 + v119 r_2966 1 + v119 r_2967 1 + v120 r_13 1 + v120 r_265 1 + v120 r_393 -1 + v120 r_1373 1 + v120 r_1792 1 + v120 r_2079 1 + v120 r_2080 1 + v120 r_2081 1 + v120 r_2216 1 + v120 r_2217 1 + v120 r_2218 1 + v121 r_13 1 + v121 r_283 1 + v121 r_410 -1 + v121 r_1374 1 + v121 r_1859 1 + v121 r_2079 1 + v121 r_2080 1 + v121 r_2081 1 + v121 r_2216 1 + v121 r_2217 1 + v121 r_2218 1 + v122 r_13 1 + v122 r_298 1 + v122 r_424 -1 + v122 r_1375 1 + v122 r_1925 1 + v122 r_2079 1 + v122 r_2080 1 + v122 r_2081 1 + v122 r_2216 1 + v122 r_2217 1 + v122 r_2218 1 + v122 r_2965 1 + v122 r_2966 1 + v122 r_2967 1 + v123 r_13 1 + v123 r_1978 1 + v123 r_2021 1 + v123 r_2039 1 + v123 r_2639 1 + v123 r_2640 1 + v123 r_2641 1 + v123 r_2642 1 + v123 r_2643 1 + v123 r_2757 1 + v123 r_2758 1 + v123 r_2759 1 + v123 r_2817 1 + v124 r_14 1 + v124 r_438 1 + v124 r_531 1 + v124 r_656 1 + v124 r_781 1 + v124 r_909 1 + v124 r_1015 1 + v124 r_1144 1 + v124 r_1271 1 + v124 r_2057 1 + v124 r_2287 1 + v124 r_2288 1 + v124 r_2289 1 + v124 r_2470 -1 + v124 r_2471 -1 + v124 r_2472 -1 + v124 r_2473 -1 + v124 r_2640 1 + v124 r_2641 1 + v124 r_2642 1 + v124 r_2643 1 + v125 r_14 1 + v125 r_180 1 + v125 r_313 -1 + v125 r_1368 1 + v125 r_1503 1 + v125 r_2080 1 + v125 r_2081 1 + v125 r_2082 1 + v125 r_2850 1 + v125 r_2851 1 + v125 r_2966 1 + v125 r_2967 1 + v125 r_2968 1 + v126 r_14 1 + v126 r_196 1 + v126 r_328 -1 + v126 r_1369 1 + v126 r_1550 1 + v126 r_2080 1 + v126 r_2081 1 + v126 r_2082 1 + v127 r_14 1 + v127 r_214 1 + v127 r_345 -1 + v127 r_1370 1 + v127 r_1610 1 + v127 r_2080 1 + v127 r_2081 1 + v127 r_2082 1 + v128 r_14 1 + v128 r_232 1 + v128 r_362 -1 + v128 r_1371 1 + v128 r_1671 1 + v128 r_2080 1 + v128 r_2081 1 + v128 r_2082 1 + v129 r_14 1 + v129 r_249 1 + v129 r_378 -1 + v129 r_1372 1 + v129 r_1738 1 + v129 r_2080 1 + v129 r_2081 1 + v129 r_2082 1 + v129 r_2850 1 + v129 r_2851 1 + v129 r_2966 1 + v129 r_2967 1 + v129 r_2968 1 + v130 r_14 1 + v130 r_266 1 + v130 r_394 -1 + v130 r_1373 1 + v130 r_1793 1 + v130 r_2080 1 + v130 r_2081 1 + v130 r_2082 1 + v131 r_14 1 + v131 r_284 1 + v131 r_411 -1 + v131 r_1374 1 + v131 r_1860 1 + v131 r_2080 1 + v131 r_2081 1 + v131 r_2082 1 + v132 r_14 1 + v132 r_299 1 + v132 r_425 -1 + v132 r_1375 1 + v132 r_1926 1 + v132 r_2080 1 + v132 r_2081 1 + v132 r_2082 1 + v132 r_2966 1 + v132 r_2967 1 + v132 r_2968 1 + v133 r_14 1 + v133 r_1979 1 + v133 r_2021 1 + v133 r_2040 1 + v133 r_2640 1 + v133 r_2641 1 + v133 r_2642 1 + v133 r_2643 1 + v134 r_15 1 + v134 r_532 1 + v134 r_657 1 + v134 r_782 1 + v134 r_910 1 + v134 r_1016 1 + v134 r_1145 1 + v134 r_1272 1 + v134 r_2058 1 + v134 r_2288 1 + v134 r_2289 1 + v134 r_2290 1 + v134 r_2408 1 + v134 r_2409 1 + v134 r_2471 -1 + v134 r_2472 -1 + v134 r_2473 -1 + v134 r_2586 -1 + v134 r_2587 -1 + v134 r_2641 1 + v134 r_2642 1 + v134 r_2643 1 + v134 r_2758 1 + v134 r_2759 1 + v134 r_2808 1 + v135 r_15 1 + v135 r_197 1 + v135 r_329 -1 + v135 r_1369 1 + v135 r_1551 1 + v135 r_2081 1 + v135 r_2082 1 + v135 r_2083 1 + v135 r_2217 1 + v135 r_2218 1 + v136 r_15 1 + v136 r_215 1 + v136 r_346 -1 + v136 r_1370 1 + v136 r_1611 1 + v136 r_2081 1 + v136 r_2082 1 + v136 r_2083 1 + v136 r_2217 1 + v136 r_2218 1 + v137 r_15 1 + v137 r_233 1 + v137 r_363 -1 + v137 r_1371 1 + v137 r_1672 1 + v137 r_2081 1 + v137 r_2082 1 + v137 r_2083 1 + v137 r_2217 1 + v137 r_2218 1 + v138 r_15 1 + v138 r_250 1 + v138 r_379 -1 + v138 r_1372 1 + v138 r_1739 1 + v138 r_2081 1 + v138 r_2082 1 + v138 r_2083 1 + v138 r_2217 1 + v138 r_2218 1 + v138 r_2851 1 + v138 r_2852 1 + v138 r_2967 1 + v138 r_2968 1 + v138 r_2969 1 + v139 r_15 1 + v139 r_267 1 + v139 r_395 -1 + v139 r_1373 1 + v139 r_1794 1 + v139 r_2081 1 + v139 r_2082 1 + v139 r_2083 1 + v139 r_2217 1 + v139 r_2218 1 + v140 r_15 1 + v140 r_285 1 + v140 r_412 -1 + v140 r_1374 1 + v140 r_1861 1 + v140 r_2081 1 + v140 r_2082 1 + v140 r_2083 1 + v140 r_2217 1 + v140 r_2218 1 + v141 r_15 1 + v141 r_300 1 + v141 r_426 -1 + v141 r_1375 1 + v141 r_1927 1 + v141 r_2081 1 + v141 r_2082 1 + v141 r_2083 1 + v141 r_2217 1 + v141 r_2218 1 + v141 r_2967 1 + v141 r_2968 1 + v141 r_2969 1 + v142 r_16 1 + v142 r_439 1 + v142 r_533 1 + v142 r_658 1 + v142 r_783 1 + v142 r_911 1 + v142 r_1017 1 + v142 r_1146 1 + v142 r_1273 1 + v142 r_2059 1 + v142 r_2061 1 + v142 r_2289 1 + v142 r_2290 1 + v142 r_2472 -1 + v142 r_2473 -1 + v142 r_2642 1 + v142 r_2643 1 + v143 r_16 1 + v143 r_181 1 + v143 r_314 -1 + v143 r_1368 1 + v143 r_1504 1 + v143 r_2082 1 + v143 r_2083 1 + v143 r_2852 1 + v143 r_2853 1 + v143 r_2968 1 + v143 r_2969 1 + v144 r_16 1 + v144 r_198 1 + v144 r_330 -1 + v144 r_1369 1 + v144 r_1552 1 + v144 r_2082 1 + v144 r_2083 1 + v145 r_16 1 + v145 r_216 1 + v145 r_347 -1 + v145 r_1370 1 + v145 r_1612 1 + v145 r_2082 1 + v145 r_2083 1 + v146 r_16 1 + v146 r_234 1 + v146 r_364 -1 + v146 r_1371 1 + v146 r_1673 1 + v146 r_2082 1 + v146 r_2083 1 + v147 r_16 1 + v147 r_251 1 + v147 r_380 -1 + v147 r_1372 1 + v147 r_1740 1 + v147 r_2082 1 + v147 r_2083 1 + v147 r_2852 1 + v147 r_2853 1 + v147 r_2968 1 + v147 r_2969 1 + v148 r_16 1 + v148 r_268 1 + v148 r_396 -1 + v148 r_1373 1 + v148 r_1795 1 + v148 r_2082 1 + v148 r_2083 1 + v149 r_16 1 + v149 r_286 1 + v149 r_413 -1 + v149 r_1374 1 + v149 r_1862 1 + v149 r_2082 1 + v149 r_2083 1 + v150 r_16 1 + v150 r_1980 1 + v150 r_2021 1 + v150 r_2041 1 + v150 r_2061 1 + v150 r_2642 1 + v150 r_2643 1 + v151 r_17 1 + v151 r_534 1 + v151 r_659 1 + v151 r_784 1 + v151 r_1018 1 + v151 r_1147 1 + v151 r_2060 1 + v151 r_2061 1 + v151 r_2290 1 + v151 r_2409 1 + v151 r_2473 -1 + v151 r_2587 -1 + v151 r_2643 1 + v151 r_2759 1 + v151 r_2808 1 + v151 r_3051 1 + v152 r_17 1 + v152 r_199 1 + v152 r_331 -1 + v152 r_1369 1 + v152 r_1553 1 + v152 r_2083 1 + v152 r_2218 1 + v153 r_17 1 + v153 r_217 1 + v153 r_348 -1 + v153 r_1370 1 + v153 r_1613 1 + v153 r_2083 1 + v153 r_2218 1 + v153 r_2832 1 + v154 r_17 1 + v154 r_235 1 + v154 r_365 -1 + v154 r_1371 1 + v154 r_1674 1 + v154 r_2083 1 + v154 r_2218 1 + v155 r_17 1 + v155 r_269 1 + v155 r_397 -1 + v155 r_1373 1 + v155 r_1796 1 + v155 r_2083 1 + v155 r_2218 1 + v156 r_17 1 + v156 r_287 1 + v156 r_414 -1 + v156 r_1374 1 + v156 r_1863 1 + v156 r_2083 1 + v156 r_2218 1 + v157 r_17 1 + v157 r_301 1 + v157 r_1375 1 + v157 r_1928 1 + v157 r_2083 1 + v157 r_2218 1 + v157 r_2969 1 + v158 r_17 1 + v158 r_1981 1 + v158 r_2021 1 + v158 r_2042 1 + v158 r_2061 1 + v158 r_2643 1 + v158 r_2759 1 + v158 r_2817 1 + v158 r_3051 1 + v159 r_18 1 + v159 r_150 1 + v159 r_1376 1 + v159 r_1498 -1 + v159 r_2084 1 + v159 r_2954 1 + v160 r_18 1 + v160 r_785 1 + v160 r_1019 1 + v160 r_1148 1 + v160 r_2043 1 + v160 r_2291 1 + v160 r_2474 -1 + v160 r_2644 1 + v161 r_18 1 + v161 r_182 1 + v161 r_1377 1 + v161 r_1505 -1 + v161 r_2084 1 + v161 r_2970 1 + v162 r_18 1 + v162 r_200 1 + v162 r_1378 1 + v162 r_1512 -1 + v162 r_2084 1 + v162 r_2986 1 + v163 r_18 1 + v163 r_218 1 + v163 r_466 -1 + v163 r_1379 1 + v163 r_1519 -1 + v163 r_2084 1 + v163 r_3002 1 + v164 r_18 1 + v164 r_252 1 + v164 r_480 -1 + v164 r_1380 1 + v164 r_1526 -1 + v164 r_2084 1 + v164 r_3018 1 + v165 r_18 1 + v165 r_270 1 + v165 r_494 -1 + v165 r_1381 1 + v165 r_1533 -1 + v165 r_2084 1 + v165 r_3034 1 + v166 r_19 1 + v166 r_151 1 + v166 r_427 -1 + v166 r_1376 1 + v166 r_1499 -1 + v166 r_2084 1 + v166 r_2085 1 + v166 r_2219 1 + v166 r_2954 1 + v166 r_2955 1 + v167 r_19 1 + v167 r_302 1 + v167 r_535 1 + v167 r_660 1 + v167 r_786 1 + v167 r_1020 1 + v167 r_1149 1 + v167 r_1274 1 + v167 r_2044 1 + v167 r_2291 1 + v167 r_2292 1 + v167 r_2410 1 + v167 r_2474 -1 + v167 r_2475 -1 + v167 r_2588 -1 + v167 r_2644 1 + v167 r_2645 1 + v167 r_2760 1 + v167 r_2809 1 + v167 r_2825 1 + v168 r_19 1 + v168 r_183 1 + v168 r_440 -1 + v168 r_1377 1 + v168 r_1506 -1 + v168 r_2084 1 + v168 r_2085 1 + v168 r_2219 1 + v168 r_2970 1 + v168 r_2971 1 + v169 r_19 1 + v169 r_201 1 + v169 r_453 -1 + v169 r_1378 1 + v169 r_1513 -1 + v169 r_2084 1 + v169 r_2085 1 + v169 r_2219 1 + v169 r_2986 1 + v169 r_2987 1 + v170 r_19 1 + v170 r_219 1 + v170 r_467 -1 + v170 r_1379 1 + v170 r_1520 -1 + v170 r_2084 1 + v170 r_2085 1 + v170 r_2219 1 + v170 r_3002 1 + v170 r_3003 1 + v171 r_19 1 + v171 r_253 1 + v171 r_481 -1 + v171 r_1380 1 + v171 r_1527 -1 + v171 r_2084 1 + v171 r_2085 1 + v171 r_2219 1 + v171 r_3018 1 + v171 r_3019 1 + v172 r_19 1 + v172 r_271 1 + v172 r_495 -1 + v172 r_1381 1 + v172 r_1534 -1 + v172 r_2084 1 + v172 r_2085 1 + v172 r_2219 1 + v172 r_3034 1 + v172 r_3035 1 + v173 r_19 1 + v173 r_288 1 + v173 r_508 -1 + v173 r_1382 1 + v173 r_1540 -1 + v173 r_2084 1 + v173 r_2085 1 + v173 r_2219 1 + v174 r_20 1 + v174 r_152 1 + v174 r_428 -1 + v174 r_1376 1 + v174 r_1500 -1 + v174 r_2084 1 + v174 r_2085 1 + v174 r_2086 1 + v174 r_2954 1 + v174 r_2955 1 + v174 r_2956 1 + v175 r_20 1 + v175 r_303 1 + v175 r_536 1 + v175 r_661 1 + v175 r_787 1 + v175 r_1021 1 + v175 r_1150 1 + v175 r_1275 1 + v175 r_2045 1 + v175 r_2291 1 + v175 r_2292 1 + v175 r_2293 1 + v175 r_2474 -1 + v175 r_2475 -1 + v175 r_2476 -1 + v175 r_2644 1 + v175 r_2645 1 + v175 r_2646 1 + v176 r_20 1 + v176 r_184 1 + v176 r_441 -1 + v176 r_1377 1 + v176 r_1507 -1 + v176 r_2084 1 + v176 r_2085 1 + v176 r_2086 1 + v176 r_2970 1 + v176 r_2971 1 + v176 r_2972 1 + v177 r_20 1 + v177 r_202 1 + v177 r_454 -1 + v177 r_1378 1 + v177 r_1514 -1 + v177 r_2084 1 + v177 r_2085 1 + v177 r_2086 1 + v177 r_2986 1 + v177 r_2987 1 + v177 r_2988 1 + v178 r_20 1 + v178 r_220 1 + v178 r_468 -1 + v178 r_1379 1 + v178 r_1521 -1 + v178 r_2084 1 + v178 r_2085 1 + v178 r_2086 1 + v178 r_3002 1 + v178 r_3003 1 + v178 r_3004 1 + v179 r_20 1 + v179 r_254 1 + v179 r_482 -1 + v179 r_1380 1 + v179 r_1528 -1 + v179 r_2084 1 + v179 r_2085 1 + v179 r_2086 1 + v179 r_3018 1 + v179 r_3019 1 + v179 r_3020 1 + v180 r_20 1 + v180 r_272 1 + v180 r_496 -1 + v180 r_1381 1 + v180 r_1535 -1 + v180 r_2084 1 + v180 r_2085 1 + v180 r_2086 1 + v180 r_3034 1 + v180 r_3035 1 + v180 r_3036 1 + v181 r_20 1 + v181 r_289 1 + v181 r_509 -1 + v181 r_1382 1 + v181 r_1541 -1 + v181 r_2084 1 + v181 r_2085 1 + v181 r_2086 1 + v182 r_21 1 + v182 r_153 1 + v182 r_429 -1 + v182 r_1376 1 + v182 r_1501 -1 + v182 r_2085 1 + v182 r_2086 1 + v182 r_2087 1 + v182 r_2219 1 + v182 r_2220 1 + v182 r_2955 1 + v182 r_2956 1 + v182 r_2957 1 + v183 r_21 1 + v183 r_304 1 + v183 r_537 1 + v183 r_662 1 + v183 r_788 1 + v183 r_1022 1 + v183 r_1151 1 + v183 r_1276 1 + v183 r_2046 1 + v183 r_2292 1 + v183 r_2293 1 + v183 r_2294 1 + v183 r_2410 1 + v183 r_2411 1 + v183 r_2474 -1 + v183 r_2475 -1 + v183 r_2476 -1 + v183 r_2477 -1 + v183 r_2588 -1 + v183 r_2589 -1 + v183 r_2644 1 + v183 r_2645 1 + v183 r_2646 1 + v183 r_2647 1 + v183 r_2760 1 + v183 r_2761 1 + v183 r_2809 1 + v183 r_2825 1 + v184 r_21 1 + v184 r_185 1 + v184 r_442 -1 + v184 r_1377 1 + v184 r_1508 -1 + v184 r_2085 1 + v184 r_2086 1 + v184 r_2087 1 + v184 r_2219 1 + v184 r_2220 1 + v184 r_2971 1 + v184 r_2972 1 + v184 r_2973 1 + v185 r_21 1 + v185 r_203 1 + v185 r_455 -1 + v185 r_1378 1 + v185 r_1515 -1 + v185 r_2085 1 + v185 r_2086 1 + v185 r_2087 1 + v185 r_2219 1 + v185 r_2220 1 + v185 r_2987 1 + v185 r_2988 1 + v185 r_2989 1 + v186 r_21 1 + v186 r_221 1 + v186 r_469 -1 + v186 r_1379 1 + v186 r_1522 -1 + v186 r_2085 1 + v186 r_2086 1 + v186 r_2087 1 + v186 r_2219 1 + v186 r_2220 1 + v186 r_3003 1 + v186 r_3004 1 + v186 r_3005 1 + v187 r_21 1 + v187 r_255 1 + v187 r_483 -1 + v187 r_1380 1 + v187 r_1529 -1 + v187 r_2085 1 + v187 r_2086 1 + v187 r_2087 1 + v187 r_2219 1 + v187 r_2220 1 + v187 r_3019 1 + v187 r_3020 1 + v187 r_3021 1 + v188 r_21 1 + v188 r_273 1 + v188 r_497 -1 + v188 r_1381 1 + v188 r_1536 -1 + v188 r_2085 1 + v188 r_2086 1 + v188 r_2087 1 + v188 r_2219 1 + v188 r_2220 1 + v188 r_3035 1 + v188 r_3036 1 + v188 r_3037 1 + v189 r_21 1 + v189 r_290 1 + v189 r_510 -1 + v189 r_1382 1 + v189 r_1542 -1 + v189 r_2085 1 + v189 r_2086 1 + v189 r_2087 1 + v189 r_2219 1 + v189 r_2220 1 + v190 r_22 1 + v190 r_154 1 + v190 r_430 -1 + v190 r_1376 1 + v190 r_1502 -1 + v190 r_2086 1 + v190 r_2087 1 + v190 r_2088 1 + v190 r_2956 1 + v190 r_2957 1 + v190 r_2958 1 + v191 r_22 1 + v191 r_305 1 + v191 r_538 1 + v191 r_663 1 + v191 r_789 1 + v191 r_1023 1 + v191 r_1152 1 + v191 r_1277 1 + v191 r_2047 1 + v191 r_2293 1 + v191 r_2294 1 + v191 r_2475 -1 + v191 r_2476 -1 + v191 r_2477 -1 + v191 r_2478 -1 + v191 r_2644 1 + v191 r_2645 1 + v191 r_2646 1 + v191 r_2647 1 + v191 r_2648 1 + v192 r_22 1 + v192 r_186 1 + v192 r_443 -1 + v192 r_1377 1 + v192 r_1509 -1 + v192 r_2086 1 + v192 r_2087 1 + v192 r_2088 1 + v192 r_2972 1 + v192 r_2973 1 + v192 r_2974 1 + v193 r_22 1 + v193 r_204 1 + v193 r_456 -1 + v193 r_1378 1 + v193 r_1516 -1 + v193 r_2086 1 + v193 r_2087 1 + v193 r_2088 1 + v193 r_2988 1 + v193 r_2989 1 + v193 r_2990 1 + v194 r_22 1 + v194 r_222 1 + v194 r_470 -1 + v194 r_1379 1 + v194 r_1523 -1 + v194 r_2086 1 + v194 r_2087 1 + v194 r_2088 1 + v194 r_3004 1 + v194 r_3005 1 + v194 r_3006 1 + v195 r_22 1 + v195 r_256 1 + v195 r_484 -1 + v195 r_1380 1 + v195 r_1530 -1 + v195 r_2086 1 + v195 r_2087 1 + v195 r_2088 1 + v195 r_3020 1 + v195 r_3021 1 + v195 r_3022 1 + v196 r_22 1 + v196 r_274 1 + v196 r_498 -1 + v196 r_1381 1 + v196 r_1537 -1 + v196 r_2086 1 + v196 r_2087 1 + v196 r_2088 1 + v196 r_3036 1 + v196 r_3037 1 + v196 r_3038 1 + v197 r_22 1 + v197 r_291 1 + v197 r_511 -1 + v197 r_1382 1 + v197 r_1543 -1 + v197 r_2086 1 + v197 r_2087 1 + v197 r_2088 1 + v198 r_23 1 + v198 r_155 1 + v198 r_431 -1 + v198 r_1376 1 + v198 r_1503 -1 + v198 r_2087 1 + v198 r_2088 1 + v198 r_2089 1 + v198 r_2219 1 + v198 r_2220 1 + v198 r_2221 1 + v198 r_2957 1 + v198 r_2958 1 + v198 r_2959 1 + v199 r_23 1 + v199 r_306 1 + v199 r_539 1 + v199 r_664 1 + v199 r_790 1 + v199 r_1024 1 + v199 r_1153 1 + v199 r_1278 1 + v199 r_2048 1 + v199 r_2294 1 + v199 r_2410 1 + v199 r_2411 1 + v199 r_2412 1 + v199 r_2476 -1 + v199 r_2477 -1 + v199 r_2478 -1 + v199 r_2479 -1 + v199 r_2588 -1 + v199 r_2589 -1 + v199 r_2590 -1 + v199 r_2645 1 + v199 r_2646 1 + v199 r_2647 1 + v199 r_2648 1 + v199 r_2649 1 + v199 r_2760 1 + v199 r_2761 1 + v199 r_2762 1 + v199 r_2809 1 + v199 r_2825 1 + v200 r_23 1 + v200 r_187 1 + v200 r_444 -1 + v200 r_1377 1 + v200 r_1510 -1 + v200 r_2087 1 + v200 r_2088 1 + v200 r_2089 1 + v200 r_2219 1 + v200 r_2220 1 + v200 r_2221 1 + v200 r_2973 1 + v200 r_2974 1 + v200 r_2975 1 + v201 r_23 1 + v201 r_205 1 + v201 r_457 -1 + v201 r_1378 1 + v201 r_1517 -1 + v201 r_2087 1 + v201 r_2088 1 + v201 r_2089 1 + v201 r_2219 1 + v201 r_2220 1 + v201 r_2221 1 + v201 r_2989 1 + v201 r_2990 1 + v201 r_2991 1 + v202 r_23 1 + v202 r_223 1 + v202 r_471 -1 + v202 r_1379 1 + v202 r_1524 -1 + v202 r_2087 1 + v202 r_2088 1 + v202 r_2089 1 + v202 r_2219 1 + v202 r_2220 1 + v202 r_2221 1 + v202 r_3005 1 + v202 r_3006 1 + v202 r_3007 1 + v203 r_23 1 + v203 r_257 1 + v203 r_485 -1 + v203 r_1380 1 + v203 r_1531 -1 + v203 r_2087 1 + v203 r_2088 1 + v203 r_2089 1 + v203 r_2219 1 + v203 r_2220 1 + v203 r_2221 1 + v203 r_3021 1 + v203 r_3022 1 + v203 r_3023 1 + v204 r_23 1 + v204 r_275 1 + v204 r_499 -1 + v204 r_1381 1 + v204 r_1538 -1 + v204 r_2087 1 + v204 r_2088 1 + v204 r_2089 1 + v204 r_2219 1 + v204 r_2220 1 + v204 r_2221 1 + v204 r_3037 1 + v204 r_3038 1 + v204 r_3039 1 + v205 r_23 1 + v205 r_292 1 + v205 r_512 -1 + v205 r_1382 1 + v205 r_1544 -1 + v205 r_2087 1 + v205 r_2088 1 + v205 r_2089 1 + v205 r_2219 1 + v205 r_2220 1 + v205 r_2221 1 + v206 r_24 1 + v206 r_157 1 + v206 r_432 -1 + v206 r_1376 1 + v206 r_2089 1 + v206 r_2090 1 + v206 r_2091 1 + v206 r_2220 1 + v206 r_2221 1 + v206 r_2222 1 + v206 r_2959 1 + v206 r_2960 1 + v206 r_2961 1 + v207 r_24 1 + v207 r_307 1 + v207 r_540 1 + v207 r_665 1 + v207 r_791 1 + v207 r_1025 1 + v207 r_1154 1 + v207 r_2050 1 + v207 r_2295 1 + v207 r_2411 1 + v207 r_2412 1 + v207 r_2413 1 + v207 r_2478 -1 + v207 r_2479 -1 + v207 r_2480 -1 + v207 r_2481 -1 + v207 r_2588 -1 + v207 r_2589 -1 + v207 r_2590 -1 + v207 r_2591 -1 + v207 r_2647 1 + v207 r_2648 1 + v207 r_2649 1 + v207 r_2650 1 + v207 r_2651 1 + v207 r_2760 1 + v207 r_2761 1 + v207 r_2762 1 + v207 r_2763 1 + v207 r_2809 1 + v207 r_2825 1 + v208 r_24 1 + v208 r_189 1 + v208 r_445 -1 + v208 r_1377 1 + v208 r_2089 1 + v208 r_2090 1 + v208 r_2091 1 + v208 r_2220 1 + v208 r_2221 1 + v208 r_2222 1 + v208 r_2975 1 + v208 r_2976 1 + v208 r_2977 1 + v209 r_24 1 + v209 r_207 1 + v209 r_458 -1 + v209 r_1378 1 + v209 r_2089 1 + v209 r_2090 1 + v209 r_2091 1 + v209 r_2220 1 + v209 r_2221 1 + v209 r_2222 1 + v209 r_2991 1 + v209 r_2992 1 + v209 r_2993 1 + v210 r_24 1 + v210 r_225 1 + v210 r_472 -1 + v210 r_1379 1 + v210 r_1675 1 + v210 r_2089 1 + v210 r_2090 1 + v210 r_2091 1 + v210 r_2220 1 + v210 r_2221 1 + v210 r_2222 1 + v210 r_3007 1 + v210 r_3008 1 + v210 r_3009 1 + v211 r_24 1 + v211 r_259 1 + v211 r_486 -1 + v211 r_1380 1 + v211 r_1797 1 + v211 r_2089 1 + v211 r_2090 1 + v211 r_2091 1 + v211 r_2220 1 + v211 r_2221 1 + v211 r_2222 1 + v211 r_3023 1 + v211 r_3024 1 + v211 r_3025 1 + v212 r_24 1 + v212 r_277 1 + v212 r_500 -1 + v212 r_1381 1 + v212 r_1864 1 + v212 r_2089 1 + v212 r_2090 1 + v212 r_2091 1 + v212 r_2220 1 + v212 r_2221 1 + v212 r_2222 1 + v212 r_3039 1 + v212 r_3040 1 + v212 r_3041 1 + v213 r_25 1 + v213 r_158 1 + v213 r_433 -1 + v213 r_1376 1 + v213 r_1438 1 + v213 r_2090 1 + v213 r_2091 1 + v213 r_2092 1 + v213 r_2960 1 + v213 r_2961 1 + v213 r_2962 1 + v214 r_25 1 + v214 r_308 1 + v214 r_541 1 + v214 r_666 1 + v214 r_792 1 + v214 r_1026 1 + v214 r_1155 1 + v214 r_1279 1 + v214 r_2051 1 + v214 r_2295 1 + v214 r_2479 -1 + v214 r_2480 -1 + v214 r_2481 -1 + v214 r_2482 -1 + v214 r_2648 1 + v214 r_2649 1 + v214 r_2650 1 + v214 r_2651 1 + v214 r_2652 1 + v215 r_25 1 + v215 r_190 1 + v215 r_446 -1 + v215 r_1377 1 + v215 r_1554 1 + v215 r_2090 1 + v215 r_2091 1 + v215 r_2092 1 + v215 r_2976 1 + v215 r_2977 1 + v215 r_2978 1 + v216 r_25 1 + v216 r_208 1 + v216 r_459 -1 + v216 r_1378 1 + v216 r_1614 1 + v216 r_2090 1 + v216 r_2091 1 + v216 r_2092 1 + v216 r_2992 1 + v216 r_2993 1 + v216 r_2994 1 + v217 r_25 1 + v217 r_226 1 + v217 r_473 -1 + v217 r_1379 1 + v217 r_1676 1 + v217 r_2090 1 + v217 r_2091 1 + v217 r_2092 1 + v217 r_3008 1 + v217 r_3009 1 + v217 r_3010 1 + v218 r_25 1 + v218 r_260 1 + v218 r_487 -1 + v218 r_1380 1 + v218 r_1798 1 + v218 r_2090 1 + v218 r_2091 1 + v218 r_2092 1 + v218 r_3024 1 + v218 r_3025 1 + v218 r_3026 1 + v219 r_25 1 + v219 r_278 1 + v219 r_501 -1 + v219 r_1381 1 + v219 r_1865 1 + v219 r_2090 1 + v219 r_2091 1 + v219 r_2092 1 + v219 r_3040 1 + v219 r_3041 1 + v219 r_3042 1 + v220 r_25 1 + v220 r_294 1 + v220 r_513 -1 + v220 r_1382 1 + v220 r_1929 1 + v220 r_2090 1 + v220 r_2091 1 + v220 r_2092 1 + v221 r_25 1 + v221 r_2022 1 + v221 r_2034 1 + v221 r_2648 1 + v221 r_2649 1 + v221 r_2650 1 + v221 r_2651 1 + v221 r_2652 1 + v222 r_26 1 + v222 r_159 1 + v222 r_434 -1 + v222 r_1376 1 + v222 r_1504 -1 + v222 r_2091 1 + v222 r_2092 1 + v222 r_2093 1 + v222 r_2221 1 + v222 r_2222 1 + v222 r_2223 1 + v222 r_2961 1 + v222 r_2962 1 + v222 r_2963 1 + v223 r_26 1 + v223 r_309 1 + v223 r_542 1 + v223 r_667 1 + v223 r_793 1 + v223 r_1027 1 + v223 r_1156 1 + v223 r_2052 1 + v223 r_2295 1 + v223 r_2412 1 + v223 r_2413 1 + v223 r_2414 1 + v223 r_2480 -1 + v223 r_2481 -1 + v223 r_2482 -1 + v223 r_2483 -1 + v223 r_2589 -1 + v223 r_2590 -1 + v223 r_2591 -1 + v223 r_2592 -1 + v223 r_2649 1 + v223 r_2650 1 + v223 r_2651 1 + v223 r_2652 1 + v223 r_2653 1 + v223 r_2761 1 + v223 r_2762 1 + v223 r_2763 1 + v223 r_2764 1 + v223 r_2809 1 + v223 r_2825 1 + v224 r_26 1 + v224 r_191 1 + v224 r_447 -1 + v224 r_1377 1 + v224 r_1511 -1 + v224 r_2091 1 + v224 r_2092 1 + v224 r_2093 1 + v224 r_2221 1 + v224 r_2222 1 + v224 r_2223 1 + v224 r_2977 1 + v224 r_2978 1 + v224 r_2979 1 + v225 r_26 1 + v225 r_209 1 + v225 r_460 -1 + v225 r_1378 1 + v225 r_1518 -1 + v225 r_2091 1 + v225 r_2092 1 + v225 r_2093 1 + v225 r_2221 1 + v225 r_2222 1 + v225 r_2223 1 + v225 r_2993 1 + v225 r_2994 1 + v225 r_2995 1 + v226 r_26 1 + v226 r_227 1 + v226 r_474 -1 + v226 r_1379 1 + v226 r_1525 -1 + v226 r_2091 1 + v226 r_2092 1 + v226 r_2093 1 + v226 r_2221 1 + v226 r_2222 1 + v226 r_2223 1 + v226 r_3009 1 + v226 r_3010 1 + v226 r_3011 1 + v227 r_26 1 + v227 r_261 1 + v227 r_488 -1 + v227 r_1380 1 + v227 r_1532 -1 + v227 r_2091 1 + v227 r_2092 1 + v227 r_2093 1 + v227 r_2221 1 + v227 r_2222 1 + v227 r_2223 1 + v227 r_3025 1 + v227 r_3026 1 + v227 r_3027 1 + v228 r_26 1 + v228 r_279 1 + v228 r_502 -1 + v228 r_1381 1 + v228 r_1539 -1 + v228 r_2091 1 + v228 r_2092 1 + v228 r_2093 1 + v228 r_2221 1 + v228 r_2222 1 + v228 r_2223 1 + v228 r_3041 1 + v228 r_3042 1 + v228 r_3043 1 + v229 r_26 1 + v229 r_295 1 + v229 r_1382 1 + v229 r_1545 -1 + v229 r_2091 1 + v229 r_2092 1 + v229 r_2093 1 + v229 r_2221 1 + v229 r_2222 1 + v229 r_2223 1 + v230 r_27 1 + v230 r_161 1 + v230 r_435 -1 + v230 r_1376 1 + v230 r_1439 1 + v230 r_2093 1 + v230 r_2094 1 + v230 r_2095 1 + v230 r_2222 1 + v230 r_2223 1 + v230 r_2224 1 + v230 r_2963 1 + v230 r_2964 1 + v230 r_2965 1 + v231 r_27 1 + v231 r_310 1 + v231 r_543 1 + v231 r_668 1 + v231 r_794 1 + v231 r_1028 1 + v231 r_1157 1 + v231 r_1280 1 + v231 r_2054 1 + v231 r_2296 1 + v231 r_2413 1 + v231 r_2414 1 + v231 r_2482 -1 + v231 r_2483 -1 + v231 r_2484 -1 + v231 r_2485 -1 + v231 r_2590 -1 + v231 r_2591 -1 + v231 r_2592 -1 + v231 r_2651 1 + v231 r_2652 1 + v231 r_2653 1 + v231 r_2654 1 + v231 r_2655 1 + v231 r_2762 1 + v231 r_2763 1 + v231 r_2764 1 + v231 r_2765 1 + v231 r_2809 1 + v232 r_27 1 + v232 r_193 1 + v232 r_448 -1 + v232 r_1377 1 + v232 r_1555 1 + v232 r_2093 1 + v232 r_2094 1 + v232 r_2095 1 + v232 r_2222 1 + v232 r_2223 1 + v232 r_2224 1 + v232 r_2979 1 + v232 r_2980 1 + v232 r_2981 1 + v233 r_27 1 + v233 r_211 1 + v233 r_461 -1 + v233 r_1378 1 + v233 r_1615 1 + v233 r_2093 1 + v233 r_2094 1 + v233 r_2095 1 + v233 r_2222 1 + v233 r_2223 1 + v233 r_2224 1 + v233 r_2836 1 + v233 r_2995 1 + v233 r_2996 1 + v233 r_2997 1 + v234 r_27 1 + v234 r_229 1 + v234 r_475 -1 + v234 r_1379 1 + v234 r_1677 1 + v234 r_2093 1 + v234 r_2094 1 + v234 r_2095 1 + v234 r_2222 1 + v234 r_2223 1 + v234 r_2224 1 + v234 r_3011 1 + v234 r_3012 1 + v234 r_3013 1 + v235 r_27 1 + v235 r_263 1 + v235 r_489 -1 + v235 r_1380 1 + v235 r_1799 1 + v235 r_2093 1 + v235 r_2094 1 + v235 r_2095 1 + v235 r_2222 1 + v235 r_2223 1 + v235 r_2224 1 + v235 r_3027 1 + v235 r_3028 1 + v235 r_3029 1 + v236 r_27 1 + v236 r_281 1 + v236 r_503 -1 + v236 r_1381 1 + v236 r_1866 1 + v236 r_2093 1 + v236 r_2094 1 + v236 r_2095 1 + v236 r_2222 1 + v236 r_2223 1 + v236 r_2224 1 + v236 r_3043 1 + v236 r_3044 1 + v236 r_3045 1 + v237 r_27 1 + v237 r_296 1 + v237 r_514 -1 + v237 r_1382 1 + v237 r_1930 1 + v237 r_2093 1 + v237 r_2094 1 + v237 r_2095 1 + v237 r_2222 1 + v237 r_2223 1 + v237 r_2224 1 + v237 r_2834 1 + v238 r_28 1 + v238 r_162 1 + v238 r_436 -1 + v238 r_1376 1 + v238 r_1440 1 + v238 r_2094 1 + v238 r_2095 1 + v238 r_2096 1 + v238 r_2964 1 + v238 r_2965 1 + v238 r_2966 1 + v239 r_28 1 + v239 r_311 1 + v239 r_544 1 + v239 r_669 1 + v239 r_795 1 + v239 r_1029 1 + v239 r_1158 1 + v239 r_1281 1 + v239 r_2055 1 + v239 r_2296 1 + v239 r_2297 1 + v239 r_2483 -1 + v239 r_2484 -1 + v239 r_2485 -1 + v239 r_2486 -1 + v239 r_2652 1 + v239 r_2653 1 + v239 r_2654 1 + v239 r_2655 1 + v239 r_2656 1 + v240 r_28 1 + v240 r_194 1 + v240 r_449 -1 + v240 r_1377 1 + v240 r_1556 1 + v240 r_2094 1 + v240 r_2095 1 + v240 r_2096 1 + v240 r_2980 1 + v240 r_2981 1 + v240 r_2982 1 + v241 r_28 1 + v241 r_212 1 + v241 r_462 -1 + v241 r_1378 1 + v241 r_1616 1 + v241 r_2094 1 + v241 r_2095 1 + v241 r_2096 1 + v241 r_2836 1 + v241 r_2996 1 + v241 r_2997 1 + v241 r_2998 1 + v242 r_28 1 + v242 r_230 1 + v242 r_476 -1 + v242 r_1379 1 + v242 r_1678 1 + v242 r_2094 1 + v242 r_2095 1 + v242 r_2096 1 + v242 r_3012 1 + v242 r_3013 1 + v242 r_3014 1 + v243 r_28 1 + v243 r_264 1 + v243 r_490 -1 + v243 r_1380 1 + v243 r_1800 1 + v243 r_2094 1 + v243 r_2095 1 + v243 r_2096 1 + v243 r_3028 1 + v243 r_3029 1 + v243 r_3030 1 + v244 r_28 1 + v244 r_282 1 + v244 r_504 -1 + v244 r_1381 1 + v244 r_1867 1 + v244 r_2094 1 + v244 r_2095 1 + v244 r_2096 1 + v244 r_3044 1 + v244 r_3045 1 + v244 r_3046 1 + v245 r_28 1 + v245 r_297 1 + v245 r_515 -1 + v245 r_1382 1 + v245 r_1931 1 + v245 r_2094 1 + v245 r_2095 1 + v245 r_2096 1 + v245 r_2834 1 + v246 r_28 1 + v246 r_2022 1 + v246 r_2038 1 + v246 r_2652 1 + v246 r_2653 1 + v246 r_2654 1 + v246 r_2655 1 + v246 r_2656 1 + v247 r_29 1 + v247 r_163 1 + v247 r_437 -1 + v247 r_1376 1 + v247 r_1441 1 + v247 r_2095 1 + v247 r_2096 1 + v247 r_2097 1 + v247 r_2223 1 + v247 r_2224 1 + v247 r_2225 1 + v247 r_2965 1 + v247 r_2966 1 + v247 r_2967 1 + v248 r_29 1 + v248 r_312 1 + v248 r_545 1 + v248 r_670 1 + v248 r_796 1 + v248 r_1030 1 + v248 r_1159 1 + v248 r_1282 1 + v248 r_2056 1 + v248 r_2296 1 + v248 r_2297 1 + v248 r_2414 1 + v248 r_2484 -1 + v248 r_2485 -1 + v248 r_2486 -1 + v248 r_2487 -1 + v248 r_2591 -1 + v248 r_2592 -1 + v248 r_2653 1 + v248 r_2654 1 + v248 r_2655 1 + v248 r_2656 1 + v248 r_2657 1 + v248 r_2763 1 + v248 r_2764 1 + v248 r_2765 1 + v248 r_2809 1 + v249 r_29 1 + v249 r_195 1 + v249 r_450 -1 + v249 r_1377 1 + v249 r_1557 1 + v249 r_2095 1 + v249 r_2096 1 + v249 r_2097 1 + v249 r_2223 1 + v249 r_2224 1 + v249 r_2225 1 + v249 r_2981 1 + v249 r_2982 1 + v249 r_2983 1 + v250 r_29 1 + v250 r_213 1 + v250 r_463 -1 + v250 r_1378 1 + v250 r_1617 1 + v250 r_2095 1 + v250 r_2096 1 + v250 r_2097 1 + v250 r_2223 1 + v250 r_2224 1 + v250 r_2225 1 + v250 r_2836 1 + v250 r_2997 1 + v250 r_2998 1 + v250 r_2999 1 + v251 r_29 1 + v251 r_231 1 + v251 r_477 -1 + v251 r_1379 1 + v251 r_1679 1 + v251 r_2095 1 + v251 r_2096 1 + v251 r_2097 1 + v251 r_2223 1 + v251 r_2224 1 + v251 r_2225 1 + v251 r_3013 1 + v251 r_3014 1 + v251 r_3015 1 + v252 r_29 1 + v252 r_265 1 + v252 r_491 -1 + v252 r_1380 1 + v252 r_1801 1 + v252 r_2095 1 + v252 r_2096 1 + v252 r_2097 1 + v252 r_2223 1 + v252 r_2224 1 + v252 r_2225 1 + v252 r_3029 1 + v252 r_3030 1 + v252 r_3031 1 + v253 r_29 1 + v253 r_283 1 + v253 r_505 -1 + v253 r_1381 1 + v253 r_1868 1 + v253 r_2095 1 + v253 r_2096 1 + v253 r_2097 1 + v253 r_2223 1 + v253 r_2224 1 + v253 r_2225 1 + v253 r_3045 1 + v253 r_3046 1 + v253 r_3047 1 + v254 r_29 1 + v254 r_298 1 + v254 r_516 -1 + v254 r_1382 1 + v254 r_1932 1 + v254 r_2095 1 + v254 r_2096 1 + v254 r_2097 1 + v254 r_2223 1 + v254 r_2224 1 + v254 r_2225 1 + v254 r_2834 1 + v255 r_30 1 + v255 r_164 1 + v255 r_438 -1 + v255 r_1376 1 + v255 r_1442 1 + v255 r_2096 1 + v255 r_2097 1 + v255 r_2098 1 + v255 r_2966 1 + v255 r_2967 1 + v255 r_2968 1 + v256 r_30 1 + v256 r_313 1 + v256 r_546 1 + v256 r_671 1 + v256 r_797 1 + v256 r_1031 1 + v256 r_1160 1 + v256 r_1283 1 + v256 r_2057 1 + v256 r_2297 1 + v256 r_2485 -1 + v256 r_2486 -1 + v256 r_2487 -1 + v256 r_2654 1 + v256 r_2655 1 + v256 r_2656 1 + v256 r_2657 1 + v257 r_30 1 + v257 r_196 1 + v257 r_451 -1 + v257 r_1377 1 + v257 r_1558 1 + v257 r_2096 1 + v257 r_2097 1 + v257 r_2098 1 + v257 r_2982 1 + v257 r_2983 1 + v257 r_2984 1 + v258 r_30 1 + v258 r_214 1 + v258 r_464 -1 + v258 r_1378 1 + v258 r_1618 1 + v258 r_2096 1 + v258 r_2097 1 + v258 r_2098 1 + v258 r_2836 1 + v258 r_2998 1 + v258 r_2999 1 + v258 r_3000 1 + v259 r_30 1 + v259 r_232 1 + v259 r_478 -1 + v259 r_1379 1 + v259 r_1680 1 + v259 r_2096 1 + v259 r_2097 1 + v259 r_2098 1 + v259 r_3014 1 + v259 r_3015 1 + v259 r_3016 1 + v260 r_30 1 + v260 r_266 1 + v260 r_492 -1 + v260 r_1380 1 + v260 r_1802 1 + v260 r_2096 1 + v260 r_2097 1 + v260 r_2098 1 + v260 r_3030 1 + v260 r_3031 1 + v260 r_3032 1 + v261 r_30 1 + v261 r_284 1 + v261 r_506 -1 + v261 r_1381 1 + v261 r_1869 1 + v261 r_2096 1 + v261 r_2097 1 + v261 r_2098 1 + v261 r_3046 1 + v261 r_3047 1 + v261 r_3048 1 + v262 r_30 1 + v262 r_299 1 + v262 r_517 -1 + v262 r_1382 1 + v262 r_1933 1 + v262 r_2096 1 + v262 r_2097 1 + v262 r_2098 1 + v262 r_2834 1 + v263 r_30 1 + v263 r_2022 1 + v263 r_2040 1 + v263 r_2654 1 + v263 r_2655 1 + v263 r_2656 1 + v263 r_2657 1 + v264 r_31 1 + v264 r_166 1 + v264 r_439 -1 + v264 r_1376 1 + v264 r_1443 1 + v264 r_2098 1 + v264 r_2099 1 + v264 r_2968 1 + v264 r_2969 1 + v265 r_31 1 + v265 r_314 1 + v265 r_547 1 + v265 r_672 1 + v265 r_798 1 + v265 r_1032 1 + v265 r_1161 1 + v265 r_1284 1 + v265 r_2059 1 + v265 r_2487 -1 + v265 r_2656 1 + v265 r_2657 1 + v266 r_31 1 + v266 r_198 1 + v266 r_452 -1 + v266 r_1377 1 + v266 r_1559 1 + v266 r_2098 1 + v266 r_2099 1 + v266 r_2984 1 + v266 r_2985 1 + v267 r_31 1 + v267 r_216 1 + v267 r_465 -1 + v267 r_1378 1 + v267 r_1619 1 + v267 r_2098 1 + v267 r_2099 1 + v267 r_2836 1 + v267 r_3000 1 + v267 r_3001 1 + v268 r_31 1 + v268 r_234 1 + v268 r_479 -1 + v268 r_1379 1 + v268 r_1681 1 + v268 r_2098 1 + v268 r_2099 1 + v268 r_3016 1 + v268 r_3017 1 + v269 r_31 1 + v269 r_268 1 + v269 r_493 -1 + v269 r_1380 1 + v269 r_1803 1 + v269 r_2098 1 + v269 r_2099 1 + v269 r_3032 1 + v269 r_3033 1 + v270 r_31 1 + v270 r_286 1 + v270 r_507 -1 + v270 r_1381 1 + v270 r_1870 1 + v270 r_2098 1 + v270 r_2099 1 + v270 r_3048 1 + v270 r_3049 1 + v271 r_31 1 + v271 r_2022 1 + v271 r_2041 1 + v271 r_2656 1 + v271 r_2657 1 + v272 r_32 1 + v272 r_151 1 + v272 r_518 -1 + v272 r_1383 1 + v272 r_1546 -1 + v272 r_2100 1 + v272 r_2101 1 + v272 r_2226 1 + v273 r_32 1 + v273 r_169 1 + v273 r_535 -1 + v273 r_1384 1 + v273 r_1554 -1 + v273 r_2100 1 + v273 r_2101 1 + v273 r_2226 1 + v273 r_2854 1 + v273 r_2855 1 + v273 r_2970 1 + v273 r_2971 1 + v274 r_32 1 + v274 r_315 1 + v274 r_440 1 + v274 r_673 1 + v274 r_799 1 + v274 r_912 1 + v274 r_1033 1 + v274 r_1162 1 + v274 r_1285 1 + v274 r_2044 1 + v274 r_2298 1 + v274 r_2299 1 + v274 r_2415 1 + v274 r_2488 -1 + v274 r_2593 -1 + v274 r_2658 1 + v274 r_2659 1 + v274 r_2766 1 + v274 r_2810 1 + v274 r_2826 1 + v275 r_32 1 + v275 r_201 1 + v275 r_548 -1 + v275 r_1385 1 + v275 r_1560 -1 + v275 r_2100 1 + v275 r_2101 1 + v275 r_2226 1 + v276 r_32 1 + v276 r_219 1 + v276 r_565 -1 + v276 r_1386 1 + v276 r_1568 -1 + v276 r_2100 1 + v276 r_2101 1 + v276 r_2226 1 + v277 r_32 1 + v277 r_237 1 + v277 r_582 -1 + v277 r_1387 1 + v277 r_1576 -1 + v277 r_2100 1 + v277 r_2101 1 + v277 r_2226 1 + v277 r_2854 1 + v277 r_2855 1 + v277 r_2970 1 + v277 r_2971 1 + v278 r_32 1 + v278 r_253 1 + v278 r_597 -1 + v278 r_1388 1 + v278 r_1583 -1 + v278 r_2100 1 + v278 r_2101 1 + v278 r_2226 1 + v279 r_32 1 + v279 r_271 1 + v279 r_614 -1 + v279 r_1389 1 + v279 r_1591 -1 + v279 r_2100 1 + v279 r_2101 1 + v279 r_2226 1 + v280 r_32 1 + v280 r_288 1 + v280 r_631 -1 + v280 r_1390 1 + v280 r_1599 -1 + v280 r_2100 1 + v280 r_2101 1 + v280 r_2226 1 + v280 r_2970 1 + v280 r_2971 1 + v281 r_32 1 + v281 r_1982 -1 + v281 r_2023 1 + v281 r_2029 1 + v281 r_2658 1 + v281 r_2659 1 + v281 r_2766 1 + v281 r_2818 1 + v281 r_2826 1 + v282 r_33 1 + v282 r_152 1 + v282 r_519 -1 + v282 r_1383 1 + v282 r_1547 -1 + v282 r_2100 1 + v282 r_2101 1 + v282 r_2102 1 + v283 r_33 1 + v283 r_170 1 + v283 r_536 -1 + v283 r_1384 1 + v283 r_1555 -1 + v283 r_2100 1 + v283 r_2101 1 + v283 r_2102 1 + v283 r_2855 1 + v283 r_2856 1 + v283 r_2970 1 + v283 r_2971 1 + v283 r_2972 1 + v284 r_33 1 + v284 r_316 1 + v284 r_441 1 + v284 r_674 1 + v284 r_800 1 + v284 r_913 1 + v284 r_1034 1 + v284 r_1163 1 + v284 r_1286 1 + v284 r_2045 1 + v284 r_2298 1 + v284 r_2299 1 + v284 r_2300 1 + v284 r_2488 -1 + v284 r_2489 -1 + v284 r_2658 1 + v284 r_2659 1 + v284 r_2660 1 + v285 r_33 1 + v285 r_202 1 + v285 r_549 -1 + v285 r_1385 1 + v285 r_1561 -1 + v285 r_2100 1 + v285 r_2101 1 + v285 r_2102 1 + v286 r_33 1 + v286 r_220 1 + v286 r_566 -1 + v286 r_1386 1 + v286 r_1569 -1 + v286 r_2100 1 + v286 r_2101 1 + v286 r_2102 1 + v287 r_33 1 + v287 r_238 1 + v287 r_583 -1 + v287 r_1387 1 + v287 r_1577 -1 + v287 r_2100 1 + v287 r_2101 1 + v287 r_2102 1 + v287 r_2855 1 + v287 r_2856 1 + v287 r_2970 1 + v287 r_2971 1 + v287 r_2972 1 + v288 r_33 1 + v288 r_254 1 + v288 r_598 -1 + v288 r_1388 1 + v288 r_1584 -1 + v288 r_2100 1 + v288 r_2101 1 + v288 r_2102 1 + v289 r_33 1 + v289 r_272 1 + v289 r_615 -1 + v289 r_1389 1 + v289 r_1592 -1 + v289 r_2100 1 + v289 r_2101 1 + v289 r_2102 1 + v290 r_33 1 + v290 r_289 1 + v290 r_632 -1 + v290 r_1390 1 + v290 r_1600 -1 + v290 r_2100 1 + v290 r_2101 1 + v290 r_2102 1 + v290 r_2970 1 + v290 r_2971 1 + v290 r_2972 1 + v291 r_33 1 + v291 r_1983 -1 + v291 r_2023 1 + v291 r_2030 1 + v291 r_2658 1 + v291 r_2659 1 + v291 r_2660 1 + v292 r_34 1 + v292 r_153 1 + v292 r_520 -1 + v292 r_1383 1 + v292 r_1548 -1 + v292 r_2101 1 + v292 r_2102 1 + v292 r_2103 1 + v292 r_2226 1 + v292 r_2227 1 + v293 r_34 1 + v293 r_171 1 + v293 r_537 -1 + v293 r_1384 1 + v293 r_1556 -1 + v293 r_2101 1 + v293 r_2102 1 + v293 r_2103 1 + v293 r_2226 1 + v293 r_2227 1 + v293 r_2856 1 + v293 r_2857 1 + v293 r_2971 1 + v293 r_2972 1 + v293 r_2973 1 + v294 r_34 1 + v294 r_317 1 + v294 r_442 1 + v294 r_675 1 + v294 r_801 1 + v294 r_914 1 + v294 r_1035 1 + v294 r_1164 1 + v294 r_1287 1 + v294 r_2046 1 + v294 r_2299 1 + v294 r_2300 1 + v294 r_2301 1 + v294 r_2415 1 + v294 r_2416 1 + v294 r_2488 -1 + v294 r_2489 -1 + v294 r_2490 -1 + v294 r_2593 -1 + v294 r_2594 -1 + v294 r_2658 1 + v294 r_2659 1 + v294 r_2660 1 + v294 r_2661 1 + v294 r_2766 1 + v294 r_2767 1 + v294 r_2810 1 + v294 r_2826 1 + v295 r_34 1 + v295 r_203 1 + v295 r_550 -1 + v295 r_1385 1 + v295 r_1562 -1 + v295 r_2101 1 + v295 r_2102 1 + v295 r_2103 1 + v295 r_2226 1 + v295 r_2227 1 + v296 r_34 1 + v296 r_221 1 + v296 r_567 -1 + v296 r_1386 1 + v296 r_1570 -1 + v296 r_2101 1 + v296 r_2102 1 + v296 r_2103 1 + v296 r_2226 1 + v296 r_2227 1 + v297 r_34 1 + v297 r_239 1 + v297 r_584 -1 + v297 r_1387 1 + v297 r_1578 -1 + v297 r_2101 1 + v297 r_2102 1 + v297 r_2103 1 + v297 r_2226 1 + v297 r_2227 1 + v297 r_2856 1 + v297 r_2857 1 + v297 r_2971 1 + v297 r_2972 1 + v297 r_2973 1 + v298 r_34 1 + v298 r_255 1 + v298 r_599 -1 + v298 r_1388 1 + v298 r_1585 -1 + v298 r_2101 1 + v298 r_2102 1 + v298 r_2103 1 + v298 r_2226 1 + v298 r_2227 1 + v299 r_34 1 + v299 r_273 1 + v299 r_616 -1 + v299 r_1389 1 + v299 r_1593 -1 + v299 r_2101 1 + v299 r_2102 1 + v299 r_2103 1 + v299 r_2226 1 + v299 r_2227 1 + v300 r_34 1 + v300 r_290 1 + v300 r_633 -1 + v300 r_1390 1 + v300 r_1601 -1 + v300 r_2101 1 + v300 r_2102 1 + v300 r_2103 1 + v300 r_2226 1 + v300 r_2227 1 + v300 r_2971 1 + v300 r_2972 1 + v300 r_2973 1 + v301 r_34 1 + v301 r_1984 -1 + v301 r_2023 1 + v301 r_2031 1 + v301 r_2658 1 + v301 r_2659 1 + v301 r_2660 1 + v301 r_2661 1 + v301 r_2766 1 + v301 r_2767 1 + v301 r_2818 1 + v301 r_2826 1 + v302 r_35 1 + v302 r_154 1 + v302 r_521 -1 + v302 r_1383 1 + v302 r_1549 -1 + v302 r_2102 1 + v302 r_2103 1 + v302 r_2104 1 + v303 r_35 1 + v303 r_172 1 + v303 r_538 -1 + v303 r_1384 1 + v303 r_1557 -1 + v303 r_2102 1 + v303 r_2103 1 + v303 r_2104 1 + v303 r_2857 1 + v303 r_2858 1 + v303 r_2972 1 + v303 r_2973 1 + v303 r_2974 1 + v304 r_35 1 + v304 r_318 1 + v304 r_443 1 + v304 r_676 1 + v304 r_802 1 + v304 r_915 1 + v304 r_1036 1 + v304 r_1165 1 + v304 r_1288 1 + v304 r_2047 1 + v304 r_2300 1 + v304 r_2301 1 + v304 r_2302 1 + v304 r_2488 -1 + v304 r_2489 -1 + v304 r_2490 -1 + v304 r_2491 -1 + v304 r_2658 1 + v304 r_2659 1 + v304 r_2660 1 + v304 r_2661 1 + v304 r_2662 1 + v305 r_35 1 + v305 r_204 1 + v305 r_551 -1 + v305 r_1385 1 + v305 r_1563 -1 + v305 r_2102 1 + v305 r_2103 1 + v305 r_2104 1 + v306 r_35 1 + v306 r_222 1 + v306 r_568 -1 + v306 r_1386 1 + v306 r_1571 -1 + v306 r_2102 1 + v306 r_2103 1 + v306 r_2104 1 + v307 r_35 1 + v307 r_240 1 + v307 r_585 -1 + v307 r_1387 1 + v307 r_1579 -1 + v307 r_2102 1 + v307 r_2103 1 + v307 r_2104 1 + v307 r_2857 1 + v307 r_2858 1 + v307 r_2972 1 + v307 r_2973 1 + v307 r_2974 1 + v308 r_35 1 + v308 r_256 1 + v308 r_600 -1 + v308 r_1388 1 + v308 r_1586 -1 + v308 r_2102 1 + v308 r_2103 1 + v308 r_2104 1 + v309 r_35 1 + v309 r_274 1 + v309 r_617 -1 + v309 r_1389 1 + v309 r_1594 -1 + v309 r_2102 1 + v309 r_2103 1 + v309 r_2104 1 + v310 r_35 1 + v310 r_291 1 + v310 r_634 -1 + v310 r_1390 1 + v310 r_1602 -1 + v310 r_2102 1 + v310 r_2103 1 + v310 r_2104 1 + v310 r_2972 1 + v310 r_2973 1 + v310 r_2974 1 + v311 r_35 1 + v311 r_1985 -1 + v311 r_2023 1 + v311 r_2032 1 + v311 r_2658 1 + v311 r_2659 1 + v311 r_2660 1 + v311 r_2661 1 + v311 r_2662 1 + v312 r_36 1 + v312 r_155 1 + v312 r_522 -1 + v312 r_1383 1 + v312 r_1550 -1 + v312 r_2103 1 + v312 r_2104 1 + v312 r_2105 1 + v312 r_2226 1 + v312 r_2227 1 + v312 r_2228 1 + v313 r_36 1 + v313 r_173 1 + v313 r_539 -1 + v313 r_1384 1 + v313 r_1558 -1 + v313 r_2103 1 + v313 r_2104 1 + v313 r_2105 1 + v313 r_2226 1 + v313 r_2227 1 + v313 r_2228 1 + v313 r_2858 1 + v313 r_2859 1 + v313 r_2973 1 + v313 r_2974 1 + v313 r_2975 1 + v314 r_36 1 + v314 r_319 1 + v314 r_444 1 + v314 r_677 1 + v314 r_803 1 + v314 r_916 1 + v314 r_1037 1 + v314 r_1166 1 + v314 r_1289 1 + v314 r_2048 1 + v314 r_2301 1 + v314 r_2302 1 + v314 r_2303 1 + v314 r_2415 1 + v314 r_2416 1 + v314 r_2417 1 + v314 r_2489 -1 + v314 r_2490 -1 + v314 r_2491 -1 + v314 r_2492 -1 + v314 r_2593 -1 + v314 r_2594 -1 + v314 r_2595 -1 + v314 r_2659 1 + v314 r_2660 1 + v314 r_2661 1 + v314 r_2662 1 + v314 r_2663 1 + v314 r_2766 1 + v314 r_2767 1 + v314 r_2768 1 + v314 r_2810 1 + v314 r_2826 1 + v315 r_36 1 + v315 r_205 1 + v315 r_552 -1 + v315 r_1385 1 + v315 r_1564 -1 + v315 r_2103 1 + v315 r_2104 1 + v315 r_2105 1 + v315 r_2226 1 + v315 r_2227 1 + v315 r_2228 1 + v316 r_36 1 + v316 r_223 1 + v316 r_569 -1 + v316 r_1386 1 + v316 r_1572 -1 + v316 r_2103 1 + v316 r_2104 1 + v316 r_2105 1 + v316 r_2226 1 + v316 r_2227 1 + v316 r_2228 1 + v317 r_36 1 + v317 r_241 1 + v317 r_586 -1 + v317 r_1387 1 + v317 r_1580 -1 + v317 r_2103 1 + v317 r_2104 1 + v317 r_2105 1 + v317 r_2226 1 + v317 r_2227 1 + v317 r_2228 1 + v317 r_2858 1 + v317 r_2859 1 + v317 r_2973 1 + v317 r_2974 1 + v317 r_2975 1 + v318 r_36 1 + v318 r_257 1 + v318 r_601 -1 + v318 r_1388 1 + v318 r_1587 -1 + v318 r_2103 1 + v318 r_2104 1 + v318 r_2105 1 + v318 r_2226 1 + v318 r_2227 1 + v318 r_2228 1 + v319 r_36 1 + v319 r_275 1 + v319 r_618 -1 + v319 r_1389 1 + v319 r_1595 -1 + v319 r_2103 1 + v319 r_2104 1 + v319 r_2105 1 + v319 r_2226 1 + v319 r_2227 1 + v319 r_2228 1 + v320 r_36 1 + v320 r_292 1 + v320 r_635 -1 + v320 r_1390 1 + v320 r_1603 -1 + v320 r_2103 1 + v320 r_2104 1 + v320 r_2105 1 + v320 r_2226 1 + v320 r_2227 1 + v320 r_2228 1 + v320 r_2973 1 + v320 r_2974 1 + v320 r_2975 1 + v321 r_36 1 + v321 r_1986 -1 + v321 r_2023 1 + v321 r_2033 1 + v321 r_2659 1 + v321 r_2660 1 + v321 r_2661 1 + v321 r_2662 1 + v321 r_2663 1 + v321 r_2766 1 + v321 r_2767 1 + v321 r_2768 1 + v321 r_2818 1 + v321 r_2826 1 + v322 r_37 1 + v322 r_156 1 + v322 r_523 -1 + v322 r_1383 1 + v322 r_1551 -1 + v322 r_2104 1 + v322 r_2105 1 + v322 r_2106 1 + v323 r_37 1 + v323 r_320 1 + v323 r_678 1 + v323 r_804 1 + v323 r_917 1 + v323 r_1038 1 + v323 r_1167 1 + v323 r_1290 1 + v323 r_2049 1 + v323 r_2302 1 + v323 r_2303 1 + v323 r_2304 1 + v323 r_2490 -1 + v323 r_2491 -1 + v323 r_2492 -1 + v323 r_2493 -1 + v323 r_2660 1 + v323 r_2661 1 + v323 r_2662 1 + v323 r_2663 1 + v323 r_2664 1 + v324 r_37 1 + v324 r_206 1 + v324 r_553 -1 + v324 r_1385 1 + v324 r_1565 -1 + v324 r_2104 1 + v324 r_2105 1 + v324 r_2106 1 + v325 r_37 1 + v325 r_224 1 + v325 r_570 -1 + v325 r_1386 1 + v325 r_1573 -1 + v325 r_2104 1 + v325 r_2105 1 + v325 r_2106 1 + v326 r_37 1 + v326 r_242 1 + v326 r_587 -1 + v326 r_1387 1 + v326 r_1581 -1 + v326 r_2104 1 + v326 r_2105 1 + v326 r_2106 1 + v326 r_2859 1 + v326 r_2860 1 + v326 r_2974 1 + v326 r_2975 1 + v326 r_2976 1 + v327 r_37 1 + v327 r_258 1 + v327 r_602 -1 + v327 r_1388 1 + v327 r_1588 -1 + v327 r_2104 1 + v327 r_2105 1 + v327 r_2106 1 + v328 r_37 1 + v328 r_276 1 + v328 r_619 -1 + v328 r_1389 1 + v328 r_1596 -1 + v328 r_2104 1 + v328 r_2105 1 + v328 r_2106 1 + v329 r_37 1 + v329 r_293 1 + v329 r_636 -1 + v329 r_1390 1 + v329 r_1604 -1 + v329 r_2104 1 + v329 r_2105 1 + v329 r_2106 1 + v329 r_2974 1 + v329 r_2975 1 + v329 r_2976 1 + v330 r_38 1 + v330 r_157 1 + v330 r_524 -1 + v330 r_1383 1 + v330 r_2105 1 + v330 r_2106 1 + v330 r_2107 1 + v330 r_2227 1 + v330 r_2228 1 + v330 r_2229 1 + v331 r_38 1 + v331 r_174 1 + v331 r_540 -1 + v331 r_1384 1 + v331 r_1505 1 + v331 r_2105 1 + v331 r_2106 1 + v331 r_2107 1 + v331 r_2227 1 + v331 r_2228 1 + v331 r_2229 1 + v331 r_2860 1 + v331 r_2861 1 + v331 r_2975 1 + v331 r_2976 1 + v331 r_2977 1 + v332 r_38 1 + v332 r_321 1 + v332 r_445 1 + v332 r_679 1 + v332 r_805 1 + v332 r_918 1 + v332 r_1039 1 + v332 r_1168 1 + v332 r_2050 1 + v332 r_2303 1 + v332 r_2304 1 + v332 r_2305 1 + v332 r_2416 1 + v332 r_2417 1 + v332 r_2418 1 + v332 r_2491 -1 + v332 r_2492 -1 + v332 r_2493 -1 + v332 r_2494 -1 + v332 r_2593 -1 + v332 r_2594 -1 + v332 r_2595 -1 + v332 r_2596 -1 + v332 r_2661 1 + v332 r_2662 1 + v332 r_2663 1 + v332 r_2664 1 + v332 r_2665 1 + v332 r_2766 1 + v332 r_2767 1 + v332 r_2768 1 + v332 r_2769 1 + v332 r_2810 1 + v332 r_2826 1 + v333 r_38 1 + v333 r_207 1 + v333 r_554 -1 + v333 r_1385 1 + v333 r_2105 1 + v333 r_2106 1 + v333 r_2107 1 + v333 r_2227 1 + v333 r_2228 1 + v333 r_2229 1 + v334 r_38 1 + v334 r_225 1 + v334 r_571 -1 + v334 r_1386 1 + v334 r_1682 1 + v334 r_2105 1 + v334 r_2106 1 + v334 r_2107 1 + v334 r_2227 1 + v334 r_2228 1 + v334 r_2229 1 + v335 r_38 1 + v335 r_243 1 + v335 r_588 -1 + v335 r_1387 1 + v335 r_1741 1 + v335 r_2105 1 + v335 r_2106 1 + v335 r_2107 1 + v335 r_2227 1 + v335 r_2228 1 + v335 r_2229 1 + v335 r_2860 1 + v335 r_2861 1 + v335 r_2975 1 + v335 r_2976 1 + v335 r_2977 1 + v336 r_38 1 + v336 r_259 1 + v336 r_603 -1 + v336 r_1388 1 + v336 r_1804 1 + v336 r_2105 1 + v336 r_2106 1 + v336 r_2107 1 + v336 r_2227 1 + v336 r_2228 1 + v336 r_2229 1 + v337 r_38 1 + v337 r_277 1 + v337 r_620 -1 + v337 r_1389 1 + v337 r_1871 1 + v337 r_2105 1 + v337 r_2106 1 + v337 r_2107 1 + v337 r_2227 1 + v337 r_2228 1 + v337 r_2229 1 + v338 r_39 1 + v338 r_158 1 + v338 r_525 -1 + v338 r_1383 1 + v338 r_1444 1 + v338 r_2106 1 + v338 r_2107 1 + v338 r_2108 1 + v339 r_39 1 + v339 r_175 1 + v339 r_541 -1 + v339 r_1384 1 + v339 r_1506 1 + v339 r_2106 1 + v339 r_2107 1 + v339 r_2108 1 + v339 r_2861 1 + v339 r_2862 1 + v339 r_2976 1 + v339 r_2977 1 + v339 r_2978 1 + v340 r_39 1 + v340 r_322 1 + v340 r_446 1 + v340 r_680 1 + v340 r_806 1 + v340 r_919 1 + v340 r_1040 1 + v340 r_1169 1 + v340 r_1291 1 + v340 r_2051 1 + v340 r_2304 1 + v340 r_2305 1 + v340 r_2306 1 + v340 r_2492 -1 + v340 r_2493 -1 + v340 r_2494 -1 + v340 r_2495 -1 + v340 r_2662 1 + v340 r_2663 1 + v340 r_2664 1 + v340 r_2665 1 + v340 r_2666 1 + v341 r_39 1 + v341 r_208 1 + v341 r_555 -1 + v341 r_1385 1 + v341 r_1620 1 + v341 r_2106 1 + v341 r_2107 1 + v341 r_2108 1 + v342 r_39 1 + v342 r_226 1 + v342 r_572 -1 + v342 r_1386 1 + v342 r_1683 1 + v342 r_2106 1 + v342 r_2107 1 + v342 r_2108 1 + v343 r_39 1 + v343 r_244 1 + v343 r_589 -1 + v343 r_1387 1 + v343 r_1742 1 + v343 r_2106 1 + v343 r_2107 1 + v343 r_2108 1 + v343 r_2861 1 + v343 r_2862 1 + v343 r_2976 1 + v343 r_2977 1 + v343 r_2978 1 + v344 r_39 1 + v344 r_260 1 + v344 r_604 -1 + v344 r_1388 1 + v344 r_1805 1 + v344 r_2106 1 + v344 r_2107 1 + v344 r_2108 1 + v345 r_39 1 + v345 r_278 1 + v345 r_621 -1 + v345 r_1389 1 + v345 r_1872 1 + v345 r_2106 1 + v345 r_2107 1 + v345 r_2108 1 + v346 r_39 1 + v346 r_294 1 + v346 r_637 -1 + v346 r_1390 1 + v346 r_1934 1 + v346 r_2106 1 + v346 r_2107 1 + v346 r_2108 1 + v346 r_2976 1 + v346 r_2977 1 + v346 r_2978 1 + v347 r_39 1 + v347 r_1982 1 + v347 r_2023 1 + v347 r_2034 1 + v347 r_2662 1 + v347 r_2663 1 + v347 r_2664 1 + v347 r_2665 1 + v347 r_2666 1 + v348 r_40 1 + v348 r_159 1 + v348 r_526 -1 + v348 r_1383 1 + v348 r_1552 -1 + v348 r_2107 1 + v348 r_2108 1 + v348 r_2109 1 + v348 r_2228 1 + v348 r_2229 1 + v348 r_2230 1 + v349 r_40 1 + v349 r_176 1 + v349 r_542 -1 + v349 r_1384 1 + v349 r_1559 -1 + v349 r_2107 1 + v349 r_2108 1 + v349 r_2109 1 + v349 r_2228 1 + v349 r_2229 1 + v349 r_2230 1 + v349 r_2862 1 + v349 r_2863 1 + v349 r_2977 1 + v349 r_2978 1 + v349 r_2979 1 + v350 r_40 1 + v350 r_323 1 + v350 r_447 1 + v350 r_681 1 + v350 r_807 1 + v350 r_920 1 + v350 r_1041 1 + v350 r_1170 1 + v350 r_2052 1 + v350 r_2305 1 + v350 r_2306 1 + v350 r_2307 1 + v350 r_2417 1 + v350 r_2418 1 + v350 r_2419 1 + v350 r_2493 -1 + v350 r_2494 -1 + v350 r_2495 -1 + v350 r_2496 -1 + v350 r_2594 -1 + v350 r_2595 -1 + v350 r_2596 -1 + v350 r_2597 -1 + v350 r_2663 1 + v350 r_2664 1 + v350 r_2665 1 + v350 r_2666 1 + v350 r_2667 1 + v350 r_2767 1 + v350 r_2768 1 + v350 r_2769 1 + v350 r_2770 1 + v350 r_2810 1 + v350 r_2826 1 + v351 r_40 1 + v351 r_209 1 + v351 r_556 -1 + v351 r_1385 1 + v351 r_1566 -1 + v351 r_2107 1 + v351 r_2108 1 + v351 r_2109 1 + v351 r_2228 1 + v351 r_2229 1 + v351 r_2230 1 + v352 r_40 1 + v352 r_227 1 + v352 r_573 -1 + v352 r_1386 1 + v352 r_1574 -1 + v352 r_2107 1 + v352 r_2108 1 + v352 r_2109 1 + v352 r_2228 1 + v352 r_2229 1 + v352 r_2230 1 + v353 r_40 1 + v353 r_245 1 + v353 r_590 -1 + v353 r_1387 1 + v353 r_1582 -1 + v353 r_2107 1 + v353 r_2108 1 + v353 r_2109 1 + v353 r_2228 1 + v353 r_2229 1 + v353 r_2230 1 + v353 r_2862 1 + v353 r_2863 1 + v353 r_2977 1 + v353 r_2978 1 + v353 r_2979 1 + v354 r_40 1 + v354 r_261 1 + v354 r_605 -1 + v354 r_1388 1 + v354 r_1589 -1 + v354 r_2107 1 + v354 r_2108 1 + v354 r_2109 1 + v354 r_2228 1 + v354 r_2229 1 + v354 r_2230 1 + v355 r_40 1 + v355 r_279 1 + v355 r_622 -1 + v355 r_1389 1 + v355 r_1597 -1 + v355 r_2107 1 + v355 r_2108 1 + v355 r_2109 1 + v355 r_2228 1 + v355 r_2229 1 + v355 r_2230 1 + v356 r_40 1 + v356 r_295 1 + v356 r_1390 1 + v356 r_1605 -1 + v356 r_2107 1 + v356 r_2108 1 + v356 r_2109 1 + v356 r_2228 1 + v356 r_2229 1 + v356 r_2230 1 + v356 r_2977 1 + v356 r_2978 1 + v356 r_2979 1 + v357 r_40 1 + v357 r_1987 -1 + v357 r_2023 1 + v357 r_2035 1 + v357 r_2663 1 + v357 r_2664 1 + v357 r_2665 1 + v357 r_2666 1 + v357 r_2667 1 + v357 r_2767 1 + v357 r_2768 1 + v357 r_2769 1 + v357 r_2770 1 + v357 r_2818 1 + v357 r_2826 1 + v358 r_41 1 + v358 r_160 1 + v358 r_527 -1 + v358 r_1383 1 + v358 r_1553 -1 + v358 r_2108 1 + v358 r_2109 1 + v358 r_2110 1 + v359 r_41 1 + v359 r_324 1 + v359 r_682 1 + v359 r_808 1 + v359 r_1042 1 + v359 r_1171 1 + v359 r_1292 1 + v359 r_2053 1 + v359 r_2306 1 + v359 r_2307 1 + v359 r_2308 1 + v359 r_2494 -1 + v359 r_2495 -1 + v359 r_2496 -1 + v359 r_2497 -1 + v359 r_2664 1 + v359 r_2665 1 + v359 r_2666 1 + v359 r_2667 1 + v359 r_2668 1 + v360 r_41 1 + v360 r_210 1 + v360 r_557 -1 + v360 r_1385 1 + v360 r_1567 -1 + v360 r_2108 1 + v360 r_2109 1 + v360 r_2110 1 + v361 r_41 1 + v361 r_228 1 + v361 r_574 -1 + v361 r_1386 1 + v361 r_1575 -1 + v361 r_2108 1 + v361 r_2109 1 + v361 r_2110 1 + v362 r_41 1 + v362 r_262 1 + v362 r_606 -1 + v362 r_1388 1 + v362 r_1590 -1 + v362 r_2108 1 + v362 r_2109 1 + v362 r_2110 1 + v363 r_41 1 + v363 r_280 1 + v363 r_623 -1 + v363 r_1389 1 + v363 r_1598 -1 + v363 r_2108 1 + v363 r_2109 1 + v363 r_2110 1 + v364 r_42 1 + v364 r_161 1 + v364 r_528 -1 + v364 r_1383 1 + v364 r_1445 1 + v364 r_2109 1 + v364 r_2110 1 + v364 r_2111 1 + v364 r_2229 1 + v364 r_2230 1 + v364 r_2231 1 + v365 r_42 1 + v365 r_177 1 + v365 r_543 -1 + v365 r_1384 1 + v365 r_1507 1 + v365 r_2109 1 + v365 r_2110 1 + v365 r_2111 1 + v365 r_2229 1 + v365 r_2230 1 + v365 r_2231 1 + v365 r_2864 1 + v365 r_2865 1 + v365 r_2979 1 + v365 r_2980 1 + v365 r_2981 1 + v366 r_42 1 + v366 r_325 1 + v366 r_448 1 + v366 r_683 1 + v366 r_809 1 + v366 r_921 1 + v366 r_1043 1 + v366 r_1172 1 + v366 r_1293 1 + v366 r_2054 1 + v366 r_2307 1 + v366 r_2308 1 + v366 r_2309 1 + v366 r_2418 1 + v366 r_2419 1 + v366 r_2420 1 + v366 r_2495 -1 + v366 r_2496 -1 + v366 r_2497 -1 + v366 r_2498 -1 + v366 r_2595 -1 + v366 r_2596 -1 + v366 r_2597 -1 + v366 r_2598 -1 + v366 r_2665 1 + v366 r_2666 1 + v366 r_2667 1 + v366 r_2668 1 + v366 r_2669 1 + v366 r_2768 1 + v366 r_2769 1 + v366 r_2770 1 + v366 r_2771 1 + v366 r_2810 1 + v367 r_42 1 + v367 r_211 1 + v367 r_558 -1 + v367 r_1385 1 + v367 r_1621 1 + v367 r_2109 1 + v367 r_2110 1 + v367 r_2111 1 + v367 r_2229 1 + v367 r_2230 1 + v367 r_2231 1 + v368 r_42 1 + v368 r_229 1 + v368 r_575 -1 + v368 r_1386 1 + v368 r_1684 1 + v368 r_2109 1 + v368 r_2110 1 + v368 r_2111 1 + v368 r_2229 1 + v368 r_2230 1 + v368 r_2231 1 + v369 r_42 1 + v369 r_246 1 + v369 r_591 -1 + v369 r_1387 1 + v369 r_1743 1 + v369 r_2109 1 + v369 r_2110 1 + v369 r_2111 1 + v369 r_2229 1 + v369 r_2230 1 + v369 r_2231 1 + v369 r_2864 1 + v369 r_2865 1 + v369 r_2979 1 + v369 r_2980 1 + v369 r_2981 1 + v370 r_42 1 + v370 r_263 1 + v370 r_607 -1 + v370 r_1388 1 + v370 r_1806 1 + v370 r_2109 1 + v370 r_2110 1 + v370 r_2111 1 + v370 r_2229 1 + v370 r_2230 1 + v370 r_2231 1 + v371 r_42 1 + v371 r_281 1 + v371 r_624 -1 + v371 r_1389 1 + v371 r_1873 1 + v371 r_2109 1 + v371 r_2110 1 + v371 r_2111 1 + v371 r_2229 1 + v371 r_2230 1 + v371 r_2231 1 + v372 r_42 1 + v372 r_296 1 + v372 r_638 -1 + v372 r_1390 1 + v372 r_1935 1 + v372 r_2109 1 + v372 r_2110 1 + v372 r_2111 1 + v372 r_2229 1 + v372 r_2230 1 + v372 r_2231 1 + v372 r_2979 1 + v372 r_2980 1 + v372 r_2981 1 + v373 r_42 1 + v373 r_1983 1 + v373 r_2023 1 + v373 r_2037 1 + v373 r_2665 1 + v373 r_2666 1 + v373 r_2667 1 + v373 r_2668 1 + v373 r_2669 1 + v373 r_2768 1 + v373 r_2769 1 + v373 r_2770 1 + v373 r_2771 1 + v373 r_2818 1 + v374 r_43 1 + v374 r_162 1 + v374 r_529 -1 + v374 r_1383 1 + v374 r_1446 1 + v374 r_2110 1 + v374 r_2111 1 + v374 r_2112 1 + v375 r_43 1 + v375 r_178 1 + v375 r_544 -1 + v375 r_1384 1 + v375 r_1508 1 + v375 r_2110 1 + v375 r_2111 1 + v375 r_2112 1 + v375 r_2865 1 + v375 r_2866 1 + v375 r_2980 1 + v375 r_2981 1 + v375 r_2982 1 + v376 r_43 1 + v376 r_326 1 + v376 r_449 1 + v376 r_684 1 + v376 r_810 1 + v376 r_922 1 + v376 r_1044 1 + v376 r_1173 1 + v376 r_1294 1 + v376 r_2055 1 + v376 r_2308 1 + v376 r_2309 1 + v376 r_2310 1 + v376 r_2496 -1 + v376 r_2497 -1 + v376 r_2498 -1 + v376 r_2499 -1 + v376 r_2666 1 + v376 r_2667 1 + v376 r_2668 1 + v376 r_2669 1 + v376 r_2670 1 + v377 r_43 1 + v377 r_212 1 + v377 r_559 -1 + v377 r_1385 1 + v377 r_1622 1 + v377 r_2110 1 + v377 r_2111 1 + v377 r_2112 1 + v378 r_43 1 + v378 r_230 1 + v378 r_576 -1 + v378 r_1386 1 + v378 r_1685 1 + v378 r_2110 1 + v378 r_2111 1 + v378 r_2112 1 + v379 r_43 1 + v379 r_247 1 + v379 r_592 -1 + v379 r_1387 1 + v379 r_1744 1 + v379 r_2110 1 + v379 r_2111 1 + v379 r_2112 1 + v379 r_2865 1 + v379 r_2866 1 + v379 r_2980 1 + v379 r_2981 1 + v379 r_2982 1 + v380 r_43 1 + v380 r_264 1 + v380 r_608 -1 + v380 r_1388 1 + v380 r_1807 1 + v380 r_2110 1 + v380 r_2111 1 + v380 r_2112 1 + v381 r_43 1 + v381 r_282 1 + v381 r_625 -1 + v381 r_1389 1 + v381 r_1874 1 + v381 r_2110 1 + v381 r_2111 1 + v381 r_2112 1 + v382 r_43 1 + v382 r_297 1 + v382 r_639 -1 + v382 r_1390 1 + v382 r_1936 1 + v382 r_2110 1 + v382 r_2111 1 + v382 r_2112 1 + v382 r_2980 1 + v382 r_2981 1 + v382 r_2982 1 + v383 r_43 1 + v383 r_1984 1 + v383 r_2023 1 + v383 r_2038 1 + v383 r_2666 1 + v383 r_2667 1 + v383 r_2668 1 + v383 r_2669 1 + v383 r_2670 1 + v384 r_44 1 + v384 r_163 1 + v384 r_530 -1 + v384 r_1383 1 + v384 r_1447 1 + v384 r_2111 1 + v384 r_2112 1 + v384 r_2113 1 + v384 r_2230 1 + v384 r_2231 1 + v384 r_2232 1 + v385 r_44 1 + v385 r_179 1 + v385 r_545 -1 + v385 r_1384 1 + v385 r_1509 1 + v385 r_2111 1 + v385 r_2112 1 + v385 r_2113 1 + v385 r_2230 1 + v385 r_2231 1 + v385 r_2232 1 + v385 r_2866 1 + v385 r_2867 1 + v385 r_2981 1 + v385 r_2982 1 + v385 r_2983 1 + v386 r_44 1 + v386 r_327 1 + v386 r_450 1 + v386 r_685 1 + v386 r_811 1 + v386 r_923 1 + v386 r_1045 1 + v386 r_1174 1 + v386 r_1295 1 + v386 r_2056 1 + v386 r_2309 1 + v386 r_2310 1 + v386 r_2311 1 + v386 r_2419 1 + v386 r_2420 1 + v386 r_2421 1 + v386 r_2497 -1 + v386 r_2498 -1 + v386 r_2499 -1 + v386 r_2500 -1 + v386 r_2596 -1 + v386 r_2597 -1 + v386 r_2598 -1 + v386 r_2667 1 + v386 r_2668 1 + v386 r_2669 1 + v386 r_2670 1 + v386 r_2671 1 + v386 r_2769 1 + v386 r_2770 1 + v386 r_2771 1 + v386 r_2810 1 + v387 r_44 1 + v387 r_213 1 + v387 r_560 -1 + v387 r_1385 1 + v387 r_1623 1 + v387 r_2111 1 + v387 r_2112 1 + v387 r_2113 1 + v387 r_2230 1 + v387 r_2231 1 + v387 r_2232 1 + v388 r_44 1 + v388 r_231 1 + v388 r_577 -1 + v388 r_1386 1 + v388 r_1686 1 + v388 r_2111 1 + v388 r_2112 1 + v388 r_2113 1 + v388 r_2230 1 + v388 r_2231 1 + v388 r_2232 1 + v389 r_44 1 + v389 r_248 1 + v389 r_593 -1 + v389 r_1387 1 + v389 r_1745 1 + v389 r_2111 1 + v389 r_2112 1 + v389 r_2113 1 + v389 r_2230 1 + v389 r_2231 1 + v389 r_2232 1 + v389 r_2866 1 + v389 r_2867 1 + v389 r_2981 1 + v389 r_2982 1 + v389 r_2983 1 + v390 r_44 1 + v390 r_265 1 + v390 r_609 -1 + v390 r_1388 1 + v390 r_1808 1 + v390 r_2111 1 + v390 r_2112 1 + v390 r_2113 1 + v390 r_2230 1 + v390 r_2231 1 + v390 r_2232 1 + v391 r_44 1 + v391 r_283 1 + v391 r_626 -1 + v391 r_1389 1 + v391 r_1875 1 + v391 r_2111 1 + v391 r_2112 1 + v391 r_2113 1 + v391 r_2230 1 + v391 r_2231 1 + v391 r_2232 1 + v392 r_44 1 + v392 r_298 1 + v392 r_640 -1 + v392 r_1390 1 + v392 r_1937 1 + v392 r_2111 1 + v392 r_2112 1 + v392 r_2113 1 + v392 r_2230 1 + v392 r_2231 1 + v392 r_2232 1 + v392 r_2981 1 + v392 r_2982 1 + v392 r_2983 1 + v393 r_44 1 + v393 r_1985 1 + v393 r_2023 1 + v393 r_2039 1 + v393 r_2667 1 + v393 r_2668 1 + v393 r_2669 1 + v393 r_2670 1 + v393 r_2671 1 + v393 r_2769 1 + v393 r_2770 1 + v393 r_2771 1 + v393 r_2818 1 + v394 r_45 1 + v394 r_164 1 + v394 r_531 -1 + v394 r_1383 1 + v394 r_1448 1 + v394 r_2112 1 + v394 r_2113 1 + v394 r_2114 1 + v395 r_45 1 + v395 r_180 1 + v395 r_546 -1 + v395 r_1384 1 + v395 r_1510 1 + v395 r_2112 1 + v395 r_2113 1 + v395 r_2114 1 + v395 r_2867 1 + v395 r_2868 1 + v395 r_2982 1 + v395 r_2983 1 + v395 r_2984 1 + v396 r_45 1 + v396 r_328 1 + v396 r_451 1 + v396 r_686 1 + v396 r_812 1 + v396 r_924 1 + v396 r_1046 1 + v396 r_1175 1 + v396 r_1296 1 + v396 r_2057 1 + v396 r_2310 1 + v396 r_2311 1 + v396 r_2312 1 + v396 r_2498 -1 + v396 r_2499 -1 + v396 r_2500 -1 + v396 r_2501 -1 + v396 r_2668 1 + v396 r_2669 1 + v396 r_2670 1 + v396 r_2671 1 + v397 r_45 1 + v397 r_214 1 + v397 r_561 -1 + v397 r_1385 1 + v397 r_1624 1 + v397 r_2112 1 + v397 r_2113 1 + v397 r_2114 1 + v398 r_45 1 + v398 r_232 1 + v398 r_578 -1 + v398 r_1386 1 + v398 r_1687 1 + v398 r_2112 1 + v398 r_2113 1 + v398 r_2114 1 + v399 r_45 1 + v399 r_249 1 + v399 r_594 -1 + v399 r_1387 1 + v399 r_1746 1 + v399 r_2112 1 + v399 r_2113 1 + v399 r_2114 1 + v399 r_2867 1 + v399 r_2868 1 + v399 r_2982 1 + v399 r_2983 1 + v399 r_2984 1 + v400 r_45 1 + v400 r_266 1 + v400 r_610 -1 + v400 r_1388 1 + v400 r_1809 1 + v400 r_2112 1 + v400 r_2113 1 + v400 r_2114 1 + v401 r_45 1 + v401 r_284 1 + v401 r_627 -1 + v401 r_1389 1 + v401 r_1876 1 + v401 r_2112 1 + v401 r_2113 1 + v401 r_2114 1 + v402 r_45 1 + v402 r_299 1 + v402 r_641 -1 + v402 r_1390 1 + v402 r_1938 1 + v402 r_2112 1 + v402 r_2113 1 + v402 r_2114 1 + v402 r_2982 1 + v402 r_2983 1 + v402 r_2984 1 + v403 r_45 1 + v403 r_1986 1 + v403 r_2023 1 + v403 r_2040 1 + v403 r_2668 1 + v403 r_2669 1 + v403 r_2670 1 + v403 r_2671 1 + v404 r_46 1 + v404 r_165 1 + v404 r_532 -1 + v404 r_1383 1 + v404 r_1449 1 + v404 r_2113 1 + v404 r_2114 1 + v404 r_2115 1 + v404 r_2231 1 + v404 r_2232 1 + v405 r_46 1 + v405 r_329 1 + v405 r_687 1 + v405 r_813 1 + v405 r_925 1 + v405 r_1047 1 + v405 r_1176 1 + v405 r_1297 1 + v405 r_2058 1 + v405 r_2311 1 + v405 r_2312 1 + v405 r_2313 1 + v405 r_2420 1 + v405 r_2421 1 + v405 r_2499 -1 + v405 r_2500 -1 + v405 r_2501 -1 + v405 r_2597 -1 + v405 r_2598 -1 + v405 r_2669 1 + v405 r_2670 1 + v405 r_2671 1 + v405 r_2770 1 + v405 r_2771 1 + v405 r_2810 1 + v406 r_46 1 + v406 r_215 1 + v406 r_562 -1 + v406 r_1385 1 + v406 r_1625 1 + v406 r_2113 1 + v406 r_2114 1 + v406 r_2115 1 + v406 r_2231 1 + v406 r_2232 1 + v407 r_46 1 + v407 r_233 1 + v407 r_579 -1 + v407 r_1386 1 + v407 r_1688 1 + v407 r_2113 1 + v407 r_2114 1 + v407 r_2115 1 + v407 r_2231 1 + v407 r_2232 1 + v408 r_46 1 + v408 r_250 1 + v408 r_595 -1 + v408 r_1387 1 + v408 r_1747 1 + v408 r_2113 1 + v408 r_2114 1 + v408 r_2115 1 + v408 r_2231 1 + v408 r_2232 1 + v408 r_2868 1 + v408 r_2869 1 + v408 r_2983 1 + v408 r_2984 1 + v408 r_2985 1 + v409 r_46 1 + v409 r_267 1 + v409 r_611 -1 + v409 r_1388 1 + v409 r_1810 1 + v409 r_2113 1 + v409 r_2114 1 + v409 r_2115 1 + v409 r_2231 1 + v409 r_2232 1 + v410 r_46 1 + v410 r_285 1 + v410 r_628 -1 + v410 r_1389 1 + v410 r_1877 1 + v410 r_2113 1 + v410 r_2114 1 + v410 r_2115 1 + v410 r_2231 1 + v410 r_2232 1 + v411 r_46 1 + v411 r_300 1 + v411 r_642 -1 + v411 r_1390 1 + v411 r_1939 1 + v411 r_2113 1 + v411 r_2114 1 + v411 r_2115 1 + v411 r_2231 1 + v411 r_2232 1 + v411 r_2983 1 + v411 r_2984 1 + v411 r_2985 1 + v412 r_47 1 + v412 r_166 1 + v412 r_533 -1 + v412 r_1383 1 + v412 r_1450 1 + v412 r_2114 1 + v412 r_2115 1 + v413 r_47 1 + v413 r_181 1 + v413 r_547 -1 + v413 r_1384 1 + v413 r_1511 1 + v413 r_2114 1 + v413 r_2115 1 + v413 r_2869 1 + v413 r_2870 1 + v413 r_2984 1 + v413 r_2985 1 + v414 r_47 1 + v414 r_330 1 + v414 r_452 1 + v414 r_688 1 + v414 r_814 1 + v414 r_926 1 + v414 r_1048 1 + v414 r_1177 1 + v414 r_1298 1 + v414 r_2059 1 + v414 r_2062 1 + v414 r_2312 1 + v414 r_2313 1 + v414 r_2500 -1 + v414 r_2501 -1 + v414 r_2670 1 + v414 r_2671 1 + v415 r_47 1 + v415 r_216 1 + v415 r_563 -1 + v415 r_1385 1 + v415 r_1626 1 + v415 r_2114 1 + v415 r_2115 1 + v416 r_47 1 + v416 r_234 1 + v416 r_580 -1 + v416 r_1386 1 + v416 r_1689 1 + v416 r_2114 1 + v416 r_2115 1 + v417 r_47 1 + v417 r_251 1 + v417 r_596 -1 + v417 r_1387 1 + v417 r_1748 1 + v417 r_2114 1 + v417 r_2115 1 + v417 r_2869 1 + v417 r_2870 1 + v417 r_2984 1 + v417 r_2985 1 + v418 r_47 1 + v418 r_268 1 + v418 r_612 -1 + v418 r_1388 1 + v418 r_1811 1 + v418 r_2114 1 + v418 r_2115 1 + v419 r_47 1 + v419 r_286 1 + v419 r_629 -1 + v419 r_1389 1 + v419 r_1878 1 + v419 r_2114 1 + v419 r_2115 1 + v420 r_47 1 + v420 r_1987 1 + v420 r_2023 1 + v420 r_2041 1 + v420 r_2062 1 + v420 r_2670 1 + v420 r_2671 1 + v421 r_48 1 + v421 r_167 1 + v421 r_534 -1 + v421 r_1383 1 + v421 r_1451 1 + v421 r_2115 1 + v421 r_2232 1 + v422 r_48 1 + v422 r_331 1 + v422 r_689 1 + v422 r_815 1 + v422 r_1049 1 + v422 r_1178 1 + v422 r_2060 1 + v422 r_2062 1 + v422 r_2313 1 + v422 r_2421 1 + v422 r_2501 -1 + v422 r_2598 -1 + v422 r_2671 1 + v422 r_2771 1 + v422 r_2810 1 + v423 r_48 1 + v423 r_217 1 + v423 r_564 -1 + v423 r_1385 1 + v423 r_1627 1 + v423 r_2115 1 + v423 r_2232 1 + v424 r_48 1 + v424 r_235 1 + v424 r_581 -1 + v424 r_1386 1 + v424 r_1690 1 + v424 r_2115 1 + v424 r_2232 1 + v425 r_48 1 + v425 r_269 1 + v425 r_613 -1 + v425 r_1388 1 + v425 r_1812 1 + v425 r_2115 1 + v425 r_2232 1 + v426 r_48 1 + v426 r_287 1 + v426 r_630 -1 + v426 r_1389 1 + v426 r_1879 1 + v426 r_2115 1 + v426 r_2232 1 + v427 r_48 1 + v427 r_301 1 + v427 r_1390 1 + v427 r_1940 1 + v427 r_2115 1 + v427 r_2232 1 + v427 r_2985 1 + v428 r_49 1 + v428 r_151 1 + v428 r_643 -1 + v428 r_1391 1 + v428 r_1606 -1 + v428 r_2116 1 + v428 r_2117 1 + v428 r_2233 1 + v429 r_49 1 + v429 r_169 1 + v429 r_660 -1 + v429 r_1392 1 + v429 r_1614 -1 + v429 r_2116 1 + v429 r_2117 1 + v429 r_2233 1 + v429 r_2871 1 + v429 r_2872 1 + v429 r_2986 1 + v429 r_2987 1 + v430 r_49 1 + v430 r_183 1 + v430 r_673 -1 + v430 r_1393 1 + v430 r_1620 -1 + v430 r_2116 1 + v430 r_2117 1 + v430 r_2233 1 + v431 r_49 1 + v431 r_332 1 + v431 r_453 1 + v431 r_548 1 + v431 r_816 1 + v431 r_927 1 + v431 r_1050 1 + v431 r_1179 1 + v431 r_1299 1 + v431 r_2044 1 + v431 r_2314 1 + v431 r_2315 1 + v431 r_2422 1 + v431 r_2502 -1 + v431 r_2599 -1 + v431 r_2672 1 + v431 r_2673 1 + v431 r_2772 1 + v431 r_2811 1 + v431 r_2827 1 + v432 r_49 1 + v432 r_219 1 + v432 r_690 -1 + v432 r_1394 1 + v432 r_1628 -1 + v432 r_2116 1 + v432 r_2117 1 + v432 r_2233 1 + v433 r_49 1 + v433 r_237 1 + v433 r_707 -1 + v433 r_1395 1 + v433 r_1636 -1 + v433 r_2116 1 + v433 r_2117 1 + v433 r_2233 1 + v433 r_2871 1 + v433 r_2872 1 + v433 r_2986 1 + v433 r_2987 1 + v434 r_49 1 + v434 r_253 1 + v434 r_722 -1 + v434 r_1396 1 + v434 r_1643 -1 + v434 r_2116 1 + v434 r_2117 1 + v434 r_2233 1 + v435 r_49 1 + v435 r_271 1 + v435 r_739 -1 + v435 r_1397 1 + v435 r_1651 -1 + v435 r_2116 1 + v435 r_2117 1 + v435 r_2233 1 + v436 r_49 1 + v436 r_288 1 + v436 r_756 -1 + v436 r_1398 1 + v436 r_1659 -1 + v436 r_2116 1 + v436 r_2117 1 + v436 r_2233 1 + v436 r_2986 1 + v436 r_2987 1 + v437 r_49 1 + v437 r_1988 -1 + v437 r_2024 1 + v437 r_2029 1 + v437 r_2672 1 + v437 r_2673 1 + v437 r_2772 1 + v437 r_2819 1 + v437 r_2827 1 + v438 r_50 1 + v438 r_152 1 + v438 r_644 -1 + v438 r_1391 1 + v438 r_1607 -1 + v438 r_2116 1 + v438 r_2117 1 + v438 r_2118 1 + v439 r_50 1 + v439 r_170 1 + v439 r_661 -1 + v439 r_1392 1 + v439 r_1615 -1 + v439 r_2116 1 + v439 r_2117 1 + v439 r_2118 1 + v439 r_2872 1 + v439 r_2873 1 + v439 r_2986 1 + v439 r_2987 1 + v439 r_2988 1 + v440 r_50 1 + v440 r_184 1 + v440 r_674 -1 + v440 r_1393 1 + v440 r_1621 -1 + v440 r_2116 1 + v440 r_2117 1 + v440 r_2118 1 + v441 r_50 1 + v441 r_333 1 + v441 r_454 1 + v441 r_549 1 + v441 r_817 1 + v441 r_928 1 + v441 r_1051 1 + v441 r_1180 1 + v441 r_1300 1 + v441 r_2045 1 + v441 r_2314 1 + v441 r_2315 1 + v441 r_2316 1 + v441 r_2502 -1 + v441 r_2503 -1 + v441 r_2672 1 + v441 r_2673 1 + v441 r_2674 1 + v442 r_50 1 + v442 r_220 1 + v442 r_691 -1 + v442 r_1394 1 + v442 r_1629 -1 + v442 r_2116 1 + v442 r_2117 1 + v442 r_2118 1 + v443 r_50 1 + v443 r_238 1 + v443 r_708 -1 + v443 r_1395 1 + v443 r_1637 -1 + v443 r_2116 1 + v443 r_2117 1 + v443 r_2118 1 + v443 r_2872 1 + v443 r_2873 1 + v443 r_2986 1 + v443 r_2987 1 + v443 r_2988 1 + v444 r_50 1 + v444 r_254 1 + v444 r_723 -1 + v444 r_1396 1 + v444 r_1644 -1 + v444 r_2116 1 + v444 r_2117 1 + v444 r_2118 1 + v445 r_50 1 + v445 r_272 1 + v445 r_740 -1 + v445 r_1397 1 + v445 r_1652 -1 + v445 r_2116 1 + v445 r_2117 1 + v445 r_2118 1 + v446 r_50 1 + v446 r_289 1 + v446 r_757 -1 + v446 r_1398 1 + v446 r_1660 -1 + v446 r_2116 1 + v446 r_2117 1 + v446 r_2118 1 + v446 r_2986 1 + v446 r_2987 1 + v446 r_2988 1 + v447 r_50 1 + v447 r_1989 -1 + v447 r_2024 1 + v447 r_2030 1 + v447 r_2672 1 + v447 r_2673 1 + v447 r_2674 1 + v448 r_51 1 + v448 r_153 1 + v448 r_645 -1 + v448 r_1391 1 + v448 r_1608 -1 + v448 r_2117 1 + v448 r_2118 1 + v448 r_2119 1 + v448 r_2233 1 + v448 r_2234 1 + v449 r_51 1 + v449 r_171 1 + v449 r_662 -1 + v449 r_1392 1 + v449 r_1616 -1 + v449 r_2117 1 + v449 r_2118 1 + v449 r_2119 1 + v449 r_2233 1 + v449 r_2234 1 + v449 r_2873 1 + v449 r_2874 1 + v449 r_2987 1 + v449 r_2988 1 + v449 r_2989 1 + v450 r_51 1 + v450 r_185 1 + v450 r_675 -1 + v450 r_1393 1 + v450 r_1622 -1 + v450 r_2117 1 + v450 r_2118 1 + v450 r_2119 1 + v450 r_2233 1 + v450 r_2234 1 + v451 r_51 1 + v451 r_334 1 + v451 r_455 1 + v451 r_550 1 + v451 r_818 1 + v451 r_929 1 + v451 r_1052 1 + v451 r_1181 1 + v451 r_1301 1 + v451 r_2046 1 + v451 r_2315 1 + v451 r_2316 1 + v451 r_2317 1 + v451 r_2422 1 + v451 r_2423 1 + v451 r_2502 -1 + v451 r_2503 -1 + v451 r_2504 -1 + v451 r_2599 -1 + v451 r_2600 -1 + v451 r_2672 1 + v451 r_2673 1 + v451 r_2674 1 + v451 r_2675 1 + v451 r_2772 1 + v451 r_2773 1 + v451 r_2811 1 + v451 r_2827 1 + v452 r_51 1 + v452 r_221 1 + v452 r_692 -1 + v452 r_1394 1 + v452 r_1630 -1 + v452 r_2117 1 + v452 r_2118 1 + v452 r_2119 1 + v452 r_2233 1 + v452 r_2234 1 + v453 r_51 1 + v453 r_239 1 + v453 r_709 -1 + v453 r_1395 1 + v453 r_1638 -1 + v453 r_2117 1 + v453 r_2118 1 + v453 r_2119 1 + v453 r_2233 1 + v453 r_2234 1 + v453 r_2873 1 + v453 r_2874 1 + v453 r_2987 1 + v453 r_2988 1 + v453 r_2989 1 + v454 r_51 1 + v454 r_255 1 + v454 r_724 -1 + v454 r_1396 1 + v454 r_1645 -1 + v454 r_2117 1 + v454 r_2118 1 + v454 r_2119 1 + v454 r_2233 1 + v454 r_2234 1 + v455 r_51 1 + v455 r_273 1 + v455 r_741 -1 + v455 r_1397 1 + v455 r_1653 -1 + v455 r_2117 1 + v455 r_2118 1 + v455 r_2119 1 + v455 r_2233 1 + v455 r_2234 1 + v456 r_51 1 + v456 r_290 1 + v456 r_758 -1 + v456 r_1398 1 + v456 r_1661 -1 + v456 r_2117 1 + v456 r_2118 1 + v456 r_2119 1 + v456 r_2233 1 + v456 r_2234 1 + v456 r_2987 1 + v456 r_2988 1 + v456 r_2989 1 + v457 r_51 1 + v457 r_1990 -1 + v457 r_2024 1 + v457 r_2031 1 + v457 r_2672 1 + v457 r_2673 1 + v457 r_2674 1 + v457 r_2675 1 + v457 r_2772 1 + v457 r_2773 1 + v457 r_2819 1 + v457 r_2827 1 + v458 r_52 1 + v458 r_154 1 + v458 r_646 -1 + v458 r_1391 1 + v458 r_1609 -1 + v458 r_2118 1 + v458 r_2119 1 + v458 r_2120 1 + v459 r_52 1 + v459 r_172 1 + v459 r_663 -1 + v459 r_1392 1 + v459 r_1617 -1 + v459 r_2118 1 + v459 r_2119 1 + v459 r_2120 1 + v459 r_2874 1 + v459 r_2875 1 + v459 r_2988 1 + v459 r_2989 1 + v459 r_2990 1 + v460 r_52 1 + v460 r_186 1 + v460 r_676 -1 + v460 r_1393 1 + v460 r_1623 -1 + v460 r_2118 1 + v460 r_2119 1 + v460 r_2120 1 + v461 r_52 1 + v461 r_335 1 + v461 r_456 1 + v461 r_551 1 + v461 r_819 1 + v461 r_930 1 + v461 r_1053 1 + v461 r_1182 1 + v461 r_1302 1 + v461 r_2047 1 + v461 r_2316 1 + v461 r_2317 1 + v461 r_2318 1 + v461 r_2502 -1 + v461 r_2503 -1 + v461 r_2504 -1 + v461 r_2505 -1 + v461 r_2672 1 + v461 r_2673 1 + v461 r_2674 1 + v461 r_2675 1 + v461 r_2676 1 + v462 r_52 1 + v462 r_222 1 + v462 r_693 -1 + v462 r_1394 1 + v462 r_1631 -1 + v462 r_2118 1 + v462 r_2119 1 + v462 r_2120 1 + v463 r_52 1 + v463 r_240 1 + v463 r_710 -1 + v463 r_1395 1 + v463 r_1639 -1 + v463 r_2118 1 + v463 r_2119 1 + v463 r_2120 1 + v463 r_2874 1 + v463 r_2875 1 + v463 r_2988 1 + v463 r_2989 1 + v463 r_2990 1 + v464 r_52 1 + v464 r_256 1 + v464 r_725 -1 + v464 r_1396 1 + v464 r_1646 -1 + v464 r_2118 1 + v464 r_2119 1 + v464 r_2120 1 + v465 r_52 1 + v465 r_274 1 + v465 r_742 -1 + v465 r_1397 1 + v465 r_1654 -1 + v465 r_2118 1 + v465 r_2119 1 + v465 r_2120 1 + v466 r_52 1 + v466 r_291 1 + v466 r_759 -1 + v466 r_1398 1 + v466 r_1662 -1 + v466 r_2118 1 + v466 r_2119 1 + v466 r_2120 1 + v466 r_2988 1 + v466 r_2989 1 + v466 r_2990 1 + v467 r_52 1 + v467 r_1991 -1 + v467 r_2024 1 + v467 r_2032 1 + v467 r_2672 1 + v467 r_2673 1 + v467 r_2674 1 + v467 r_2675 1 + v467 r_2676 1 + v468 r_53 1 + v468 r_155 1 + v468 r_647 -1 + v468 r_1391 1 + v468 r_1610 -1 + v468 r_2119 1 + v468 r_2120 1 + v468 r_2121 1 + v468 r_2233 1 + v468 r_2234 1 + v468 r_2235 1 + v469 r_53 1 + v469 r_173 1 + v469 r_664 -1 + v469 r_1392 1 + v469 r_1618 -1 + v469 r_2119 1 + v469 r_2120 1 + v469 r_2121 1 + v469 r_2233 1 + v469 r_2234 1 + v469 r_2235 1 + v469 r_2875 1 + v469 r_2876 1 + v469 r_2989 1 + v469 r_2990 1 + v469 r_2991 1 + v470 r_53 1 + v470 r_187 1 + v470 r_677 -1 + v470 r_1393 1 + v470 r_1624 -1 + v470 r_2119 1 + v470 r_2120 1 + v470 r_2121 1 + v470 r_2233 1 + v470 r_2234 1 + v470 r_2235 1 + v471 r_53 1 + v471 r_336 1 + v471 r_457 1 + v471 r_552 1 + v471 r_820 1 + v471 r_931 1 + v471 r_1054 1 + v471 r_1183 1 + v471 r_1303 1 + v471 r_2048 1 + v471 r_2317 1 + v471 r_2318 1 + v471 r_2319 1 + v471 r_2422 1 + v471 r_2423 1 + v471 r_2424 1 + v471 r_2503 -1 + v471 r_2504 -1 + v471 r_2505 -1 + v471 r_2506 -1 + v471 r_2599 -1 + v471 r_2600 -1 + v471 r_2601 -1 + v471 r_2673 1 + v471 r_2674 1 + v471 r_2675 1 + v471 r_2676 1 + v471 r_2677 1 + v471 r_2772 1 + v471 r_2773 1 + v471 r_2774 1 + v471 r_2811 1 + v471 r_2827 1 + v472 r_53 1 + v472 r_223 1 + v472 r_694 -1 + v472 r_1394 1 + v472 r_1632 -1 + v472 r_2119 1 + v472 r_2120 1 + v472 r_2121 1 + v472 r_2233 1 + v472 r_2234 1 + v472 r_2235 1 + v473 r_53 1 + v473 r_241 1 + v473 r_711 -1 + v473 r_1395 1 + v473 r_1640 -1 + v473 r_2119 1 + v473 r_2120 1 + v473 r_2121 1 + v473 r_2233 1 + v473 r_2234 1 + v473 r_2235 1 + v473 r_2875 1 + v473 r_2876 1 + v473 r_2989 1 + v473 r_2990 1 + v473 r_2991 1 + v474 r_53 1 + v474 r_257 1 + v474 r_726 -1 + v474 r_1396 1 + v474 r_1647 -1 + v474 r_2119 1 + v474 r_2120 1 + v474 r_2121 1 + v474 r_2233 1 + v474 r_2234 1 + v474 r_2235 1 + v475 r_53 1 + v475 r_275 1 + v475 r_743 -1 + v475 r_1397 1 + v475 r_1655 -1 + v475 r_2119 1 + v475 r_2120 1 + v475 r_2121 1 + v475 r_2233 1 + v475 r_2234 1 + v475 r_2235 1 + v476 r_53 1 + v476 r_292 1 + v476 r_760 -1 + v476 r_1398 1 + v476 r_1663 -1 + v476 r_2119 1 + v476 r_2120 1 + v476 r_2121 1 + v476 r_2233 1 + v476 r_2234 1 + v476 r_2235 1 + v476 r_2989 1 + v476 r_2990 1 + v476 r_2991 1 + v477 r_53 1 + v477 r_1992 -1 + v477 r_2024 1 + v477 r_2033 1 + v477 r_2673 1 + v477 r_2674 1 + v477 r_2675 1 + v477 r_2676 1 + v477 r_2677 1 + v477 r_2772 1 + v477 r_2773 1 + v477 r_2774 1 + v477 r_2819 1 + v477 r_2827 1 + v478 r_54 1 + v478 r_156 1 + v478 r_648 -1 + v478 r_1391 1 + v478 r_1611 -1 + v478 r_2120 1 + v478 r_2121 1 + v478 r_2122 1 + v479 r_54 1 + v479 r_188 1 + v479 r_678 -1 + v479 r_1393 1 + v479 r_1625 -1 + v479 r_2120 1 + v479 r_2121 1 + v479 r_2122 1 + v480 r_54 1 + v480 r_337 1 + v480 r_553 1 + v480 r_821 1 + v480 r_932 1 + v480 r_1055 1 + v480 r_1184 1 + v480 r_1304 1 + v480 r_2049 1 + v480 r_2318 1 + v480 r_2319 1 + v480 r_2320 1 + v480 r_2504 -1 + v480 r_2505 -1 + v480 r_2506 -1 + v480 r_2507 -1 + v480 r_2674 1 + v480 r_2675 1 + v480 r_2676 1 + v480 r_2677 1 + v480 r_2678 1 + v481 r_54 1 + v481 r_224 1 + v481 r_695 -1 + v481 r_1394 1 + v481 r_1633 -1 + v481 r_2120 1 + v481 r_2121 1 + v481 r_2122 1 + v482 r_54 1 + v482 r_242 1 + v482 r_712 -1 + v482 r_1395 1 + v482 r_1641 -1 + v482 r_2120 1 + v482 r_2121 1 + v482 r_2122 1 + v482 r_2876 1 + v482 r_2877 1 + v482 r_2990 1 + v482 r_2991 1 + v482 r_2992 1 + v483 r_54 1 + v483 r_258 1 + v483 r_727 -1 + v483 r_1396 1 + v483 r_1648 -1 + v483 r_2120 1 + v483 r_2121 1 + v483 r_2122 1 + v484 r_54 1 + v484 r_276 1 + v484 r_744 -1 + v484 r_1397 1 + v484 r_1656 -1 + v484 r_2120 1 + v484 r_2121 1 + v484 r_2122 1 + v485 r_54 1 + v485 r_293 1 + v485 r_761 -1 + v485 r_1398 1 + v485 r_1664 -1 + v485 r_2120 1 + v485 r_2121 1 + v485 r_2122 1 + v485 r_2990 1 + v485 r_2991 1 + v485 r_2992 1 + v486 r_55 1 + v486 r_157 1 + v486 r_649 -1 + v486 r_1391 1 + v486 r_2121 1 + v486 r_2122 1 + v486 r_2123 1 + v486 r_2234 1 + v486 r_2235 1 + v486 r_2236 1 + v487 r_55 1 + v487 r_174 1 + v487 r_665 -1 + v487 r_1392 1 + v487 r_1512 1 + v487 r_2121 1 + v487 r_2122 1 + v487 r_2123 1 + v487 r_2234 1 + v487 r_2235 1 + v487 r_2236 1 + v487 r_2877 1 + v487 r_2878 1 + v487 r_2991 1 + v487 r_2992 1 + v487 r_2993 1 + v488 r_55 1 + v488 r_189 1 + v488 r_679 -1 + v488 r_1393 1 + v488 r_2121 1 + v488 r_2122 1 + v488 r_2123 1 + v488 r_2234 1 + v488 r_2235 1 + v488 r_2236 1 + v489 r_55 1 + v489 r_338 1 + v489 r_458 1 + v489 r_554 1 + v489 r_822 1 + v489 r_933 1 + v489 r_1056 1 + v489 r_1185 1 + v489 r_2050 1 + v489 r_2319 1 + v489 r_2320 1 + v489 r_2321 1 + v489 r_2423 1 + v489 r_2424 1 + v489 r_2425 1 + v489 r_2505 -1 + v489 r_2506 -1 + v489 r_2507 -1 + v489 r_2508 -1 + v489 r_2599 -1 + v489 r_2600 -1 + v489 r_2601 -1 + v489 r_2602 -1 + v489 r_2675 1 + v489 r_2676 1 + v489 r_2677 1 + v489 r_2678 1 + v489 r_2679 1 + v489 r_2772 1 + v489 r_2773 1 + v489 r_2774 1 + v489 r_2775 1 + v489 r_2811 1 + v489 r_2827 1 + v490 r_55 1 + v490 r_225 1 + v490 r_696 -1 + v490 r_1394 1 + v490 r_1691 1 + v490 r_2121 1 + v490 r_2122 1 + v490 r_2123 1 + v490 r_2234 1 + v490 r_2235 1 + v490 r_2236 1 + v491 r_55 1 + v491 r_243 1 + v491 r_713 -1 + v491 r_1395 1 + v491 r_1749 1 + v491 r_2121 1 + v491 r_2122 1 + v491 r_2123 1 + v491 r_2234 1 + v491 r_2235 1 + v491 r_2236 1 + v491 r_2877 1 + v491 r_2878 1 + v491 r_2991 1 + v491 r_2992 1 + v491 r_2993 1 + v492 r_55 1 + v492 r_259 1 + v492 r_728 -1 + v492 r_1396 1 + v492 r_1813 1 + v492 r_2121 1 + v492 r_2122 1 + v492 r_2123 1 + v492 r_2234 1 + v492 r_2235 1 + v492 r_2236 1 + v493 r_55 1 + v493 r_277 1 + v493 r_745 -1 + v493 r_1397 1 + v493 r_1880 1 + v493 r_2121 1 + v493 r_2122 1 + v493 r_2123 1 + v493 r_2234 1 + v493 r_2235 1 + v493 r_2236 1 + v494 r_56 1 + v494 r_158 1 + v494 r_650 -1 + v494 r_1391 1 + v494 r_1452 1 + v494 r_2122 1 + v494 r_2123 1 + v494 r_2124 1 + v495 r_56 1 + v495 r_175 1 + v495 r_666 -1 + v495 r_1392 1 + v495 r_1513 1 + v495 r_2122 1 + v495 r_2123 1 + v495 r_2124 1 + v495 r_2878 1 + v495 r_2879 1 + v495 r_2992 1 + v495 r_2993 1 + v495 r_2994 1 + v496 r_56 1 + v496 r_190 1 + v496 r_680 -1 + v496 r_1393 1 + v496 r_1560 1 + v496 r_2122 1 + v496 r_2123 1 + v496 r_2124 1 + v497 r_56 1 + v497 r_339 1 + v497 r_459 1 + v497 r_555 1 + v497 r_823 1 + v497 r_934 1 + v497 r_1057 1 + v497 r_1186 1 + v497 r_1305 1 + v497 r_2051 1 + v497 r_2320 1 + v497 r_2321 1 + v497 r_2322 1 + v497 r_2506 -1 + v497 r_2507 -1 + v497 r_2508 -1 + v497 r_2509 -1 + v497 r_2676 1 + v497 r_2677 1 + v497 r_2678 1 + v497 r_2679 1 + v497 r_2680 1 + v498 r_56 1 + v498 r_226 1 + v498 r_697 -1 + v498 r_1394 1 + v498 r_1692 1 + v498 r_2122 1 + v498 r_2123 1 + v498 r_2124 1 + v499 r_56 1 + v499 r_244 1 + v499 r_714 -1 + v499 r_1395 1 + v499 r_1750 1 + v499 r_2122 1 + v499 r_2123 1 + v499 r_2124 1 + v499 r_2878 1 + v499 r_2879 1 + v499 r_2992 1 + v499 r_2993 1 + v499 r_2994 1 + v500 r_56 1 + v500 r_260 1 + v500 r_729 -1 + v500 r_1396 1 + v500 r_1814 1 + v500 r_2122 1 + v500 r_2123 1 + v500 r_2124 1 + v501 r_56 1 + v501 r_278 1 + v501 r_746 -1 + v501 r_1397 1 + v501 r_1881 1 + v501 r_2122 1 + v501 r_2123 1 + v501 r_2124 1 + v502 r_56 1 + v502 r_294 1 + v502 r_762 -1 + v502 r_1398 1 + v502 r_1941 1 + v502 r_2122 1 + v502 r_2123 1 + v502 r_2124 1 + v502 r_2992 1 + v502 r_2993 1 + v502 r_2994 1 + v503 r_56 1 + v503 r_1988 1 + v503 r_2024 1 + v503 r_2034 1 + v503 r_2676 1 + v503 r_2677 1 + v503 r_2678 1 + v503 r_2679 1 + v503 r_2680 1 + v504 r_57 1 + v504 r_159 1 + v504 r_651 -1 + v504 r_1391 1 + v504 r_1612 -1 + v504 r_2123 1 + v504 r_2124 1 + v504 r_2125 1 + v504 r_2235 1 + v504 r_2236 1 + v504 r_2237 1 + v505 r_57 1 + v505 r_176 1 + v505 r_667 -1 + v505 r_1392 1 + v505 r_1619 -1 + v505 r_2123 1 + v505 r_2124 1 + v505 r_2125 1 + v505 r_2235 1 + v505 r_2236 1 + v505 r_2237 1 + v505 r_2879 1 + v505 r_2880 1 + v505 r_2993 1 + v505 r_2994 1 + v505 r_2995 1 + v506 r_57 1 + v506 r_191 1 + v506 r_681 -1 + v506 r_1393 1 + v506 r_1626 -1 + v506 r_2123 1 + v506 r_2124 1 + v506 r_2125 1 + v506 r_2235 1 + v506 r_2236 1 + v506 r_2237 1 + v507 r_57 1 + v507 r_340 1 + v507 r_460 1 + v507 r_556 1 + v507 r_824 1 + v507 r_935 1 + v507 r_1058 1 + v507 r_1187 1 + v507 r_2052 1 + v507 r_2321 1 + v507 r_2322 1 + v507 r_2323 1 + v507 r_2424 1 + v507 r_2425 1 + v507 r_2426 1 + v507 r_2507 -1 + v507 r_2508 -1 + v507 r_2509 -1 + v507 r_2510 -1 + v507 r_2600 -1 + v507 r_2601 -1 + v507 r_2602 -1 + v507 r_2603 -1 + v507 r_2677 1 + v507 r_2678 1 + v507 r_2679 1 + v507 r_2680 1 + v507 r_2681 1 + v507 r_2773 1 + v507 r_2774 1 + v507 r_2775 1 + v507 r_2776 1 + v507 r_2811 1 + v507 r_2827 1 + v508 r_57 1 + v508 r_227 1 + v508 r_698 -1 + v508 r_1394 1 + v508 r_1634 -1 + v508 r_2123 1 + v508 r_2124 1 + v508 r_2125 1 + v508 r_2235 1 + v508 r_2236 1 + v508 r_2237 1 + v509 r_57 1 + v509 r_245 1 + v509 r_715 -1 + v509 r_1395 1 + v509 r_1642 -1 + v509 r_2123 1 + v509 r_2124 1 + v509 r_2125 1 + v509 r_2235 1 + v509 r_2236 1 + v509 r_2237 1 + v509 r_2879 1 + v509 r_2880 1 + v509 r_2993 1 + v509 r_2994 1 + v509 r_2995 1 + v510 r_57 1 + v510 r_261 1 + v510 r_730 -1 + v510 r_1396 1 + v510 r_1649 -1 + v510 r_2123 1 + v510 r_2124 1 + v510 r_2125 1 + v510 r_2235 1 + v510 r_2236 1 + v510 r_2237 1 + v511 r_57 1 + v511 r_279 1 + v511 r_747 -1 + v511 r_1397 1 + v511 r_1657 -1 + v511 r_2123 1 + v511 r_2124 1 + v511 r_2125 1 + v511 r_2235 1 + v511 r_2236 1 + v511 r_2237 1 + v512 r_57 1 + v512 r_295 1 + v512 r_1398 1 + v512 r_1665 -1 + v512 r_2123 1 + v512 r_2124 1 + v512 r_2125 1 + v512 r_2235 1 + v512 r_2236 1 + v512 r_2237 1 + v512 r_2993 1 + v512 r_2994 1 + v512 r_2995 1 + v513 r_57 1 + v513 r_1993 -1 + v513 r_2024 1 + v513 r_2035 1 + v513 r_2677 1 + v513 r_2678 1 + v513 r_2679 1 + v513 r_2680 1 + v513 r_2681 1 + v513 r_2773 1 + v513 r_2774 1 + v513 r_2775 1 + v513 r_2776 1 + v513 r_2819 1 + v513 r_2827 1 + v514 r_58 1 + v514 r_160 1 + v514 r_652 -1 + v514 r_1391 1 + v514 r_1613 -1 + v514 r_2124 1 + v514 r_2125 1 + v514 r_2126 1 + v515 r_58 1 + v515 r_192 1 + v515 r_682 -1 + v515 r_1393 1 + v515 r_1627 -1 + v515 r_2124 1 + v515 r_2125 1 + v515 r_2126 1 + v516 r_58 1 + v516 r_341 1 + v516 r_557 1 + v516 r_825 1 + v516 r_1059 1 + v516 r_1188 1 + v516 r_1306 1 + v516 r_2053 1 + v516 r_2322 1 + v516 r_2323 1 + v516 r_2324 1 + v516 r_2508 -1 + v516 r_2509 -1 + v516 r_2510 -1 + v516 r_2511 -1 + v516 r_2678 1 + v516 r_2679 1 + v516 r_2680 1 + v516 r_2681 1 + v516 r_2682 1 + v517 r_58 1 + v517 r_228 1 + v517 r_699 -1 + v517 r_1394 1 + v517 r_1635 -1 + v517 r_2124 1 + v517 r_2125 1 + v517 r_2126 1 + v518 r_58 1 + v518 r_262 1 + v518 r_731 -1 + v518 r_1396 1 + v518 r_1650 -1 + v518 r_2124 1 + v518 r_2125 1 + v518 r_2126 1 + v519 r_58 1 + v519 r_280 1 + v519 r_748 -1 + v519 r_1397 1 + v519 r_1658 -1 + v519 r_2124 1 + v519 r_2125 1 + v519 r_2126 1 + v520 r_58 1 + v520 r_1994 -1 + v520 r_2024 1 + v520 r_2036 1 + v520 r_2678 1 + v520 r_2679 1 + v520 r_2680 1 + v520 r_2681 1 + v520 r_2682 1 + v521 r_59 1 + v521 r_161 1 + v521 r_653 -1 + v521 r_1391 1 + v521 r_1453 1 + v521 r_2125 1 + v521 r_2126 1 + v521 r_2127 1 + v521 r_2236 1 + v521 r_2237 1 + v521 r_2238 1 + v522 r_59 1 + v522 r_177 1 + v522 r_668 -1 + v522 r_1392 1 + v522 r_1514 1 + v522 r_2125 1 + v522 r_2126 1 + v522 r_2127 1 + v522 r_2236 1 + v522 r_2237 1 + v522 r_2238 1 + v522 r_2836 1 + v522 r_2881 1 + v522 r_2882 1 + v522 r_2995 1 + v522 r_2996 1 + v522 r_2997 1 + v523 r_59 1 + v523 r_193 1 + v523 r_683 -1 + v523 r_1393 1 + v523 r_1561 1 + v523 r_2125 1 + v523 r_2126 1 + v523 r_2127 1 + v523 r_2236 1 + v523 r_2237 1 + v523 r_2238 1 + v524 r_59 1 + v524 r_342 1 + v524 r_461 1 + v524 r_558 1 + v524 r_826 1 + v524 r_936 1 + v524 r_1060 1 + v524 r_1189 1 + v524 r_1307 1 + v524 r_2054 1 + v524 r_2323 1 + v524 r_2324 1 + v524 r_2325 1 + v524 r_2425 1 + v524 r_2426 1 + v524 r_2427 1 + v524 r_2509 -1 + v524 r_2510 -1 + v524 r_2511 -1 + v524 r_2512 -1 + v524 r_2601 -1 + v524 r_2602 -1 + v524 r_2603 -1 + v524 r_2604 -1 + v524 r_2679 1 + v524 r_2680 1 + v524 r_2681 1 + v524 r_2682 1 + v524 r_2683 1 + v524 r_2774 1 + v524 r_2775 1 + v524 r_2776 1 + v524 r_2777 1 + v524 r_2811 1 + v525 r_59 1 + v525 r_229 1 + v525 r_700 -1 + v525 r_1394 1 + v525 r_1693 1 + v525 r_2125 1 + v525 r_2126 1 + v525 r_2127 1 + v525 r_2236 1 + v525 r_2237 1 + v525 r_2238 1 + v526 r_59 1 + v526 r_246 1 + v526 r_716 -1 + v526 r_1395 1 + v526 r_1751 1 + v526 r_2125 1 + v526 r_2126 1 + v526 r_2127 1 + v526 r_2236 1 + v526 r_2237 1 + v526 r_2238 1 + v526 r_2835 1 + v526 r_2881 1 + v526 r_2882 1 + v526 r_2995 1 + v526 r_2996 1 + v526 r_2997 1 + v527 r_59 1 + v527 r_263 1 + v527 r_732 -1 + v527 r_1396 1 + v527 r_1815 1 + v527 r_2125 1 + v527 r_2126 1 + v527 r_2127 1 + v527 r_2236 1 + v527 r_2237 1 + v527 r_2238 1 + v528 r_59 1 + v528 r_281 1 + v528 r_749 -1 + v528 r_1397 1 + v528 r_1882 1 + v528 r_2125 1 + v528 r_2126 1 + v528 r_2127 1 + v528 r_2236 1 + v528 r_2237 1 + v528 r_2238 1 + v529 r_59 1 + v529 r_296 1 + v529 r_763 -1 + v529 r_1398 1 + v529 r_1942 1 + v529 r_2125 1 + v529 r_2126 1 + v529 r_2127 1 + v529 r_2236 1 + v529 r_2237 1 + v529 r_2238 1 + v529 r_2995 1 + v529 r_2996 1 + v529 r_2997 1 + v530 r_59 1 + v530 r_1989 1 + v530 r_2024 1 + v530 r_2037 1 + v530 r_2679 1 + v530 r_2680 1 + v530 r_2681 1 + v530 r_2682 1 + v530 r_2683 1 + v530 r_2774 1 + v530 r_2775 1 + v530 r_2776 1 + v530 r_2777 1 + v530 r_2819 1 + v531 r_60 1 + v531 r_162 1 + v531 r_654 -1 + v531 r_1391 1 + v531 r_1454 1 + v531 r_2126 1 + v531 r_2127 1 + v531 r_2128 1 + v532 r_60 1 + v532 r_178 1 + v532 r_669 -1 + v532 r_1392 1 + v532 r_1515 1 + v532 r_2126 1 + v532 r_2127 1 + v532 r_2128 1 + v532 r_2836 1 + v532 r_2882 1 + v532 r_2883 1 + v532 r_2996 1 + v532 r_2997 1 + v532 r_2998 1 + v533 r_60 1 + v533 r_194 1 + v533 r_684 -1 + v533 r_1393 1 + v533 r_1562 1 + v533 r_2126 1 + v533 r_2127 1 + v533 r_2128 1 + v534 r_60 1 + v534 r_343 1 + v534 r_462 1 + v534 r_559 1 + v534 r_827 1 + v534 r_937 1 + v534 r_1061 1 + v534 r_1190 1 + v534 r_1308 1 + v534 r_2055 1 + v534 r_2324 1 + v534 r_2325 1 + v534 r_2326 1 + v534 r_2510 -1 + v534 r_2511 -1 + v534 r_2512 -1 + v534 r_2513 -1 + v534 r_2680 1 + v534 r_2681 1 + v534 r_2682 1 + v534 r_2683 1 + v534 r_2684 1 + v535 r_60 1 + v535 r_230 1 + v535 r_701 -1 + v535 r_1394 1 + v535 r_1694 1 + v535 r_2126 1 + v535 r_2127 1 + v535 r_2128 1 + v536 r_60 1 + v536 r_247 1 + v536 r_717 -1 + v536 r_1395 1 + v536 r_1752 1 + v536 r_2126 1 + v536 r_2127 1 + v536 r_2128 1 + v536 r_2835 1 + v536 r_2882 1 + v536 r_2883 1 + v536 r_2996 1 + v536 r_2997 1 + v536 r_2998 1 + v537 r_60 1 + v537 r_264 1 + v537 r_733 -1 + v537 r_1396 1 + v537 r_1816 1 + v537 r_2126 1 + v537 r_2127 1 + v537 r_2128 1 + v538 r_60 1 + v538 r_282 1 + v538 r_750 -1 + v538 r_1397 1 + v538 r_1883 1 + v538 r_2126 1 + v538 r_2127 1 + v538 r_2128 1 + v539 r_60 1 + v539 r_297 1 + v539 r_764 -1 + v539 r_1398 1 + v539 r_1943 1 + v539 r_2126 1 + v539 r_2127 1 + v539 r_2128 1 + v539 r_2996 1 + v539 r_2997 1 + v539 r_2998 1 + v540 r_60 1 + v540 r_1990 1 + v540 r_2024 1 + v540 r_2038 1 + v540 r_2680 1 + v540 r_2681 1 + v540 r_2682 1 + v540 r_2683 1 + v540 r_2684 1 + v541 r_61 1 + v541 r_163 1 + v541 r_655 -1 + v541 r_1391 1 + v541 r_1455 1 + v541 r_2127 1 + v541 r_2128 1 + v541 r_2129 1 + v541 r_2237 1 + v541 r_2238 1 + v541 r_2239 1 + v542 r_61 1 + v542 r_179 1 + v542 r_670 -1 + v542 r_1392 1 + v542 r_1516 1 + v542 r_2127 1 + v542 r_2128 1 + v542 r_2129 1 + v542 r_2237 1 + v542 r_2238 1 + v542 r_2239 1 + v542 r_2836 1 + v542 r_2883 1 + v542 r_2884 1 + v542 r_2997 1 + v542 r_2998 1 + v542 r_2999 1 + v543 r_61 1 + v543 r_195 1 + v543 r_685 -1 + v543 r_1393 1 + v543 r_1563 1 + v543 r_2127 1 + v543 r_2128 1 + v543 r_2129 1 + v543 r_2237 1 + v543 r_2238 1 + v543 r_2239 1 + v544 r_61 1 + v544 r_344 1 + v544 r_463 1 + v544 r_560 1 + v544 r_828 1 + v544 r_938 1 + v544 r_1062 1 + v544 r_1191 1 + v544 r_1309 1 + v544 r_2056 1 + v544 r_2325 1 + v544 r_2326 1 + v544 r_2327 1 + v544 r_2426 1 + v544 r_2427 1 + v544 r_2428 1 + v544 r_2511 -1 + v544 r_2512 -1 + v544 r_2513 -1 + v544 r_2514 -1 + v544 r_2602 -1 + v544 r_2603 -1 + v544 r_2604 -1 + v544 r_2681 1 + v544 r_2682 1 + v544 r_2683 1 + v544 r_2684 1 + v544 r_2685 1 + v544 r_2775 1 + v544 r_2776 1 + v544 r_2777 1 + v544 r_2811 1 + v545 r_61 1 + v545 r_231 1 + v545 r_702 -1 + v545 r_1394 1 + v545 r_1695 1 + v545 r_2127 1 + v545 r_2128 1 + v545 r_2129 1 + v545 r_2237 1 + v545 r_2238 1 + v545 r_2239 1 + v546 r_61 1 + v546 r_248 1 + v546 r_718 -1 + v546 r_1395 1 + v546 r_1753 1 + v546 r_2127 1 + v546 r_2128 1 + v546 r_2129 1 + v546 r_2237 1 + v546 r_2238 1 + v546 r_2239 1 + v546 r_2835 1 + v546 r_2883 1 + v546 r_2884 1 + v546 r_2997 1 + v546 r_2998 1 + v546 r_2999 1 + v547 r_61 1 + v547 r_265 1 + v547 r_734 -1 + v547 r_1396 1 + v547 r_1817 1 + v547 r_2127 1 + v547 r_2128 1 + v547 r_2129 1 + v547 r_2237 1 + v547 r_2238 1 + v547 r_2239 1 + v548 r_61 1 + v548 r_283 1 + v548 r_751 -1 + v548 r_1397 1 + v548 r_1884 1 + v548 r_2127 1 + v548 r_2128 1 + v548 r_2129 1 + v548 r_2237 1 + v548 r_2238 1 + v548 r_2239 1 + v549 r_61 1 + v549 r_298 1 + v549 r_765 -1 + v549 r_1398 1 + v549 r_1944 1 + v549 r_2127 1 + v549 r_2128 1 + v549 r_2129 1 + v549 r_2237 1 + v549 r_2238 1 + v549 r_2239 1 + v549 r_2997 1 + v549 r_2998 1 + v549 r_2999 1 + v550 r_61 1 + v550 r_1991 1 + v550 r_2024 1 + v550 r_2039 1 + v550 r_2681 1 + v550 r_2682 1 + v550 r_2683 1 + v550 r_2684 1 + v550 r_2685 1 + v550 r_2775 1 + v550 r_2776 1 + v550 r_2777 1 + v550 r_2819 1 + v551 r_62 1 + v551 r_164 1 + v551 r_656 -1 + v551 r_1391 1 + v551 r_1456 1 + v551 r_2128 1 + v551 r_2129 1 + v551 r_2130 1 + v552 r_62 1 + v552 r_180 1 + v552 r_671 -1 + v552 r_1392 1 + v552 r_1517 1 + v552 r_2128 1 + v552 r_2129 1 + v552 r_2130 1 + v552 r_2836 1 + v552 r_2884 1 + v552 r_2885 1 + v552 r_2998 1 + v552 r_2999 1 + v552 r_3000 1 + v553 r_62 1 + v553 r_196 1 + v553 r_686 -1 + v553 r_1393 1 + v553 r_1564 1 + v553 r_2128 1 + v553 r_2129 1 + v553 r_2130 1 + v554 r_62 1 + v554 r_345 1 + v554 r_464 1 + v554 r_561 1 + v554 r_829 1 + v554 r_939 1 + v554 r_1063 1 + v554 r_1192 1 + v554 r_1310 1 + v554 r_2057 1 + v554 r_2326 1 + v554 r_2327 1 + v554 r_2328 1 + v554 r_2512 -1 + v554 r_2513 -1 + v554 r_2514 -1 + v554 r_2515 -1 + v554 r_2682 1 + v554 r_2683 1 + v554 r_2684 1 + v554 r_2685 1 + v555 r_62 1 + v555 r_232 1 + v555 r_703 -1 + v555 r_1394 1 + v555 r_1696 1 + v555 r_2128 1 + v555 r_2129 1 + v555 r_2130 1 + v556 r_62 1 + v556 r_249 1 + v556 r_719 -1 + v556 r_1395 1 + v556 r_1754 1 + v556 r_2128 1 + v556 r_2129 1 + v556 r_2130 1 + v556 r_2835 1 + v556 r_2884 1 + v556 r_2885 1 + v556 r_2998 1 + v556 r_2999 1 + v556 r_3000 1 + v557 r_62 1 + v557 r_266 1 + v557 r_735 -1 + v557 r_1396 1 + v557 r_1818 1 + v557 r_2128 1 + v557 r_2129 1 + v557 r_2130 1 + v558 r_62 1 + v558 r_284 1 + v558 r_752 -1 + v558 r_1397 1 + v558 r_1885 1 + v558 r_2128 1 + v558 r_2129 1 + v558 r_2130 1 + v559 r_62 1 + v559 r_299 1 + v559 r_766 -1 + v559 r_1398 1 + v559 r_1945 1 + v559 r_2128 1 + v559 r_2129 1 + v559 r_2130 1 + v559 r_2998 1 + v559 r_2999 1 + v559 r_3000 1 + v560 r_62 1 + v560 r_1992 1 + v560 r_2024 1 + v560 r_2040 1 + v560 r_2682 1 + v560 r_2683 1 + v560 r_2684 1 + v560 r_2685 1 + v561 r_63 1 + v561 r_165 1 + v561 r_657 -1 + v561 r_1391 1 + v561 r_1457 1 + v561 r_2129 1 + v561 r_2130 1 + v561 r_2131 1 + v561 r_2238 1 + v561 r_2239 1 + v562 r_63 1 + v562 r_197 1 + v562 r_687 -1 + v562 r_1393 1 + v562 r_1565 1 + v562 r_2129 1 + v562 r_2130 1 + v562 r_2131 1 + v562 r_2238 1 + v562 r_2239 1 + v563 r_63 1 + v563 r_346 1 + v563 r_562 1 + v563 r_830 1 + v563 r_940 1 + v563 r_1064 1 + v563 r_1193 1 + v563 r_1311 1 + v563 r_2058 1 + v563 r_2327 1 + v563 r_2328 1 + v563 r_2329 1 + v563 r_2427 1 + v563 r_2428 1 + v563 r_2513 -1 + v563 r_2514 -1 + v563 r_2515 -1 + v563 r_2603 -1 + v563 r_2604 -1 + v563 r_2683 1 + v563 r_2684 1 + v563 r_2685 1 + v563 r_2776 1 + v563 r_2777 1 + v563 r_2811 1 + v564 r_63 1 + v564 r_233 1 + v564 r_704 -1 + v564 r_1394 1 + v564 r_1697 1 + v564 r_2129 1 + v564 r_2130 1 + v564 r_2131 1 + v564 r_2238 1 + v564 r_2239 1 + v565 r_63 1 + v565 r_250 1 + v565 r_720 -1 + v565 r_1395 1 + v565 r_1755 1 + v565 r_2129 1 + v565 r_2130 1 + v565 r_2131 1 + v565 r_2238 1 + v565 r_2239 1 + v565 r_2835 1 + v565 r_2885 1 + v565 r_2886 1 + v565 r_2999 1 + v565 r_3000 1 + v565 r_3001 1 + v566 r_63 1 + v566 r_267 1 + v566 r_736 -1 + v566 r_1396 1 + v566 r_1819 1 + v566 r_2129 1 + v566 r_2130 1 + v566 r_2131 1 + v566 r_2238 1 + v566 r_2239 1 + v567 r_63 1 + v567 r_285 1 + v567 r_753 -1 + v567 r_1397 1 + v567 r_1886 1 + v567 r_2129 1 + v567 r_2130 1 + v567 r_2131 1 + v567 r_2238 1 + v567 r_2239 1 + v568 r_63 1 + v568 r_300 1 + v568 r_767 -1 + v568 r_1398 1 + v568 r_1946 1 + v568 r_2129 1 + v568 r_2130 1 + v568 r_2131 1 + v568 r_2238 1 + v568 r_2239 1 + v568 r_2999 1 + v568 r_3000 1 + v568 r_3001 1 + v569 r_64 1 + v569 r_166 1 + v569 r_658 -1 + v569 r_1391 1 + v569 r_1458 1 + v569 r_2130 1 + v569 r_2131 1 + v570 r_64 1 + v570 r_181 1 + v570 r_672 -1 + v570 r_1392 1 + v570 r_1518 1 + v570 r_2130 1 + v570 r_2131 1 + v570 r_2836 1 + v570 r_2886 1 + v570 r_2887 1 + v570 r_3000 1 + v570 r_3001 1 + v571 r_64 1 + v571 r_198 1 + v571 r_688 -1 + v571 r_1393 1 + v571 r_1566 1 + v571 r_2130 1 + v571 r_2131 1 + v572 r_64 1 + v572 r_347 1 + v572 r_465 1 + v572 r_563 1 + v572 r_831 1 + v572 r_941 1 + v572 r_1065 1 + v572 r_1194 1 + v572 r_1312 1 + v572 r_2059 1 + v572 r_2063 1 + v572 r_2328 1 + v572 r_2329 1 + v572 r_2514 -1 + v572 r_2515 -1 + v572 r_2684 1 + v572 r_2685 1 + v573 r_64 1 + v573 r_234 1 + v573 r_705 -1 + v573 r_1394 1 + v573 r_1698 1 + v573 r_2130 1 + v573 r_2131 1 + v574 r_64 1 + v574 r_251 1 + v574 r_721 -1 + v574 r_1395 1 + v574 r_1756 1 + v574 r_2130 1 + v574 r_2131 1 + v574 r_2835 1 + v574 r_2886 1 + v574 r_2887 1 + v574 r_3000 1 + v574 r_3001 1 + v575 r_64 1 + v575 r_268 1 + v575 r_737 -1 + v575 r_1396 1 + v575 r_1820 1 + v575 r_2130 1 + v575 r_2131 1 + v576 r_64 1 + v576 r_286 1 + v576 r_754 -1 + v576 r_1397 1 + v576 r_1887 1 + v576 r_2130 1 + v576 r_2131 1 + v577 r_64 1 + v577 r_1993 1 + v577 r_2024 1 + v577 r_2041 1 + v577 r_2063 1 + v577 r_2684 1 + v577 r_2685 1 + v578 r_65 1 + v578 r_167 1 + v578 r_659 -1 + v578 r_1391 1 + v578 r_1459 1 + v578 r_2131 1 + v578 r_2239 1 + v578 r_2832 1 + v579 r_65 1 + v579 r_199 1 + v579 r_689 -1 + v579 r_1393 1 + v579 r_1567 1 + v579 r_2131 1 + v579 r_2239 1 + v580 r_65 1 + v580 r_348 1 + v580 r_564 1 + v580 r_832 1 + v580 r_1066 1 + v580 r_1195 1 + v580 r_2060 1 + v580 r_2063 1 + v580 r_2329 1 + v580 r_2428 1 + v580 r_2515 -1 + v580 r_2604 -1 + v580 r_2685 1 + v580 r_2777 1 + v580 r_2811 1 + v581 r_65 1 + v581 r_235 1 + v581 r_706 -1 + v581 r_1394 1 + v581 r_1699 1 + v581 r_2131 1 + v581 r_2239 1 + v582 r_65 1 + v582 r_269 1 + v582 r_738 -1 + v582 r_1396 1 + v582 r_1821 1 + v582 r_2131 1 + v582 r_2239 1 + v583 r_65 1 + v583 r_287 1 + v583 r_755 -1 + v583 r_1397 1 + v583 r_1888 1 + v583 r_2131 1 + v583 r_2239 1 + v584 r_65 1 + v584 r_301 1 + v584 r_1398 1 + v584 r_1947 1 + v584 r_2131 1 + v584 r_2239 1 + v584 r_3001 1 + v585 r_65 1 + v585 r_1994 1 + v585 r_2024 1 + v585 r_2042 1 + v585 r_2063 1 + v585 r_2685 1 + v585 r_2777 1 + v585 r_2819 1 + v586 r_66 1 + v586 r_150 1 + v586 r_1399 1 + v586 r_1666 -1 + v586 r_2132 1 + v587 r_66 1 + v587 r_168 1 + v587 r_785 -1 + v587 r_1400 1 + v587 r_1675 -1 + v587 r_2132 1 + v587 r_2888 1 + v587 r_3002 1 + v588 r_66 1 + v588 r_182 1 + v588 r_1401 1 + v588 r_1682 -1 + v588 r_2132 1 + v589 r_66 1 + v589 r_200 1 + v589 r_1402 1 + v589 r_1691 -1 + v589 r_2132 1 + v590 r_66 1 + v590 r_466 1 + v590 r_942 1 + v590 r_1067 1 + v590 r_1196 1 + v590 r_2043 1 + v590 r_2330 1 + v590 r_2516 -1 + v590 r_2686 1 + v591 r_66 1 + v591 r_236 1 + v591 r_833 -1 + v591 r_1403 1 + v591 r_1700 -1 + v591 r_2132 1 + v591 r_2888 1 + v591 r_3002 1 + v592 r_66 1 + v592 r_252 1 + v592 r_849 -1 + v592 r_1404 1 + v592 r_1708 -1 + v592 r_2132 1 + v593 r_66 1 + v593 r_270 1 + v593 r_867 -1 + v593 r_1405 1 + v593 r_1717 -1 + v593 r_2132 1 + v594 r_67 1 + v594 r_151 1 + v594 r_768 -1 + v594 r_1399 1 + v594 r_1667 -1 + v594 r_2132 1 + v594 r_2133 1 + v594 r_2240 1 + v595 r_67 1 + v595 r_169 1 + v595 r_786 -1 + v595 r_1400 1 + v595 r_1676 -1 + v595 r_2132 1 + v595 r_2133 1 + v595 r_2240 1 + v595 r_2888 1 + v595 r_2889 1 + v595 r_3002 1 + v595 r_3003 1 + v596 r_67 1 + v596 r_183 1 + v596 r_799 -1 + v596 r_1401 1 + v596 r_1683 -1 + v596 r_2132 1 + v596 r_2133 1 + v596 r_2240 1 + v597 r_67 1 + v597 r_201 1 + v597 r_816 -1 + v597 r_1402 1 + v597 r_1692 -1 + v597 r_2132 1 + v597 r_2133 1 + v597 r_2240 1 + v598 r_67 1 + v598 r_349 1 + v598 r_467 1 + v598 r_565 1 + v598 r_690 1 + v598 r_943 1 + v598 r_1068 1 + v598 r_1197 1 + v598 r_1313 1 + v598 r_2044 1 + v598 r_2330 1 + v598 r_2331 1 + v598 r_2429 1 + v598 r_2516 -1 + v598 r_2517 -1 + v598 r_2605 -1 + v598 r_2686 1 + v598 r_2687 1 + v598 r_2778 1 + v598 r_2812 1 + v598 r_2828 1 + v599 r_67 1 + v599 r_237 1 + v599 r_834 -1 + v599 r_1403 1 + v599 r_1701 -1 + v599 r_2132 1 + v599 r_2133 1 + v599 r_2240 1 + v599 r_2888 1 + v599 r_2889 1 + v599 r_3002 1 + v599 r_3003 1 + v600 r_67 1 + v600 r_253 1 + v600 r_850 -1 + v600 r_1404 1 + v600 r_1709 -1 + v600 r_2132 1 + v600 r_2133 1 + v600 r_2240 1 + v601 r_67 1 + v601 r_271 1 + v601 r_868 -1 + v601 r_1405 1 + v601 r_1718 -1 + v601 r_2132 1 + v601 r_2133 1 + v601 r_2240 1 + v602 r_67 1 + v602 r_288 1 + v602 r_885 -1 + v602 r_1406 1 + v602 r_1726 -1 + v602 r_2132 1 + v602 r_2133 1 + v602 r_2240 1 + v602 r_3002 1 + v602 r_3003 1 + v603 r_67 1 + v603 r_1995 -1 + v603 r_2025 1 + v603 r_2029 1 + v603 r_2686 1 + v603 r_2687 1 + v603 r_2778 1 + v603 r_2820 1 + v603 r_2828 1 + v604 r_68 1 + v604 r_152 1 + v604 r_769 -1 + v604 r_1399 1 + v604 r_1668 -1 + v604 r_2132 1 + v604 r_2133 1 + v604 r_2134 1 + v605 r_68 1 + v605 r_170 1 + v605 r_787 -1 + v605 r_1400 1 + v605 r_1677 -1 + v605 r_2132 1 + v605 r_2133 1 + v605 r_2134 1 + v605 r_2889 1 + v605 r_2890 1 + v605 r_3002 1 + v605 r_3003 1 + v605 r_3004 1 + v606 r_68 1 + v606 r_184 1 + v606 r_800 -1 + v606 r_1401 1 + v606 r_1684 -1 + v606 r_2132 1 + v606 r_2133 1 + v606 r_2134 1 + v607 r_68 1 + v607 r_202 1 + v607 r_817 -1 + v607 r_1402 1 + v607 r_1693 -1 + v607 r_2132 1 + v607 r_2133 1 + v607 r_2134 1 + v608 r_68 1 + v608 r_350 1 + v608 r_468 1 + v608 r_566 1 + v608 r_691 1 + v608 r_944 1 + v608 r_1069 1 + v608 r_1198 1 + v608 r_1314 1 + v608 r_2045 1 + v608 r_2330 1 + v608 r_2331 1 + v608 r_2332 1 + v608 r_2516 -1 + v608 r_2517 -1 + v608 r_2518 -1 + v608 r_2686 1 + v608 r_2687 1 + v608 r_2688 1 + v609 r_68 1 + v609 r_238 1 + v609 r_835 -1 + v609 r_1403 1 + v609 r_1702 -1 + v609 r_2132 1 + v609 r_2133 1 + v609 r_2134 1 + v609 r_2889 1 + v609 r_2890 1 + v609 r_3002 1 + v609 r_3003 1 + v609 r_3004 1 + v610 r_68 1 + v610 r_254 1 + v610 r_851 -1 + v610 r_1404 1 + v610 r_1710 -1 + v610 r_2132 1 + v610 r_2133 1 + v610 r_2134 1 + v611 r_68 1 + v611 r_272 1 + v611 r_869 -1 + v611 r_1405 1 + v611 r_1719 -1 + v611 r_2132 1 + v611 r_2133 1 + v611 r_2134 1 + v612 r_68 1 + v612 r_289 1 + v612 r_886 -1 + v612 r_1406 1 + v612 r_1727 -1 + v612 r_2132 1 + v612 r_2133 1 + v612 r_2134 1 + v612 r_3002 1 + v612 r_3003 1 + v612 r_3004 1 + v613 r_68 1 + v613 r_1996 -1 + v613 r_2025 1 + v613 r_2030 1 + v613 r_2686 1 + v613 r_2687 1 + v613 r_2688 1 + v614 r_69 1 + v614 r_153 1 + v614 r_770 -1 + v614 r_1399 1 + v614 r_1669 -1 + v614 r_2133 1 + v614 r_2134 1 + v614 r_2135 1 + v614 r_2240 1 + v614 r_2241 1 + v615 r_69 1 + v615 r_171 1 + v615 r_788 -1 + v615 r_1400 1 + v615 r_1678 -1 + v615 r_2133 1 + v615 r_2134 1 + v615 r_2135 1 + v615 r_2240 1 + v615 r_2241 1 + v615 r_2890 1 + v615 r_2891 1 + v615 r_3003 1 + v615 r_3004 1 + v615 r_3005 1 + v616 r_69 1 + v616 r_185 1 + v616 r_801 -1 + v616 r_1401 1 + v616 r_1685 -1 + v616 r_2133 1 + v616 r_2134 1 + v616 r_2135 1 + v616 r_2240 1 + v616 r_2241 1 + v617 r_69 1 + v617 r_203 1 + v617 r_818 -1 + v617 r_1402 1 + v617 r_1694 -1 + v617 r_2133 1 + v617 r_2134 1 + v617 r_2135 1 + v617 r_2240 1 + v617 r_2241 1 + v618 r_69 1 + v618 r_351 1 + v618 r_469 1 + v618 r_567 1 + v618 r_692 1 + v618 r_945 1 + v618 r_1070 1 + v618 r_1199 1 + v618 r_1315 1 + v618 r_2046 1 + v618 r_2331 1 + v618 r_2332 1 + v618 r_2333 1 + v618 r_2429 1 + v618 r_2430 1 + v618 r_2516 -1 + v618 r_2517 -1 + v618 r_2518 -1 + v618 r_2519 -1 + v618 r_2605 -1 + v618 r_2606 -1 + v618 r_2686 1 + v618 r_2687 1 + v618 r_2688 1 + v618 r_2689 1 + v618 r_2778 1 + v618 r_2779 1 + v618 r_2812 1 + v618 r_2828 1 + v619 r_69 1 + v619 r_239 1 + v619 r_836 -1 + v619 r_1403 1 + v619 r_1703 -1 + v619 r_2133 1 + v619 r_2134 1 + v619 r_2135 1 + v619 r_2240 1 + v619 r_2241 1 + v619 r_2890 1 + v619 r_2891 1 + v619 r_3003 1 + v619 r_3004 1 + v619 r_3005 1 + v620 r_69 1 + v620 r_255 1 + v620 r_852 -1 + v620 r_1404 1 + v620 r_1711 -1 + v620 r_2133 1 + v620 r_2134 1 + v620 r_2135 1 + v620 r_2240 1 + v620 r_2241 1 + v621 r_69 1 + v621 r_273 1 + v621 r_870 -1 + v621 r_1405 1 + v621 r_1720 -1 + v621 r_2133 1 + v621 r_2134 1 + v621 r_2135 1 + v621 r_2240 1 + v621 r_2241 1 + v622 r_69 1 + v622 r_290 1 + v622 r_887 -1 + v622 r_1406 1 + v622 r_1728 -1 + v622 r_2133 1 + v622 r_2134 1 + v622 r_2135 1 + v622 r_2240 1 + v622 r_2241 1 + v622 r_3003 1 + v622 r_3004 1 + v622 r_3005 1 + v623 r_69 1 + v623 r_1997 -1 + v623 r_2025 1 + v623 r_2031 1 + v623 r_2686 1 + v623 r_2687 1 + v623 r_2688 1 + v623 r_2689 1 + v623 r_2778 1 + v623 r_2779 1 + v623 r_2820 1 + v623 r_2828 1 + v624 r_70 1 + v624 r_154 1 + v624 r_771 -1 + v624 r_1399 1 + v624 r_1670 -1 + v624 r_2134 1 + v624 r_2135 1 + v624 r_2136 1 + v625 r_70 1 + v625 r_172 1 + v625 r_789 -1 + v625 r_1400 1 + v625 r_1679 -1 + v625 r_2134 1 + v625 r_2135 1 + v625 r_2136 1 + v625 r_2891 1 + v625 r_2892 1 + v625 r_3004 1 + v625 r_3005 1 + v625 r_3006 1 + v626 r_70 1 + v626 r_186 1 + v626 r_802 -1 + v626 r_1401 1 + v626 r_1686 -1 + v626 r_2134 1 + v626 r_2135 1 + v626 r_2136 1 + v627 r_70 1 + v627 r_204 1 + v627 r_819 -1 + v627 r_1402 1 + v627 r_1695 -1 + v627 r_2134 1 + v627 r_2135 1 + v627 r_2136 1 + v628 r_70 1 + v628 r_352 1 + v628 r_470 1 + v628 r_568 1 + v628 r_693 1 + v628 r_946 1 + v628 r_1071 1 + v628 r_1200 1 + v628 r_1316 1 + v628 r_2047 1 + v628 r_2332 1 + v628 r_2333 1 + v628 r_2334 1 + v628 r_2517 -1 + v628 r_2518 -1 + v628 r_2519 -1 + v628 r_2520 -1 + v628 r_2686 1 + v628 r_2687 1 + v628 r_2688 1 + v628 r_2689 1 + v628 r_2690 1 + v629 r_70 1 + v629 r_240 1 + v629 r_837 -1 + v629 r_1403 1 + v629 r_1704 -1 + v629 r_2134 1 + v629 r_2135 1 + v629 r_2136 1 + v629 r_2891 1 + v629 r_2892 1 + v629 r_3004 1 + v629 r_3005 1 + v629 r_3006 1 + v630 r_70 1 + v630 r_256 1 + v630 r_853 -1 + v630 r_1404 1 + v630 r_1712 -1 + v630 r_2134 1 + v630 r_2135 1 + v630 r_2136 1 + v631 r_70 1 + v631 r_274 1 + v631 r_871 -1 + v631 r_1405 1 + v631 r_1721 -1 + v631 r_2134 1 + v631 r_2135 1 + v631 r_2136 1 + v632 r_70 1 + v632 r_291 1 + v632 r_888 -1 + v632 r_1406 1 + v632 r_1729 -1 + v632 r_2134 1 + v632 r_2135 1 + v632 r_2136 1 + v632 r_3004 1 + v632 r_3005 1 + v632 r_3006 1 + v633 r_70 1 + v633 r_1998 -1 + v633 r_2025 1 + v633 r_2032 1 + v633 r_2686 1 + v633 r_2687 1 + v633 r_2688 1 + v633 r_2689 1 + v633 r_2690 1 + v634 r_71 1 + v634 r_155 1 + v634 r_772 -1 + v634 r_1399 1 + v634 r_1671 -1 + v634 r_2135 1 + v634 r_2136 1 + v634 r_2137 1 + v634 r_2240 1 + v634 r_2241 1 + v634 r_2242 1 + v635 r_71 1 + v635 r_173 1 + v635 r_790 -1 + v635 r_1400 1 + v635 r_1680 -1 + v635 r_2135 1 + v635 r_2136 1 + v635 r_2137 1 + v635 r_2240 1 + v635 r_2241 1 + v635 r_2242 1 + v635 r_2892 1 + v635 r_2893 1 + v635 r_3005 1 + v635 r_3006 1 + v635 r_3007 1 + v636 r_71 1 + v636 r_187 1 + v636 r_803 -1 + v636 r_1401 1 + v636 r_1687 -1 + v636 r_2135 1 + v636 r_2136 1 + v636 r_2137 1 + v636 r_2240 1 + v636 r_2241 1 + v636 r_2242 1 + v637 r_71 1 + v637 r_205 1 + v637 r_820 -1 + v637 r_1402 1 + v637 r_1696 -1 + v637 r_2135 1 + v637 r_2136 1 + v637 r_2137 1 + v637 r_2240 1 + v637 r_2241 1 + v637 r_2242 1 + v638 r_71 1 + v638 r_353 1 + v638 r_471 1 + v638 r_569 1 + v638 r_694 1 + v638 r_947 1 + v638 r_1072 1 + v638 r_1201 1 + v638 r_1317 1 + v638 r_2048 1 + v638 r_2333 1 + v638 r_2334 1 + v638 r_2335 1 + v638 r_2429 1 + v638 r_2430 1 + v638 r_2431 1 + v638 r_2518 -1 + v638 r_2519 -1 + v638 r_2520 -1 + v638 r_2521 -1 + v638 r_2605 -1 + v638 r_2606 -1 + v638 r_2607 -1 + v638 r_2687 1 + v638 r_2688 1 + v638 r_2689 1 + v638 r_2690 1 + v638 r_2691 1 + v638 r_2778 1 + v638 r_2779 1 + v638 r_2780 1 + v638 r_2812 1 + v638 r_2828 1 + v639 r_71 1 + v639 r_241 1 + v639 r_838 -1 + v639 r_1403 1 + v639 r_1705 -1 + v639 r_2135 1 + v639 r_2136 1 + v639 r_2137 1 + v639 r_2240 1 + v639 r_2241 1 + v639 r_2242 1 + v639 r_2892 1 + v639 r_2893 1 + v639 r_3005 1 + v639 r_3006 1 + v639 r_3007 1 + v640 r_71 1 + v640 r_257 1 + v640 r_854 -1 + v640 r_1404 1 + v640 r_1713 -1 + v640 r_2135 1 + v640 r_2136 1 + v640 r_2137 1 + v640 r_2240 1 + v640 r_2241 1 + v640 r_2242 1 + v641 r_71 1 + v641 r_275 1 + v641 r_872 -1 + v641 r_1405 1 + v641 r_1722 -1 + v641 r_2135 1 + v641 r_2136 1 + v641 r_2137 1 + v641 r_2240 1 + v641 r_2241 1 + v641 r_2242 1 + v642 r_71 1 + v642 r_292 1 + v642 r_889 -1 + v642 r_1406 1 + v642 r_1730 -1 + v642 r_2135 1 + v642 r_2136 1 + v642 r_2137 1 + v642 r_2240 1 + v642 r_2241 1 + v642 r_2242 1 + v642 r_3005 1 + v642 r_3006 1 + v642 r_3007 1 + v643 r_71 1 + v643 r_1999 -1 + v643 r_2025 1 + v643 r_2033 1 + v643 r_2687 1 + v643 r_2688 1 + v643 r_2689 1 + v643 r_2690 1 + v643 r_2691 1 + v643 r_2778 1 + v643 r_2779 1 + v643 r_2780 1 + v643 r_2820 1 + v643 r_2828 1 + v644 r_72 1 + v644 r_156 1 + v644 r_773 -1 + v644 r_1399 1 + v644 r_1672 -1 + v644 r_2136 1 + v644 r_2137 1 + v644 r_2138 1 + v645 r_72 1 + v645 r_188 1 + v645 r_804 -1 + v645 r_1401 1 + v645 r_1688 -1 + v645 r_2136 1 + v645 r_2137 1 + v645 r_2138 1 + v646 r_72 1 + v646 r_206 1 + v646 r_821 -1 + v646 r_1402 1 + v646 r_1697 -1 + v646 r_2136 1 + v646 r_2137 1 + v646 r_2138 1 + v647 r_72 1 + v647 r_354 1 + v647 r_570 1 + v647 r_695 1 + v647 r_948 1 + v647 r_1073 1 + v647 r_1202 1 + v647 r_1318 1 + v647 r_2049 1 + v647 r_2334 1 + v647 r_2335 1 + v647 r_2336 1 + v647 r_2519 -1 + v647 r_2520 -1 + v647 r_2521 -1 + v647 r_2522 -1 + v647 r_2688 1 + v647 r_2689 1 + v647 r_2690 1 + v647 r_2691 1 + v647 r_2692 1 + v648 r_72 1 + v648 r_242 1 + v648 r_839 -1 + v648 r_1403 1 + v648 r_1706 -1 + v648 r_2136 1 + v648 r_2137 1 + v648 r_2138 1 + v648 r_2893 1 + v648 r_2894 1 + v648 r_3006 1 + v648 r_3007 1 + v648 r_3008 1 + v649 r_72 1 + v649 r_258 1 + v649 r_855 -1 + v649 r_1404 1 + v649 r_1714 -1 + v649 r_2136 1 + v649 r_2137 1 + v649 r_2138 1 + v650 r_72 1 + v650 r_276 1 + v650 r_873 -1 + v650 r_1405 1 + v650 r_1723 -1 + v650 r_2136 1 + v650 r_2137 1 + v650 r_2138 1 + v651 r_72 1 + v651 r_293 1 + v651 r_890 -1 + v651 r_1406 1 + v651 r_1731 -1 + v651 r_2136 1 + v651 r_2137 1 + v651 r_2138 1 + v651 r_3006 1 + v651 r_3007 1 + v651 r_3008 1 + v652 r_73 1 + v652 r_157 1 + v652 r_774 -1 + v652 r_1399 1 + v652 r_2137 1 + v652 r_2138 1 + v652 r_2139 1 + v652 r_2241 1 + v652 r_2242 1 + v652 r_2243 1 + v653 r_73 1 + v653 r_174 1 + v653 r_791 -1 + v653 r_1400 1 + v653 r_1519 1 + v653 r_2137 1 + v653 r_2138 1 + v653 r_2139 1 + v653 r_2241 1 + v653 r_2242 1 + v653 r_2243 1 + v653 r_2894 1 + v653 r_2895 1 + v653 r_3007 1 + v653 r_3008 1 + v653 r_3009 1 + v654 r_73 1 + v654 r_189 1 + v654 r_805 -1 + v654 r_1401 1 + v654 r_2137 1 + v654 r_2138 1 + v654 r_2139 1 + v654 r_2241 1 + v654 r_2242 1 + v654 r_2243 1 + v655 r_73 1 + v655 r_207 1 + v655 r_822 -1 + v655 r_1402 1 + v655 r_2137 1 + v655 r_2138 1 + v655 r_2139 1 + v655 r_2241 1 + v655 r_2242 1 + v655 r_2243 1 + v656 r_73 1 + v656 r_355 1 + v656 r_472 1 + v656 r_571 1 + v656 r_696 1 + v656 r_949 1 + v656 r_1074 1 + v656 r_1203 1 + v656 r_2050 1 + v656 r_2335 1 + v656 r_2336 1 + v656 r_2337 1 + v656 r_2430 1 + v656 r_2431 1 + v656 r_2432 1 + v656 r_2520 -1 + v656 r_2521 -1 + v656 r_2522 -1 + v656 r_2523 -1 + v656 r_2605 -1 + v656 r_2606 -1 + v656 r_2607 -1 + v656 r_2608 -1 + v656 r_2689 1 + v656 r_2690 1 + v656 r_2691 1 + v656 r_2692 1 + v656 r_2693 1 + v656 r_2778 1 + v656 r_2779 1 + v656 r_2780 1 + v656 r_2781 1 + v656 r_2812 1 + v656 r_2828 1 + v657 r_73 1 + v657 r_243 1 + v657 r_840 -1 + v657 r_1403 1 + v657 r_1757 1 + v657 r_2137 1 + v657 r_2138 1 + v657 r_2139 1 + v657 r_2241 1 + v657 r_2242 1 + v657 r_2243 1 + v657 r_2894 1 + v657 r_2895 1 + v657 r_3007 1 + v657 r_3008 1 + v657 r_3009 1 + v658 r_73 1 + v658 r_259 1 + v658 r_856 -1 + v658 r_1404 1 + v658 r_1822 1 + v658 r_2137 1 + v658 r_2138 1 + v658 r_2139 1 + v658 r_2241 1 + v658 r_2242 1 + v658 r_2243 1 + v659 r_73 1 + v659 r_277 1 + v659 r_874 -1 + v659 r_1405 1 + v659 r_1889 1 + v659 r_2137 1 + v659 r_2138 1 + v659 r_2139 1 + v659 r_2241 1 + v659 r_2242 1 + v659 r_2243 1 + v660 r_74 1 + v660 r_158 1 + v660 r_775 -1 + v660 r_1399 1 + v660 r_1460 1 + v660 r_2138 1 + v660 r_2139 1 + v660 r_2140 1 + v661 r_74 1 + v661 r_175 1 + v661 r_792 -1 + v661 r_1400 1 + v661 r_1520 1 + v661 r_2138 1 + v661 r_2139 1 + v661 r_2140 1 + v661 r_2895 1 + v661 r_2896 1 + v661 r_3008 1 + v661 r_3009 1 + v661 r_3010 1 + v662 r_74 1 + v662 r_190 1 + v662 r_806 -1 + v662 r_1401 1 + v662 r_1568 1 + v662 r_2138 1 + v662 r_2139 1 + v662 r_2140 1 + v663 r_74 1 + v663 r_208 1 + v663 r_823 -1 + v663 r_1402 1 + v663 r_1628 1 + v663 r_2138 1 + v663 r_2139 1 + v663 r_2140 1 + v664 r_74 1 + v664 r_356 1 + v664 r_473 1 + v664 r_572 1 + v664 r_697 1 + v664 r_950 1 + v664 r_1075 1 + v664 r_1204 1 + v664 r_1319 1 + v664 r_2051 1 + v664 r_2336 1 + v664 r_2337 1 + v664 r_2338 1 + v664 r_2521 -1 + v664 r_2522 -1 + v664 r_2523 -1 + v664 r_2524 -1 + v664 r_2690 1 + v664 r_2691 1 + v664 r_2692 1 + v664 r_2693 1 + v664 r_2694 1 + v665 r_74 1 + v665 r_244 1 + v665 r_841 -1 + v665 r_1403 1 + v665 r_1758 1 + v665 r_2138 1 + v665 r_2139 1 + v665 r_2140 1 + v665 r_2895 1 + v665 r_2896 1 + v665 r_3008 1 + v665 r_3009 1 + v665 r_3010 1 + v666 r_74 1 + v666 r_260 1 + v666 r_857 -1 + v666 r_1404 1 + v666 r_1823 1 + v666 r_2138 1 + v666 r_2139 1 + v666 r_2140 1 + v667 r_74 1 + v667 r_278 1 + v667 r_875 -1 + v667 r_1405 1 + v667 r_1890 1 + v667 r_2138 1 + v667 r_2139 1 + v667 r_2140 1 + v668 r_74 1 + v668 r_294 1 + v668 r_891 -1 + v668 r_1406 1 + v668 r_1948 1 + v668 r_2138 1 + v668 r_2139 1 + v668 r_2140 1 + v668 r_3008 1 + v668 r_3009 1 + v668 r_3010 1 + v669 r_74 1 + v669 r_1995 1 + v669 r_2025 1 + v669 r_2034 1 + v669 r_2690 1 + v669 r_2691 1 + v669 r_2692 1 + v669 r_2693 1 + v669 r_2694 1 + v670 r_75 1 + v670 r_159 1 + v670 r_776 -1 + v670 r_1399 1 + v670 r_1673 -1 + v670 r_2139 1 + v670 r_2140 1 + v670 r_2141 1 + v670 r_2242 1 + v670 r_2243 1 + v670 r_2244 1 + v671 r_75 1 + v671 r_176 1 + v671 r_793 -1 + v671 r_1400 1 + v671 r_1681 -1 + v671 r_2139 1 + v671 r_2140 1 + v671 r_2141 1 + v671 r_2242 1 + v671 r_2243 1 + v671 r_2244 1 + v671 r_2896 1 + v671 r_2897 1 + v671 r_3009 1 + v671 r_3010 1 + v671 r_3011 1 + v672 r_75 1 + v672 r_191 1 + v672 r_807 -1 + v672 r_1401 1 + v672 r_1689 -1 + v672 r_2139 1 + v672 r_2140 1 + v672 r_2141 1 + v672 r_2242 1 + v672 r_2243 1 + v672 r_2244 1 + v673 r_75 1 + v673 r_209 1 + v673 r_824 -1 + v673 r_1402 1 + v673 r_1698 -1 + v673 r_2139 1 + v673 r_2140 1 + v673 r_2141 1 + v673 r_2242 1 + v673 r_2243 1 + v673 r_2244 1 + v674 r_75 1 + v674 r_357 1 + v674 r_474 1 + v674 r_573 1 + v674 r_698 1 + v674 r_951 1 + v674 r_1076 1 + v674 r_1205 1 + v674 r_2052 1 + v674 r_2337 1 + v674 r_2338 1 + v674 r_2339 1 + v674 r_2431 1 + v674 r_2432 1 + v674 r_2433 1 + v674 r_2522 -1 + v674 r_2523 -1 + v674 r_2524 -1 + v674 r_2525 -1 + v674 r_2606 -1 + v674 r_2607 -1 + v674 r_2608 -1 + v674 r_2609 -1 + v674 r_2691 1 + v674 r_2692 1 + v674 r_2693 1 + v674 r_2694 1 + v674 r_2695 1 + v674 r_2779 1 + v674 r_2780 1 + v674 r_2781 1 + v674 r_2782 1 + v674 r_2812 1 + v674 r_2828 1 + v675 r_75 1 + v675 r_245 1 + v675 r_842 -1 + v675 r_1403 1 + v675 r_1707 -1 + v675 r_2139 1 + v675 r_2140 1 + v675 r_2141 1 + v675 r_2242 1 + v675 r_2243 1 + v675 r_2244 1 + v675 r_2896 1 + v675 r_2897 1 + v675 r_3009 1 + v675 r_3010 1 + v675 r_3011 1 + v676 r_75 1 + v676 r_261 1 + v676 r_858 -1 + v676 r_1404 1 + v676 r_1715 -1 + v676 r_2139 1 + v676 r_2140 1 + v676 r_2141 1 + v676 r_2242 1 + v676 r_2243 1 + v676 r_2244 1 + v677 r_75 1 + v677 r_279 1 + v677 r_876 -1 + v677 r_1405 1 + v677 r_1724 -1 + v677 r_2139 1 + v677 r_2140 1 + v677 r_2141 1 + v677 r_2242 1 + v677 r_2243 1 + v677 r_2244 1 + v678 r_75 1 + v678 r_295 1 + v678 r_1406 1 + v678 r_1732 -1 + v678 r_2139 1 + v678 r_2140 1 + v678 r_2141 1 + v678 r_2242 1 + v678 r_2243 1 + v678 r_2244 1 + v678 r_3009 1 + v678 r_3010 1 + v678 r_3011 1 + v679 r_75 1 + v679 r_2000 -1 + v679 r_2025 1 + v679 r_2035 1 + v679 r_2691 1 + v679 r_2692 1 + v679 r_2693 1 + v679 r_2694 1 + v679 r_2695 1 + v679 r_2779 1 + v679 r_2780 1 + v679 r_2781 1 + v679 r_2782 1 + v679 r_2820 1 + v679 r_2828 1 + v680 r_76 1 + v680 r_160 1 + v680 r_777 -1 + v680 r_1399 1 + v680 r_1674 -1 + v680 r_2140 1 + v680 r_2141 1 + v680 r_2142 1 + v681 r_76 1 + v681 r_192 1 + v681 r_808 -1 + v681 r_1401 1 + v681 r_1690 -1 + v681 r_2140 1 + v681 r_2141 1 + v681 r_2142 1 + v682 r_76 1 + v682 r_210 1 + v682 r_825 -1 + v682 r_1402 1 + v682 r_1699 -1 + v682 r_2140 1 + v682 r_2141 1 + v682 r_2142 1 + v683 r_76 1 + v683 r_358 1 + v683 r_574 1 + v683 r_699 1 + v683 r_1077 1 + v683 r_1206 1 + v683 r_1320 1 + v683 r_2053 1 + v683 r_2338 1 + v683 r_2339 1 + v683 r_2340 1 + v683 r_2523 -1 + v683 r_2524 -1 + v683 r_2525 -1 + v683 r_2526 -1 + v683 r_2692 1 + v683 r_2693 1 + v683 r_2694 1 + v683 r_2695 1 + v683 r_2696 1 + v684 r_76 1 + v684 r_262 1 + v684 r_859 -1 + v684 r_1404 1 + v684 r_1716 -1 + v684 r_2140 1 + v684 r_2141 1 + v684 r_2142 1 + v685 r_76 1 + v685 r_280 1 + v685 r_877 -1 + v685 r_1405 1 + v685 r_1725 -1 + v685 r_2140 1 + v685 r_2141 1 + v685 r_2142 1 + v686 r_76 1 + v686 r_2001 -1 + v686 r_2025 1 + v686 r_2036 1 + v686 r_2692 1 + v686 r_2693 1 + v686 r_2694 1 + v686 r_2695 1 + v686 r_2696 1 + v687 r_77 1 + v687 r_161 1 + v687 r_778 -1 + v687 r_1399 1 + v687 r_1461 1 + v687 r_2141 1 + v687 r_2142 1 + v687 r_2143 1 + v687 r_2243 1 + v687 r_2244 1 + v687 r_2245 1 + v688 r_77 1 + v688 r_177 1 + v688 r_794 -1 + v688 r_1400 1 + v688 r_1521 1 + v688 r_2141 1 + v688 r_2142 1 + v688 r_2143 1 + v688 r_2243 1 + v688 r_2244 1 + v688 r_2245 1 + v688 r_2898 1 + v688 r_2899 1 + v688 r_3011 1 + v688 r_3012 1 + v688 r_3013 1 + v689 r_77 1 + v689 r_193 1 + v689 r_809 -1 + v689 r_1401 1 + v689 r_1569 1 + v689 r_2141 1 + v689 r_2142 1 + v689 r_2143 1 + v689 r_2243 1 + v689 r_2244 1 + v689 r_2245 1 + v690 r_77 1 + v690 r_211 1 + v690 r_826 -1 + v690 r_1402 1 + v690 r_1629 1 + v690 r_2141 1 + v690 r_2142 1 + v690 r_2143 1 + v690 r_2243 1 + v690 r_2244 1 + v690 r_2245 1 + v691 r_77 1 + v691 r_359 1 + v691 r_475 1 + v691 r_575 1 + v691 r_700 1 + v691 r_952 1 + v691 r_1078 1 + v691 r_1207 1 + v691 r_1321 1 + v691 r_2054 1 + v691 r_2339 1 + v691 r_2340 1 + v691 r_2341 1 + v691 r_2432 1 + v691 r_2433 1 + v691 r_2434 1 + v691 r_2524 -1 + v691 r_2525 -1 + v691 r_2526 -1 + v691 r_2527 -1 + v691 r_2607 -1 + v691 r_2608 -1 + v691 r_2609 -1 + v691 r_2610 -1 + v691 r_2693 1 + v691 r_2694 1 + v691 r_2695 1 + v691 r_2696 1 + v691 r_2697 1 + v691 r_2780 1 + v691 r_2781 1 + v691 r_2782 1 + v691 r_2783 1 + v691 r_2812 1 + v692 r_77 1 + v692 r_246 1 + v692 r_843 -1 + v692 r_1403 1 + v692 r_1759 1 + v692 r_2141 1 + v692 r_2142 1 + v692 r_2143 1 + v692 r_2243 1 + v692 r_2244 1 + v692 r_2245 1 + v692 r_2898 1 + v692 r_2899 1 + v692 r_3011 1 + v692 r_3012 1 + v692 r_3013 1 + v693 r_77 1 + v693 r_263 1 + v693 r_860 -1 + v693 r_1404 1 + v693 r_1824 1 + v693 r_2141 1 + v693 r_2142 1 + v693 r_2143 1 + v693 r_2243 1 + v693 r_2244 1 + v693 r_2245 1 + v694 r_77 1 + v694 r_281 1 + v694 r_878 -1 + v694 r_1405 1 + v694 r_1891 1 + v694 r_2141 1 + v694 r_2142 1 + v694 r_2143 1 + v694 r_2243 1 + v694 r_2244 1 + v694 r_2245 1 + v695 r_77 1 + v695 r_296 1 + v695 r_892 -1 + v695 r_1406 1 + v695 r_1949 1 + v695 r_2141 1 + v695 r_2142 1 + v695 r_2143 1 + v695 r_2243 1 + v695 r_2244 1 + v695 r_2245 1 + v695 r_3011 1 + v695 r_3012 1 + v695 r_3013 1 + v696 r_77 1 + v696 r_1996 1 + v696 r_2025 1 + v696 r_2037 1 + v696 r_2693 1 + v696 r_2694 1 + v696 r_2695 1 + v696 r_2696 1 + v696 r_2697 1 + v696 r_2780 1 + v696 r_2781 1 + v696 r_2782 1 + v696 r_2783 1 + v696 r_2820 1 + v697 r_78 1 + v697 r_162 1 + v697 r_779 -1 + v697 r_1399 1 + v697 r_1462 1 + v697 r_2142 1 + v697 r_2143 1 + v697 r_2144 1 + v698 r_78 1 + v698 r_178 1 + v698 r_795 -1 + v698 r_1400 1 + v698 r_1522 1 + v698 r_2142 1 + v698 r_2143 1 + v698 r_2144 1 + v698 r_2899 1 + v698 r_2900 1 + v698 r_3012 1 + v698 r_3013 1 + v698 r_3014 1 + v699 r_78 1 + v699 r_194 1 + v699 r_810 -1 + v699 r_1401 1 + v699 r_1570 1 + v699 r_2142 1 + v699 r_2143 1 + v699 r_2144 1 + v700 r_78 1 + v700 r_212 1 + v700 r_827 -1 + v700 r_1402 1 + v700 r_1630 1 + v700 r_2142 1 + v700 r_2143 1 + v700 r_2144 1 + v701 r_78 1 + v701 r_360 1 + v701 r_476 1 + v701 r_576 1 + v701 r_701 1 + v701 r_953 1 + v701 r_1079 1 + v701 r_1208 1 + v701 r_1322 1 + v701 r_2055 1 + v701 r_2340 1 + v701 r_2341 1 + v701 r_2342 1 + v701 r_2525 -1 + v701 r_2526 -1 + v701 r_2527 -1 + v701 r_2528 -1 + v701 r_2694 1 + v701 r_2695 1 + v701 r_2696 1 + v701 r_2697 1 + v701 r_2698 1 + v702 r_78 1 + v702 r_247 1 + v702 r_844 -1 + v702 r_1403 1 + v702 r_1760 1 + v702 r_2142 1 + v702 r_2143 1 + v702 r_2144 1 + v702 r_2899 1 + v702 r_2900 1 + v702 r_3012 1 + v702 r_3013 1 + v702 r_3014 1 + v703 r_78 1 + v703 r_264 1 + v703 r_861 -1 + v703 r_1404 1 + v703 r_1825 1 + v703 r_2142 1 + v703 r_2143 1 + v703 r_2144 1 + v704 r_78 1 + v704 r_282 1 + v704 r_879 -1 + v704 r_1405 1 + v704 r_1892 1 + v704 r_2142 1 + v704 r_2143 1 + v704 r_2144 1 + v705 r_78 1 + v705 r_297 1 + v705 r_893 -1 + v705 r_1406 1 + v705 r_1950 1 + v705 r_2142 1 + v705 r_2143 1 + v705 r_2144 1 + v705 r_3012 1 + v705 r_3013 1 + v705 r_3014 1 + v706 r_78 1 + v706 r_1997 1 + v706 r_2025 1 + v706 r_2038 1 + v706 r_2694 1 + v706 r_2695 1 + v706 r_2696 1 + v706 r_2697 1 + v706 r_2698 1 + v707 r_79 1 + v707 r_163 1 + v707 r_780 -1 + v707 r_1399 1 + v707 r_1463 1 + v707 r_2143 1 + v707 r_2144 1 + v707 r_2145 1 + v707 r_2244 1 + v707 r_2245 1 + v707 r_2246 1 + v708 r_79 1 + v708 r_179 1 + v708 r_796 -1 + v708 r_1400 1 + v708 r_1523 1 + v708 r_2143 1 + v708 r_2144 1 + v708 r_2145 1 + v708 r_2244 1 + v708 r_2245 1 + v708 r_2246 1 + v708 r_2900 1 + v708 r_2901 1 + v708 r_3013 1 + v708 r_3014 1 + v708 r_3015 1 + v709 r_79 1 + v709 r_195 1 + v709 r_811 -1 + v709 r_1401 1 + v709 r_1571 1 + v709 r_2143 1 + v709 r_2144 1 + v709 r_2145 1 + v709 r_2244 1 + v709 r_2245 1 + v709 r_2246 1 + v710 r_79 1 + v710 r_213 1 + v710 r_828 -1 + v710 r_1402 1 + v710 r_1631 1 + v710 r_2143 1 + v710 r_2144 1 + v710 r_2145 1 + v710 r_2244 1 + v710 r_2245 1 + v710 r_2246 1 + v711 r_79 1 + v711 r_361 1 + v711 r_477 1 + v711 r_577 1 + v711 r_702 1 + v711 r_954 1 + v711 r_1080 1 + v711 r_1209 1 + v711 r_1323 1 + v711 r_2056 1 + v711 r_2341 1 + v711 r_2342 1 + v711 r_2343 1 + v711 r_2433 1 + v711 r_2434 1 + v711 r_2435 1 + v711 r_2526 -1 + v711 r_2527 -1 + v711 r_2528 -1 + v711 r_2529 -1 + v711 r_2608 -1 + v711 r_2609 -1 + v711 r_2610 -1 + v711 r_2695 1 + v711 r_2696 1 + v711 r_2697 1 + v711 r_2698 1 + v711 r_2699 1 + v711 r_2781 1 + v711 r_2782 1 + v711 r_2783 1 + v711 r_2812 1 + v712 r_79 1 + v712 r_248 1 + v712 r_845 -1 + v712 r_1403 1 + v712 r_1761 1 + v712 r_2143 1 + v712 r_2144 1 + v712 r_2145 1 + v712 r_2244 1 + v712 r_2245 1 + v712 r_2246 1 + v712 r_2900 1 + v712 r_2901 1 + v712 r_3013 1 + v712 r_3014 1 + v712 r_3015 1 + v713 r_79 1 + v713 r_265 1 + v713 r_862 -1 + v713 r_1404 1 + v713 r_1826 1 + v713 r_2143 1 + v713 r_2144 1 + v713 r_2145 1 + v713 r_2244 1 + v713 r_2245 1 + v713 r_2246 1 + v714 r_79 1 + v714 r_283 1 + v714 r_880 -1 + v714 r_1405 1 + v714 r_1893 1 + v714 r_2143 1 + v714 r_2144 1 + v714 r_2145 1 + v714 r_2244 1 + v714 r_2245 1 + v714 r_2246 1 + v715 r_79 1 + v715 r_298 1 + v715 r_894 -1 + v715 r_1406 1 + v715 r_1951 1 + v715 r_2143 1 + v715 r_2144 1 + v715 r_2145 1 + v715 r_2244 1 + v715 r_2245 1 + v715 r_2246 1 + v715 r_3013 1 + v715 r_3014 1 + v715 r_3015 1 + v716 r_79 1 + v716 r_1998 1 + v716 r_2025 1 + v716 r_2039 1 + v716 r_2695 1 + v716 r_2696 1 + v716 r_2697 1 + v716 r_2698 1 + v716 r_2699 1 + v716 r_2781 1 + v716 r_2782 1 + v716 r_2783 1 + v716 r_2820 1 + v717 r_80 1 + v717 r_164 1 + v717 r_781 -1 + v717 r_1399 1 + v717 r_1464 1 + v717 r_2144 1 + v717 r_2145 1 + v717 r_2146 1 + v718 r_80 1 + v718 r_180 1 + v718 r_797 -1 + v718 r_1400 1 + v718 r_1524 1 + v718 r_2144 1 + v718 r_2145 1 + v718 r_2146 1 + v718 r_2901 1 + v718 r_2902 1 + v718 r_3014 1 + v718 r_3015 1 + v718 r_3016 1 + v719 r_80 1 + v719 r_196 1 + v719 r_812 -1 + v719 r_1401 1 + v719 r_1572 1 + v719 r_2144 1 + v719 r_2145 1 + v719 r_2146 1 + v720 r_80 1 + v720 r_214 1 + v720 r_829 -1 + v720 r_1402 1 + v720 r_1632 1 + v720 r_2144 1 + v720 r_2145 1 + v720 r_2146 1 + v721 r_80 1 + v721 r_362 1 + v721 r_478 1 + v721 r_578 1 + v721 r_703 1 + v721 r_955 1 + v721 r_1081 1 + v721 r_1210 1 + v721 r_1324 1 + v721 r_2057 1 + v721 r_2342 1 + v721 r_2343 1 + v721 r_2344 1 + v721 r_2527 -1 + v721 r_2528 -1 + v721 r_2529 -1 + v721 r_2530 -1 + v721 r_2696 1 + v721 r_2697 1 + v721 r_2698 1 + v721 r_2699 1 + v722 r_80 1 + v722 r_249 1 + v722 r_846 -1 + v722 r_1403 1 + v722 r_1762 1 + v722 r_2144 1 + v722 r_2145 1 + v722 r_2146 1 + v722 r_2901 1 + v722 r_2902 1 + v722 r_3014 1 + v722 r_3015 1 + v722 r_3016 1 + v723 r_80 1 + v723 r_266 1 + v723 r_863 -1 + v723 r_1404 1 + v723 r_1827 1 + v723 r_2144 1 + v723 r_2145 1 + v723 r_2146 1 + v724 r_80 1 + v724 r_284 1 + v724 r_881 -1 + v724 r_1405 1 + v724 r_1894 1 + v724 r_2144 1 + v724 r_2145 1 + v724 r_2146 1 + v725 r_80 1 + v725 r_299 1 + v725 r_895 -1 + v725 r_1406 1 + v725 r_1952 1 + v725 r_2144 1 + v725 r_2145 1 + v725 r_2146 1 + v725 r_3014 1 + v725 r_3015 1 + v725 r_3016 1 + v726 r_80 1 + v726 r_1999 1 + v726 r_2025 1 + v726 r_2040 1 + v726 r_2696 1 + v726 r_2697 1 + v726 r_2698 1 + v726 r_2699 1 + v727 r_81 1 + v727 r_165 1 + v727 r_782 -1 + v727 r_1399 1 + v727 r_1465 1 + v727 r_2145 1 + v727 r_2146 1 + v727 r_2147 1 + v727 r_2245 1 + v727 r_2246 1 + v728 r_81 1 + v728 r_197 1 + v728 r_813 -1 + v728 r_1401 1 + v728 r_1573 1 + v728 r_2145 1 + v728 r_2146 1 + v728 r_2147 1 + v728 r_2245 1 + v728 r_2246 1 + v729 r_81 1 + v729 r_215 1 + v729 r_830 -1 + v729 r_1402 1 + v729 r_1633 1 + v729 r_2145 1 + v729 r_2146 1 + v729 r_2147 1 + v729 r_2245 1 + v729 r_2246 1 + v730 r_81 1 + v730 r_363 1 + v730 r_579 1 + v730 r_704 1 + v730 r_956 1 + v730 r_1082 1 + v730 r_1211 1 + v730 r_1325 1 + v730 r_2058 1 + v730 r_2343 1 + v730 r_2344 1 + v730 r_2345 1 + v730 r_2434 1 + v730 r_2435 1 + v730 r_2528 -1 + v730 r_2529 -1 + v730 r_2530 -1 + v730 r_2609 -1 + v730 r_2610 -1 + v730 r_2697 1 + v730 r_2698 1 + v730 r_2699 1 + v730 r_2782 1 + v730 r_2783 1 + v730 r_2812 1 + v731 r_81 1 + v731 r_250 1 + v731 r_847 -1 + v731 r_1403 1 + v731 r_1763 1 + v731 r_2145 1 + v731 r_2146 1 + v731 r_2147 1 + v731 r_2245 1 + v731 r_2246 1 + v731 r_2902 1 + v731 r_2903 1 + v731 r_3015 1 + v731 r_3016 1 + v731 r_3017 1 + v732 r_81 1 + v732 r_267 1 + v732 r_864 -1 + v732 r_1404 1 + v732 r_1828 1 + v732 r_2145 1 + v732 r_2146 1 + v732 r_2147 1 + v732 r_2245 1 + v732 r_2246 1 + v733 r_81 1 + v733 r_285 1 + v733 r_882 -1 + v733 r_1405 1 + v733 r_1895 1 + v733 r_2145 1 + v733 r_2146 1 + v733 r_2147 1 + v733 r_2245 1 + v733 r_2246 1 + v734 r_81 1 + v734 r_300 1 + v734 r_896 -1 + v734 r_1406 1 + v734 r_1953 1 + v734 r_2145 1 + v734 r_2146 1 + v734 r_2147 1 + v734 r_2245 1 + v734 r_2246 1 + v734 r_3015 1 + v734 r_3016 1 + v734 r_3017 1 + v735 r_82 1 + v735 r_166 1 + v735 r_783 -1 + v735 r_1399 1 + v735 r_1466 1 + v735 r_2146 1 + v735 r_2147 1 + v736 r_82 1 + v736 r_181 1 + v736 r_798 -1 + v736 r_1400 1 + v736 r_1525 1 + v736 r_2146 1 + v736 r_2147 1 + v736 r_2903 1 + v736 r_2904 1 + v736 r_3016 1 + v736 r_3017 1 + v737 r_82 1 + v737 r_198 1 + v737 r_814 -1 + v737 r_1401 1 + v737 r_1574 1 + v737 r_2146 1 + v737 r_2147 1 + v738 r_82 1 + v738 r_216 1 + v738 r_831 -1 + v738 r_1402 1 + v738 r_1634 1 + v738 r_2146 1 + v738 r_2147 1 + v739 r_82 1 + v739 r_364 1 + v739 r_479 1 + v739 r_580 1 + v739 r_705 1 + v739 r_957 1 + v739 r_1083 1 + v739 r_1212 1 + v739 r_1326 1 + v739 r_2059 1 + v739 r_2064 1 + v739 r_2344 1 + v739 r_2345 1 + v739 r_2529 -1 + v739 r_2530 -1 + v739 r_2698 1 + v739 r_2699 1 + v740 r_82 1 + v740 r_251 1 + v740 r_848 -1 + v740 r_1403 1 + v740 r_1764 1 + v740 r_2146 1 + v740 r_2147 1 + v740 r_2903 1 + v740 r_2904 1 + v740 r_3016 1 + v740 r_3017 1 + v741 r_82 1 + v741 r_268 1 + v741 r_865 -1 + v741 r_1404 1 + v741 r_1829 1 + v741 r_2146 1 + v741 r_2147 1 + v742 r_82 1 + v742 r_286 1 + v742 r_883 -1 + v742 r_1405 1 + v742 r_1896 1 + v742 r_2146 1 + v742 r_2147 1 + v743 r_82 1 + v743 r_2000 1 + v743 r_2025 1 + v743 r_2041 1 + v743 r_2064 1 + v743 r_2698 1 + v743 r_2699 1 + v744 r_83 1 + v744 r_167 1 + v744 r_784 -1 + v744 r_1399 1 + v744 r_1467 1 + v744 r_2147 1 + v744 r_2246 1 + v745 r_83 1 + v745 r_199 1 + v745 r_815 -1 + v745 r_1401 1 + v745 r_1575 1 + v745 r_2147 1 + v745 r_2246 1 + v746 r_83 1 + v746 r_217 1 + v746 r_832 -1 + v746 r_1402 1 + v746 r_1635 1 + v746 r_2147 1 + v746 r_2246 1 + v747 r_83 1 + v747 r_365 1 + v747 r_581 1 + v747 r_706 1 + v747 r_1084 1 + v747 r_1213 1 + v747 r_2060 1 + v747 r_2064 1 + v747 r_2345 1 + v747 r_2435 1 + v747 r_2530 -1 + v747 r_2610 -1 + v747 r_2699 1 + v747 r_2783 1 + v747 r_2812 1 + v747 r_3052 1 + v748 r_83 1 + v748 r_269 1 + v748 r_866 -1 + v748 r_1404 1 + v748 r_1830 1 + v748 r_2147 1 + v748 r_2246 1 + v749 r_83 1 + v749 r_287 1 + v749 r_884 -1 + v749 r_1405 1 + v749 r_1897 1 + v749 r_2147 1 + v749 r_2246 1 + v749 r_2832 1 + v750 r_83 1 + v750 r_301 1 + v750 r_1406 1 + v750 r_1954 1 + v750 r_2147 1 + v750 r_2246 1 + v750 r_3017 1 + v751 r_83 1 + v751 r_2001 1 + v751 r_2025 1 + v751 r_2042 1 + v751 r_2064 1 + v751 r_2699 1 + v751 r_2783 1 + v751 r_2820 1 + v751 r_3052 1 + v752 r_84 1 + v752 r_150 1 + v752 r_1407 1 + v752 r_1733 -1 + v752 r_2148 1 + v752 r_2954 1 + v753 r_84 1 + v753 r_182 1 + v753 r_1408 1 + v753 r_1741 -1 + v753 r_2148 1 + v753 r_2970 1 + v754 r_84 1 + v754 r_200 1 + v754 r_1409 1 + v754 r_1749 -1 + v754 r_2148 1 + v754 r_2986 1 + v755 r_84 1 + v755 r_218 1 + v755 r_942 -1 + v755 r_1410 1 + v755 r_1757 -1 + v755 r_2148 1 + v755 r_3002 1 + v756 r_84 1 + v756 r_833 1 + v756 r_1085 1 + v756 r_1214 1 + v756 r_2043 1 + v756 r_2346 1 + v756 r_2531 -1 + v756 r_2700 1 + v757 r_84 1 + v757 r_252 1 + v757 r_958 -1 + v757 r_1411 1 + v757 r_1765 -1 + v757 r_2148 1 + v757 r_3018 1 + v758 r_84 1 + v758 r_270 1 + v758 r_974 -1 + v758 r_1412 1 + v758 r_1773 -1 + v758 r_2148 1 + v758 r_3034 1 + v759 r_85 1 + v759 r_151 1 + v759 r_897 -1 + v759 r_1407 1 + v759 r_1734 -1 + v759 r_2148 1 + v759 r_2149 1 + v759 r_2247 1 + v759 r_2954 1 + v759 r_2955 1 + v759 r_3050 1 + v760 r_85 1 + v760 r_183 1 + v760 r_912 -1 + v760 r_1408 1 + v760 r_1742 -1 + v760 r_2148 1 + v760 r_2149 1 + v760 r_2247 1 + v760 r_2970 1 + v760 r_2971 1 + v761 r_85 1 + v761 r_201 1 + v761 r_927 -1 + v761 r_1409 1 + v761 r_1750 -1 + v761 r_2148 1 + v761 r_2149 1 + v761 r_2247 1 + v761 r_2986 1 + v761 r_2987 1 + v762 r_85 1 + v762 r_219 1 + v762 r_943 -1 + v762 r_1410 1 + v762 r_1758 -1 + v762 r_2148 1 + v762 r_2149 1 + v762 r_2247 1 + v762 r_3002 1 + v762 r_3003 1 + v763 r_85 1 + v763 r_366 1 + v763 r_582 1 + v763 r_707 1 + v763 r_834 1 + v763 r_1086 1 + v763 r_1215 1 + v763 r_1327 1 + v763 r_2044 1 + v763 r_2346 1 + v763 r_2347 1 + v763 r_2436 1 + v763 r_2531 -1 + v763 r_2532 -1 + v763 r_2611 -1 + v763 r_2700 1 + v763 r_2701 1 + v763 r_2784 1 + v763 r_2813 1 + v763 r_2829 1 + v764 r_85 1 + v764 r_253 1 + v764 r_959 -1 + v764 r_1411 1 + v764 r_1766 -1 + v764 r_2148 1 + v764 r_2149 1 + v764 r_2247 1 + v764 r_3018 1 + v764 r_3019 1 + v765 r_85 1 + v765 r_271 1 + v765 r_975 -1 + v765 r_1412 1 + v765 r_1774 -1 + v765 r_2148 1 + v765 r_2149 1 + v765 r_2247 1 + v765 r_3034 1 + v765 r_3035 1 + v766 r_85 1 + v766 r_288 1 + v766 r_990 -1 + v766 r_1413 1 + v766 r_1781 -1 + v766 r_2148 1 + v766 r_2149 1 + v766 r_2247 1 + v767 r_85 1 + v767 r_2002 -1 + v767 r_2026 1 + v767 r_2029 1 + v767 r_2700 1 + v767 r_2701 1 + v767 r_2784 1 + v767 r_2821 1 + v767 r_2829 1 + v768 r_86 1 + v768 r_152 1 + v768 r_898 -1 + v768 r_1407 1 + v768 r_1735 -1 + v768 r_2148 1 + v768 r_2149 1 + v768 r_2150 1 + v768 r_2954 1 + v768 r_2955 1 + v768 r_2956 1 + v769 r_86 1 + v769 r_184 1 + v769 r_913 -1 + v769 r_1408 1 + v769 r_1743 -1 + v769 r_2148 1 + v769 r_2149 1 + v769 r_2150 1 + v769 r_2970 1 + v769 r_2971 1 + v769 r_2972 1 + v770 r_86 1 + v770 r_202 1 + v770 r_928 -1 + v770 r_1409 1 + v770 r_1751 -1 + v770 r_2148 1 + v770 r_2149 1 + v770 r_2150 1 + v770 r_2986 1 + v770 r_2987 1 + v770 r_2988 1 + v771 r_86 1 + v771 r_220 1 + v771 r_944 -1 + v771 r_1410 1 + v771 r_1759 -1 + v771 r_2148 1 + v771 r_2149 1 + v771 r_2150 1 + v771 r_3002 1 + v771 r_3003 1 + v771 r_3004 1 + v772 r_86 1 + v772 r_367 1 + v772 r_583 1 + v772 r_708 1 + v772 r_835 1 + v772 r_1087 1 + v772 r_1216 1 + v772 r_1328 1 + v772 r_2045 1 + v772 r_2346 1 + v772 r_2347 1 + v772 r_2348 1 + v772 r_2531 -1 + v772 r_2532 -1 + v772 r_2533 -1 + v772 r_2700 1 + v772 r_2701 1 + v772 r_2702 1 + v773 r_86 1 + v773 r_254 1 + v773 r_960 -1 + v773 r_1411 1 + v773 r_1767 -1 + v773 r_2148 1 + v773 r_2149 1 + v773 r_2150 1 + v773 r_3018 1 + v773 r_3019 1 + v773 r_3020 1 + v774 r_86 1 + v774 r_272 1 + v774 r_976 -1 + v774 r_1412 1 + v774 r_1775 -1 + v774 r_2148 1 + v774 r_2149 1 + v774 r_2150 1 + v774 r_3034 1 + v774 r_3035 1 + v774 r_3036 1 + v775 r_86 1 + v775 r_289 1 + v775 r_991 -1 + v775 r_1413 1 + v775 r_1782 -1 + v775 r_2148 1 + v775 r_2149 1 + v775 r_2150 1 + v776 r_86 1 + v776 r_2003 -1 + v776 r_2026 1 + v776 r_2030 1 + v776 r_2700 1 + v776 r_2701 1 + v776 r_2702 1 + v777 r_87 1 + v777 r_153 1 + v777 r_899 -1 + v777 r_1407 1 + v777 r_1736 -1 + v777 r_2149 1 + v777 r_2150 1 + v777 r_2151 1 + v777 r_2247 1 + v777 r_2248 1 + v777 r_2955 1 + v777 r_2956 1 + v777 r_2957 1 + v778 r_87 1 + v778 r_185 1 + v778 r_914 -1 + v778 r_1408 1 + v778 r_1744 -1 + v778 r_2149 1 + v778 r_2150 1 + v778 r_2151 1 + v778 r_2247 1 + v778 r_2248 1 + v778 r_2971 1 + v778 r_2972 1 + v778 r_2973 1 + v779 r_87 1 + v779 r_203 1 + v779 r_929 -1 + v779 r_1409 1 + v779 r_1752 -1 + v779 r_2149 1 + v779 r_2150 1 + v779 r_2151 1 + v779 r_2247 1 + v779 r_2248 1 + v779 r_2987 1 + v779 r_2988 1 + v779 r_2989 1 + v780 r_87 1 + v780 r_221 1 + v780 r_945 -1 + v780 r_1410 1 + v780 r_1760 -1 + v780 r_2149 1 + v780 r_2150 1 + v780 r_2151 1 + v780 r_2247 1 + v780 r_2248 1 + v780 r_3003 1 + v780 r_3004 1 + v780 r_3005 1 + v781 r_87 1 + v781 r_368 1 + v781 r_584 1 + v781 r_709 1 + v781 r_836 1 + v781 r_1088 1 + v781 r_1217 1 + v781 r_1329 1 + v781 r_2046 1 + v781 r_2347 1 + v781 r_2348 1 + v781 r_2349 1 + v781 r_2436 1 + v781 r_2437 1 + v781 r_2531 -1 + v781 r_2532 -1 + v781 r_2533 -1 + v781 r_2534 -1 + v781 r_2611 -1 + v781 r_2612 -1 + v781 r_2700 1 + v781 r_2701 1 + v781 r_2702 1 + v781 r_2703 1 + v781 r_2784 1 + v781 r_2785 1 + v781 r_2813 1 + v781 r_2829 1 + v782 r_87 1 + v782 r_255 1 + v782 r_961 -1 + v782 r_1411 1 + v782 r_1768 -1 + v782 r_2149 1 + v782 r_2150 1 + v782 r_2151 1 + v782 r_2247 1 + v782 r_2248 1 + v782 r_3019 1 + v782 r_3020 1 + v782 r_3021 1 + v783 r_87 1 + v783 r_273 1 + v783 r_977 -1 + v783 r_1412 1 + v783 r_1776 -1 + v783 r_2149 1 + v783 r_2150 1 + v783 r_2151 1 + v783 r_2247 1 + v783 r_2248 1 + v783 r_3035 1 + v783 r_3036 1 + v783 r_3037 1 + v784 r_87 1 + v784 r_290 1 + v784 r_992 -1 + v784 r_1413 1 + v784 r_1783 -1 + v784 r_2149 1 + v784 r_2150 1 + v784 r_2151 1 + v784 r_2247 1 + v784 r_2248 1 + v785 r_87 1 + v785 r_2004 -1 + v785 r_2026 1 + v785 r_2031 1 + v785 r_2700 1 + v785 r_2701 1 + v785 r_2702 1 + v785 r_2703 1 + v785 r_2784 1 + v785 r_2785 1 + v785 r_2821 1 + v785 r_2829 1 + v786 r_88 1 + v786 r_154 1 + v786 r_900 -1 + v786 r_1407 1 + v786 r_1737 -1 + v786 r_2150 1 + v786 r_2151 1 + v786 r_2152 1 + v786 r_2956 1 + v786 r_2957 1 + v786 r_2958 1 + v787 r_88 1 + v787 r_186 1 + v787 r_915 -1 + v787 r_1408 1 + v787 r_1745 -1 + v787 r_2150 1 + v787 r_2151 1 + v787 r_2152 1 + v787 r_2972 1 + v787 r_2973 1 + v787 r_2974 1 + v788 r_88 1 + v788 r_204 1 + v788 r_930 -1 + v788 r_1409 1 + v788 r_1753 -1 + v788 r_2150 1 + v788 r_2151 1 + v788 r_2152 1 + v788 r_2988 1 + v788 r_2989 1 + v788 r_2990 1 + v789 r_88 1 + v789 r_222 1 + v789 r_946 -1 + v789 r_1410 1 + v789 r_1761 -1 + v789 r_2150 1 + v789 r_2151 1 + v789 r_2152 1 + v789 r_3004 1 + v789 r_3005 1 + v789 r_3006 1 + v790 r_88 1 + v790 r_369 1 + v790 r_585 1 + v790 r_710 1 + v790 r_837 1 + v790 r_1089 1 + v790 r_1218 1 + v790 r_1330 1 + v790 r_2047 1 + v790 r_2348 1 + v790 r_2349 1 + v790 r_2350 1 + v790 r_2532 -1 + v790 r_2533 -1 + v790 r_2534 -1 + v790 r_2535 -1 + v790 r_2700 1 + v790 r_2701 1 + v790 r_2702 1 + v790 r_2703 1 + v790 r_2704 1 + v791 r_88 1 + v791 r_256 1 + v791 r_962 -1 + v791 r_1411 1 + v791 r_1769 -1 + v791 r_2150 1 + v791 r_2151 1 + v791 r_2152 1 + v791 r_3020 1 + v791 r_3021 1 + v791 r_3022 1 + v792 r_88 1 + v792 r_274 1 + v792 r_978 -1 + v792 r_1412 1 + v792 r_1777 -1 + v792 r_2150 1 + v792 r_2151 1 + v792 r_2152 1 + v792 r_3036 1 + v792 r_3037 1 + v792 r_3038 1 + v793 r_88 1 + v793 r_291 1 + v793 r_993 -1 + v793 r_1413 1 + v793 r_1784 -1 + v793 r_2150 1 + v793 r_2151 1 + v793 r_2152 1 + v794 r_88 1 + v794 r_2005 -1 + v794 r_2026 1 + v794 r_2032 1 + v794 r_2700 1 + v794 r_2701 1 + v794 r_2702 1 + v794 r_2703 1 + v794 r_2704 1 + v795 r_89 1 + v795 r_155 1 + v795 r_901 -1 + v795 r_1407 1 + v795 r_1738 -1 + v795 r_2151 1 + v795 r_2152 1 + v795 r_2153 1 + v795 r_2247 1 + v795 r_2248 1 + v795 r_2249 1 + v795 r_2957 1 + v795 r_2958 1 + v795 r_2959 1 + v796 r_89 1 + v796 r_187 1 + v796 r_916 -1 + v796 r_1408 1 + v796 r_1746 -1 + v796 r_2151 1 + v796 r_2152 1 + v796 r_2153 1 + v796 r_2247 1 + v796 r_2248 1 + v796 r_2249 1 + v796 r_2973 1 + v796 r_2974 1 + v796 r_2975 1 + v797 r_89 1 + v797 r_205 1 + v797 r_931 -1 + v797 r_1409 1 + v797 r_1754 -1 + v797 r_2151 1 + v797 r_2152 1 + v797 r_2153 1 + v797 r_2247 1 + v797 r_2248 1 + v797 r_2249 1 + v797 r_2989 1 + v797 r_2990 1 + v797 r_2991 1 + v798 r_89 1 + v798 r_223 1 + v798 r_947 -1 + v798 r_1410 1 + v798 r_1762 -1 + v798 r_2151 1 + v798 r_2152 1 + v798 r_2153 1 + v798 r_2247 1 + v798 r_2248 1 + v798 r_2249 1 + v798 r_3005 1 + v798 r_3006 1 + v798 r_3007 1 + v799 r_89 1 + v799 r_370 1 + v799 r_586 1 + v799 r_711 1 + v799 r_838 1 + v799 r_1090 1 + v799 r_1219 1 + v799 r_1331 1 + v799 r_2048 1 + v799 r_2349 1 + v799 r_2350 1 + v799 r_2351 1 + v799 r_2436 1 + v799 r_2437 1 + v799 r_2438 1 + v799 r_2533 -1 + v799 r_2534 -1 + v799 r_2535 -1 + v799 r_2536 -1 + v799 r_2611 -1 + v799 r_2612 -1 + v799 r_2613 -1 + v799 r_2701 1 + v799 r_2702 1 + v799 r_2703 1 + v799 r_2704 1 + v799 r_2705 1 + v799 r_2784 1 + v799 r_2785 1 + v799 r_2786 1 + v799 r_2813 1 + v799 r_2829 1 + v800 r_89 1 + v800 r_257 1 + v800 r_963 -1 + v800 r_1411 1 + v800 r_1770 -1 + v800 r_2151 1 + v800 r_2152 1 + v800 r_2153 1 + v800 r_2247 1 + v800 r_2248 1 + v800 r_2249 1 + v800 r_3021 1 + v800 r_3022 1 + v800 r_3023 1 + v801 r_89 1 + v801 r_275 1 + v801 r_979 -1 + v801 r_1412 1 + v801 r_1778 -1 + v801 r_2151 1 + v801 r_2152 1 + v801 r_2153 1 + v801 r_2247 1 + v801 r_2248 1 + v801 r_2249 1 + v801 r_3037 1 + v801 r_3038 1 + v801 r_3039 1 + v802 r_89 1 + v802 r_292 1 + v802 r_994 -1 + v802 r_1413 1 + v802 r_1785 -1 + v802 r_2151 1 + v802 r_2152 1 + v802 r_2153 1 + v802 r_2247 1 + v802 r_2248 1 + v802 r_2249 1 + v803 r_89 1 + v803 r_2006 -1 + v803 r_2026 1 + v803 r_2033 1 + v803 r_2701 1 + v803 r_2702 1 + v803 r_2703 1 + v803 r_2704 1 + v803 r_2705 1 + v803 r_2784 1 + v803 r_2785 1 + v803 r_2786 1 + v803 r_2821 1 + v803 r_2829 1 + v804 r_90 1 + v804 r_156 1 + v804 r_902 -1 + v804 r_1407 1 + v804 r_1739 -1 + v804 r_2152 1 + v804 r_2153 1 + v804 r_2154 1 + v804 r_2958 1 + v804 r_2959 1 + v804 r_2960 1 + v805 r_90 1 + v805 r_188 1 + v805 r_917 -1 + v805 r_1408 1 + v805 r_1747 -1 + v805 r_2152 1 + v805 r_2153 1 + v805 r_2154 1 + v805 r_2974 1 + v805 r_2975 1 + v805 r_2976 1 + v806 r_90 1 + v806 r_206 1 + v806 r_932 -1 + v806 r_1409 1 + v806 r_1755 -1 + v806 r_2152 1 + v806 r_2153 1 + v806 r_2154 1 + v806 r_2990 1 + v806 r_2991 1 + v806 r_2992 1 + v807 r_90 1 + v807 r_224 1 + v807 r_948 -1 + v807 r_1410 1 + v807 r_1763 -1 + v807 r_2152 1 + v807 r_2153 1 + v807 r_2154 1 + v807 r_3006 1 + v807 r_3007 1 + v807 r_3008 1 + v808 r_90 1 + v808 r_371 1 + v808 r_587 1 + v808 r_712 1 + v808 r_839 1 + v808 r_1091 1 + v808 r_1220 1 + v808 r_1332 1 + v808 r_2049 1 + v808 r_2350 1 + v808 r_2351 1 + v808 r_2352 1 + v808 r_2534 -1 + v808 r_2535 -1 + v808 r_2536 -1 + v808 r_2537 -1 + v808 r_2702 1 + v808 r_2703 1 + v808 r_2704 1 + v808 r_2705 1 + v808 r_2706 1 + v809 r_90 1 + v809 r_258 1 + v809 r_964 -1 + v809 r_1411 1 + v809 r_1771 -1 + v809 r_2152 1 + v809 r_2153 1 + v809 r_2154 1 + v809 r_3022 1 + v809 r_3023 1 + v809 r_3024 1 + v810 r_90 1 + v810 r_276 1 + v810 r_980 -1 + v810 r_1412 1 + v810 r_1779 -1 + v810 r_2152 1 + v810 r_2153 1 + v810 r_2154 1 + v810 r_3038 1 + v810 r_3039 1 + v810 r_3040 1 + v811 r_90 1 + v811 r_293 1 + v811 r_995 -1 + v811 r_1413 1 + v811 r_1786 -1 + v811 r_2152 1 + v811 r_2153 1 + v811 r_2154 1 + v812 r_91 1 + v812 r_157 1 + v812 r_903 -1 + v812 r_1407 1 + v812 r_2153 1 + v812 r_2154 1 + v812 r_2155 1 + v812 r_2248 1 + v812 r_2249 1 + v812 r_2250 1 + v812 r_2959 1 + v812 r_2960 1 + v812 r_2961 1 + v813 r_91 1 + v813 r_189 1 + v813 r_918 -1 + v813 r_1408 1 + v813 r_2153 1 + v813 r_2154 1 + v813 r_2155 1 + v813 r_2248 1 + v813 r_2249 1 + v813 r_2250 1 + v813 r_2975 1 + v813 r_2976 1 + v813 r_2977 1 + v814 r_91 1 + v814 r_207 1 + v814 r_933 -1 + v814 r_1409 1 + v814 r_2153 1 + v814 r_2154 1 + v814 r_2155 1 + v814 r_2248 1 + v814 r_2249 1 + v814 r_2250 1 + v814 r_2991 1 + v814 r_2992 1 + v814 r_2993 1 + v815 r_91 1 + v815 r_225 1 + v815 r_949 -1 + v815 r_1410 1 + v815 r_1700 1 + v815 r_2153 1 + v815 r_2154 1 + v815 r_2155 1 + v815 r_2248 1 + v815 r_2249 1 + v815 r_2250 1 + v815 r_3007 1 + v815 r_3008 1 + v815 r_3009 1 + v816 r_91 1 + v816 r_372 1 + v816 r_588 1 + v816 r_713 1 + v816 r_840 1 + v816 r_1092 1 + v816 r_1221 1 + v816 r_2050 1 + v816 r_2351 1 + v816 r_2352 1 + v816 r_2353 1 + v816 r_2437 1 + v816 r_2438 1 + v816 r_2439 1 + v816 r_2535 -1 + v816 r_2536 -1 + v816 r_2537 -1 + v816 r_2611 -1 + v816 r_2612 -1 + v816 r_2613 -1 + v816 r_2614 -1 + v816 r_2703 1 + v816 r_2704 1 + v816 r_2705 1 + v816 r_2706 1 + v816 r_2707 1 + v816 r_2784 1 + v816 r_2785 1 + v816 r_2786 1 + v816 r_2787 1 + v816 r_2813 1 + v816 r_2829 1 + v817 r_91 1 + v817 r_259 1 + v817 r_965 -1 + v817 r_1411 1 + v817 r_1831 1 + v817 r_2153 1 + v817 r_2154 1 + v817 r_2155 1 + v817 r_2248 1 + v817 r_2249 1 + v817 r_2250 1 + v817 r_3023 1 + v817 r_3024 1 + v817 r_3025 1 + v818 r_91 1 + v818 r_277 1 + v818 r_981 -1 + v818 r_1412 1 + v818 r_1898 1 + v818 r_2153 1 + v818 r_2154 1 + v818 r_2155 1 + v818 r_2248 1 + v818 r_2249 1 + v818 r_2250 1 + v818 r_3039 1 + v818 r_3040 1 + v818 r_3041 1 + v819 r_92 1 + v819 r_158 1 + v819 r_904 -1 + v819 r_1407 1 + v819 r_1468 1 + v819 r_2154 1 + v819 r_2155 1 + v819 r_2156 1 + v819 r_2960 1 + v819 r_2961 1 + v819 r_2962 1 + v820 r_92 1 + v820 r_190 1 + v820 r_919 -1 + v820 r_1408 1 + v820 r_1576 1 + v820 r_2154 1 + v820 r_2155 1 + v820 r_2156 1 + v820 r_2976 1 + v820 r_2977 1 + v820 r_2978 1 + v821 r_92 1 + v821 r_208 1 + v821 r_934 -1 + v821 r_1409 1 + v821 r_1636 1 + v821 r_2154 1 + v821 r_2155 1 + v821 r_2156 1 + v821 r_2992 1 + v821 r_2993 1 + v821 r_2994 1 + v822 r_92 1 + v822 r_226 1 + v822 r_950 -1 + v822 r_1410 1 + v822 r_1701 1 + v822 r_2154 1 + v822 r_2155 1 + v822 r_2156 1 + v822 r_3008 1 + v822 r_3009 1 + v822 r_3010 1 + v823 r_92 1 + v823 r_373 1 + v823 r_589 1 + v823 r_714 1 + v823 r_841 1 + v823 r_1093 1 + v823 r_1222 1 + v823 r_1333 1 + v823 r_2051 1 + v823 r_2352 1 + v823 r_2353 1 + v823 r_2354 1 + v823 r_2536 -1 + v823 r_2537 -1 + v823 r_2704 1 + v823 r_2705 1 + v823 r_2706 1 + v823 r_2707 1 + v823 r_2708 1 + v824 r_92 1 + v824 r_260 1 + v824 r_966 -1 + v824 r_1411 1 + v824 r_1832 1 + v824 r_2154 1 + v824 r_2155 1 + v824 r_2156 1 + v824 r_3024 1 + v824 r_3025 1 + v824 r_3026 1 + v825 r_92 1 + v825 r_278 1 + v825 r_982 -1 + v825 r_1412 1 + v825 r_1899 1 + v825 r_2154 1 + v825 r_2155 1 + v825 r_2156 1 + v825 r_3040 1 + v825 r_3041 1 + v825 r_3042 1 + v826 r_92 1 + v826 r_294 1 + v826 r_996 -1 + v826 r_1413 1 + v826 r_1955 1 + v826 r_2154 1 + v826 r_2155 1 + v826 r_2156 1 + v827 r_92 1 + v827 r_2002 1 + v827 r_2026 1 + v827 r_2034 1 + v827 r_2704 1 + v827 r_2705 1 + v827 r_2706 1 + v827 r_2707 1 + v827 r_2708 1 + v828 r_93 1 + v828 r_159 1 + v828 r_905 -1 + v828 r_1407 1 + v828 r_1740 -1 + v828 r_2155 1 + v828 r_2156 1 + v828 r_2157 1 + v828 r_2249 1 + v828 r_2250 1 + v828 r_2251 1 + v828 r_2961 1 + v828 r_2962 1 + v828 r_2963 1 + v829 r_93 1 + v829 r_191 1 + v829 r_920 -1 + v829 r_1408 1 + v829 r_1748 -1 + v829 r_2155 1 + v829 r_2156 1 + v829 r_2157 1 + v829 r_2249 1 + v829 r_2250 1 + v829 r_2251 1 + v829 r_2977 1 + v829 r_2978 1 + v829 r_2979 1 + v830 r_93 1 + v830 r_209 1 + v830 r_935 -1 + v830 r_1409 1 + v830 r_1756 -1 + v830 r_2155 1 + v830 r_2156 1 + v830 r_2157 1 + v830 r_2249 1 + v830 r_2250 1 + v830 r_2251 1 + v830 r_2993 1 + v830 r_2994 1 + v830 r_2995 1 + v831 r_93 1 + v831 r_227 1 + v831 r_951 -1 + v831 r_1410 1 + v831 r_1764 -1 + v831 r_2155 1 + v831 r_2156 1 + v831 r_2157 1 + v831 r_2249 1 + v831 r_2250 1 + v831 r_2251 1 + v831 r_3009 1 + v831 r_3010 1 + v831 r_3011 1 + v832 r_93 1 + v832 r_374 1 + v832 r_590 1 + v832 r_715 1 + v832 r_842 1 + v832 r_1094 1 + v832 r_1223 1 + v832 r_2052 1 + v832 r_2353 1 + v832 r_2354 1 + v832 r_2355 1 + v832 r_2438 1 + v832 r_2439 1 + v832 r_2440 1 + v832 r_2537 -1 + v832 r_2612 -1 + v832 r_2613 -1 + v832 r_2614 -1 + v832 r_2615 -1 + v832 r_2705 1 + v832 r_2706 1 + v832 r_2707 1 + v832 r_2708 1 + v832 r_2709 1 + v832 r_2785 1 + v832 r_2786 1 + v832 r_2787 1 + v832 r_2788 1 + v832 r_2813 1 + v832 r_2829 1 + v833 r_93 1 + v833 r_261 1 + v833 r_967 -1 + v833 r_1411 1 + v833 r_1772 -1 + v833 r_2155 1 + v833 r_2156 1 + v833 r_2157 1 + v833 r_2249 1 + v833 r_2250 1 + v833 r_2251 1 + v833 r_3025 1 + v833 r_3026 1 + v833 r_3027 1 + v834 r_93 1 + v834 r_279 1 + v834 r_983 -1 + v834 r_1412 1 + v834 r_1780 -1 + v834 r_2155 1 + v834 r_2156 1 + v834 r_2157 1 + v834 r_2249 1 + v834 r_2250 1 + v834 r_2251 1 + v834 r_3041 1 + v834 r_3042 1 + v834 r_3043 1 + v835 r_93 1 + v835 r_295 1 + v835 r_1413 1 + v835 r_1787 -1 + v835 r_2155 1 + v835 r_2156 1 + v835 r_2157 1 + v835 r_2249 1 + v835 r_2250 1 + v835 r_2251 1 + v836 r_93 1 + v836 r_2007 -1 + v836 r_2026 1 + v836 r_2035 1 + v836 r_2705 1 + v836 r_2706 1 + v836 r_2707 1 + v836 r_2708 1 + v836 r_2709 1 + v836 r_2785 1 + v836 r_2786 1 + v836 r_2787 1 + v836 r_2788 1 + v836 r_2821 1 + v836 r_2829 1 + v837 r_94 1 + v837 r_161 1 + v837 r_906 -1 + v837 r_1407 1 + v837 r_1469 1 + v837 r_2157 1 + v837 r_2158 1 + v837 r_2159 1 + v837 r_2250 1 + v837 r_2251 1 + v837 r_2252 1 + v837 r_2963 1 + v837 r_2964 1 + v837 r_2965 1 + v838 r_94 1 + v838 r_193 1 + v838 r_921 -1 + v838 r_1408 1 + v838 r_1577 1 + v838 r_2157 1 + v838 r_2158 1 + v838 r_2159 1 + v838 r_2250 1 + v838 r_2251 1 + v838 r_2252 1 + v838 r_2979 1 + v838 r_2980 1 + v838 r_2981 1 + v839 r_94 1 + v839 r_211 1 + v839 r_936 -1 + v839 r_1409 1 + v839 r_1637 1 + v839 r_2157 1 + v839 r_2158 1 + v839 r_2159 1 + v839 r_2250 1 + v839 r_2251 1 + v839 r_2252 1 + v839 r_2835 1 + v839 r_2995 1 + v839 r_2996 1 + v839 r_2997 1 + v840 r_94 1 + v840 r_229 1 + v840 r_952 -1 + v840 r_1410 1 + v840 r_1702 1 + v840 r_2157 1 + v840 r_2158 1 + v840 r_2159 1 + v840 r_2250 1 + v840 r_2251 1 + v840 r_2252 1 + v840 r_3011 1 + v840 r_3012 1 + v840 r_3013 1 + v841 r_94 1 + v841 r_375 1 + v841 r_591 1 + v841 r_716 1 + v841 r_843 1 + v841 r_1095 1 + v841 r_1224 1 + v841 r_1334 1 + v841 r_2054 1 + v841 r_2355 1 + v841 r_2356 1 + v841 r_2357 1 + v841 r_2439 1 + v841 r_2440 1 + v841 r_2441 1 + v841 r_2538 -1 + v841 r_2613 -1 + v841 r_2614 -1 + v841 r_2615 -1 + v841 r_2616 -1 + v841 r_2707 1 + v841 r_2708 1 + v841 r_2709 1 + v841 r_2710 1 + v841 r_2711 1 + v841 r_2786 1 + v841 r_2787 1 + v841 r_2788 1 + v841 r_2789 1 + v841 r_2813 1 + v842 r_94 1 + v842 r_263 1 + v842 r_968 -1 + v842 r_1411 1 + v842 r_1833 1 + v842 r_2157 1 + v842 r_2158 1 + v842 r_2159 1 + v842 r_2250 1 + v842 r_2251 1 + v842 r_2252 1 + v842 r_3027 1 + v842 r_3028 1 + v842 r_3029 1 + v843 r_94 1 + v843 r_281 1 + v843 r_984 -1 + v843 r_1412 1 + v843 r_1900 1 + v843 r_2157 1 + v843 r_2158 1 + v843 r_2159 1 + v843 r_2250 1 + v843 r_2251 1 + v843 r_2252 1 + v843 r_3043 1 + v843 r_3044 1 + v843 r_3045 1 + v844 r_94 1 + v844 r_296 1 + v844 r_997 -1 + v844 r_1413 1 + v844 r_1956 1 + v844 r_2157 1 + v844 r_2158 1 + v844 r_2159 1 + v844 r_2250 1 + v844 r_2251 1 + v844 r_2252 1 + v844 r_2833 1 + v845 r_94 1 + v845 r_2003 1 + v845 r_2026 1 + v845 r_2037 1 + v845 r_2707 1 + v845 r_2708 1 + v845 r_2709 1 + v845 r_2710 1 + v845 r_2711 1 + v845 r_2786 1 + v845 r_2787 1 + v845 r_2788 1 + v845 r_2789 1 + v845 r_2821 1 + v846 r_95 1 + v846 r_162 1 + v846 r_907 -1 + v846 r_1407 1 + v846 r_1470 1 + v846 r_2158 1 + v846 r_2159 1 + v846 r_2160 1 + v846 r_2964 1 + v846 r_2965 1 + v846 r_2966 1 + v847 r_95 1 + v847 r_194 1 + v847 r_922 -1 + v847 r_1408 1 + v847 r_1578 1 + v847 r_2158 1 + v847 r_2159 1 + v847 r_2160 1 + v847 r_2980 1 + v847 r_2981 1 + v847 r_2982 1 + v848 r_95 1 + v848 r_212 1 + v848 r_937 -1 + v848 r_1409 1 + v848 r_1638 1 + v848 r_2158 1 + v848 r_2159 1 + v848 r_2160 1 + v848 r_2835 1 + v848 r_2996 1 + v848 r_2997 1 + v848 r_2998 1 + v849 r_95 1 + v849 r_230 1 + v849 r_953 -1 + v849 r_1410 1 + v849 r_1703 1 + v849 r_2158 1 + v849 r_2159 1 + v849 r_2160 1 + v849 r_3012 1 + v849 r_3013 1 + v849 r_3014 1 + v850 r_95 1 + v850 r_376 1 + v850 r_592 1 + v850 r_717 1 + v850 r_844 1 + v850 r_1096 1 + v850 r_1225 1 + v850 r_1335 1 + v850 r_2055 1 + v850 r_2356 1 + v850 r_2357 1 + v850 r_2358 1 + v850 r_2538 -1 + v850 r_2539 -1 + v850 r_2708 1 + v850 r_2709 1 + v850 r_2710 1 + v850 r_2711 1 + v850 r_2712 1 + v851 r_95 1 + v851 r_264 1 + v851 r_969 -1 + v851 r_1411 1 + v851 r_1834 1 + v851 r_2158 1 + v851 r_2159 1 + v851 r_2160 1 + v851 r_3028 1 + v851 r_3029 1 + v851 r_3030 1 + v852 r_95 1 + v852 r_282 1 + v852 r_985 -1 + v852 r_1412 1 + v852 r_1901 1 + v852 r_2158 1 + v852 r_2159 1 + v852 r_2160 1 + v852 r_3044 1 + v852 r_3045 1 + v852 r_3046 1 + v853 r_95 1 + v853 r_297 1 + v853 r_998 -1 + v853 r_1413 1 + v853 r_1957 1 + v853 r_2158 1 + v853 r_2159 1 + v853 r_2160 1 + v853 r_2833 1 + v854 r_95 1 + v854 r_2004 1 + v854 r_2026 1 + v854 r_2038 1 + v854 r_2708 1 + v854 r_2709 1 + v854 r_2710 1 + v854 r_2711 1 + v854 r_2712 1 + v855 r_96 1 + v855 r_163 1 + v855 r_908 -1 + v855 r_1407 1 + v855 r_1471 1 + v855 r_2159 1 + v855 r_2160 1 + v855 r_2161 1 + v855 r_2251 1 + v855 r_2252 1 + v855 r_2253 1 + v855 r_2965 1 + v855 r_2966 1 + v855 r_2967 1 + v856 r_96 1 + v856 r_195 1 + v856 r_923 -1 + v856 r_1408 1 + v856 r_1579 1 + v856 r_2159 1 + v856 r_2160 1 + v856 r_2161 1 + v856 r_2251 1 + v856 r_2252 1 + v856 r_2253 1 + v856 r_2981 1 + v856 r_2982 1 + v856 r_2983 1 + v857 r_96 1 + v857 r_213 1 + v857 r_938 -1 + v857 r_1409 1 + v857 r_1639 1 + v857 r_2159 1 + v857 r_2160 1 + v857 r_2161 1 + v857 r_2251 1 + v857 r_2252 1 + v857 r_2253 1 + v857 r_2835 1 + v857 r_2997 1 + v857 r_2998 1 + v857 r_2999 1 + v858 r_96 1 + v858 r_231 1 + v858 r_954 -1 + v858 r_1410 1 + v858 r_1704 1 + v858 r_2159 1 + v858 r_2160 1 + v858 r_2161 1 + v858 r_2251 1 + v858 r_2252 1 + v858 r_2253 1 + v858 r_3013 1 + v858 r_3014 1 + v858 r_3015 1 + v859 r_96 1 + v859 r_377 1 + v859 r_593 1 + v859 r_718 1 + v859 r_845 1 + v859 r_1097 1 + v859 r_1226 1 + v859 r_1336 1 + v859 r_2056 1 + v859 r_2357 1 + v859 r_2358 1 + v859 r_2359 1 + v859 r_2440 1 + v859 r_2441 1 + v859 r_2538 -1 + v859 r_2539 -1 + v859 r_2540 -1 + v859 r_2614 -1 + v859 r_2615 -1 + v859 r_2616 -1 + v859 r_2709 1 + v859 r_2710 1 + v859 r_2711 1 + v859 r_2712 1 + v859 r_2713 1 + v859 r_2787 1 + v859 r_2788 1 + v859 r_2789 1 + v859 r_2813 1 + v860 r_96 1 + v860 r_265 1 + v860 r_970 -1 + v860 r_1411 1 + v860 r_1835 1 + v860 r_2159 1 + v860 r_2160 1 + v860 r_2161 1 + v860 r_2251 1 + v860 r_2252 1 + v860 r_2253 1 + v860 r_3029 1 + v860 r_3030 1 + v860 r_3031 1 + v861 r_96 1 + v861 r_283 1 + v861 r_986 -1 + v861 r_1412 1 + v861 r_1902 1 + v861 r_2159 1 + v861 r_2160 1 + v861 r_2161 1 + v861 r_2251 1 + v861 r_2252 1 + v861 r_2253 1 + v861 r_3045 1 + v861 r_3046 1 + v861 r_3047 1 + v862 r_96 1 + v862 r_298 1 + v862 r_999 -1 + v862 r_1413 1 + v862 r_1958 1 + v862 r_2159 1 + v862 r_2160 1 + v862 r_2161 1 + v862 r_2251 1 + v862 r_2252 1 + v862 r_2253 1 + v862 r_2833 1 + v863 r_96 1 + v863 r_2005 1 + v863 r_2026 1 + v863 r_2039 1 + v863 r_2709 1 + v863 r_2710 1 + v863 r_2711 1 + v863 r_2712 1 + v863 r_2713 1 + v863 r_2787 1 + v863 r_2788 1 + v863 r_2789 1 + v863 r_2821 1 + v864 r_97 1 + v864 r_164 1 + v864 r_909 -1 + v864 r_1407 1 + v864 r_1472 1 + v864 r_2160 1 + v864 r_2161 1 + v864 r_2162 1 + v864 r_2966 1 + v864 r_2967 1 + v864 r_2968 1 + v865 r_97 1 + v865 r_196 1 + v865 r_924 -1 + v865 r_1408 1 + v865 r_1580 1 + v865 r_2160 1 + v865 r_2161 1 + v865 r_2162 1 + v865 r_2982 1 + v865 r_2983 1 + v865 r_2984 1 + v866 r_97 1 + v866 r_214 1 + v866 r_939 -1 + v866 r_1409 1 + v866 r_1640 1 + v866 r_2160 1 + v866 r_2161 1 + v866 r_2162 1 + v866 r_2835 1 + v866 r_2998 1 + v866 r_2999 1 + v866 r_3000 1 + v867 r_97 1 + v867 r_232 1 + v867 r_955 -1 + v867 r_1410 1 + v867 r_1705 1 + v867 r_2160 1 + v867 r_2161 1 + v867 r_2162 1 + v867 r_3014 1 + v867 r_3015 1 + v867 r_3016 1 + v868 r_97 1 + v868 r_378 1 + v868 r_594 1 + v868 r_719 1 + v868 r_846 1 + v868 r_1098 1 + v868 r_1227 1 + v868 r_1337 1 + v868 r_2057 1 + v868 r_2358 1 + v868 r_2359 1 + v868 r_2360 1 + v868 r_2538 -1 + v868 r_2539 -1 + v868 r_2540 -1 + v868 r_2541 -1 + v868 r_2710 1 + v868 r_2711 1 + v868 r_2712 1 + v868 r_2713 1 + v869 r_97 1 + v869 r_266 1 + v869 r_971 -1 + v869 r_1411 1 + v869 r_1836 1 + v869 r_2160 1 + v869 r_2161 1 + v869 r_2162 1 + v869 r_3030 1 + v869 r_3031 1 + v869 r_3032 1 + v870 r_97 1 + v870 r_284 1 + v870 r_987 -1 + v870 r_1412 1 + v870 r_1903 1 + v870 r_2160 1 + v870 r_2161 1 + v870 r_2162 1 + v870 r_3046 1 + v870 r_3047 1 + v870 r_3048 1 + v871 r_97 1 + v871 r_299 1 + v871 r_1000 -1 + v871 r_1413 1 + v871 r_1959 1 + v871 r_2160 1 + v871 r_2161 1 + v871 r_2162 1 + v871 r_2833 1 + v872 r_97 1 + v872 r_2006 1 + v872 r_2026 1 + v872 r_2040 1 + v872 r_2710 1 + v872 r_2711 1 + v872 r_2712 1 + v872 r_2713 1 + v873 r_98 1 + v873 r_165 1 + v873 r_910 -1 + v873 r_1407 1 + v873 r_1473 1 + v873 r_2161 1 + v873 r_2162 1 + v873 r_2163 1 + v873 r_2252 1 + v873 r_2253 1 + v873 r_2967 1 + v873 r_2968 1 + v873 r_2969 1 + v874 r_98 1 + v874 r_197 1 + v874 r_925 -1 + v874 r_1408 1 + v874 r_1581 1 + v874 r_2161 1 + v874 r_2162 1 + v874 r_2163 1 + v874 r_2252 1 + v874 r_2253 1 + v874 r_2983 1 + v874 r_2984 1 + v874 r_2985 1 + v875 r_98 1 + v875 r_215 1 + v875 r_940 -1 + v875 r_1409 1 + v875 r_1641 1 + v875 r_2161 1 + v875 r_2162 1 + v875 r_2163 1 + v875 r_2252 1 + v875 r_2253 1 + v875 r_2835 1 + v875 r_2999 1 + v875 r_3000 1 + v875 r_3001 1 + v876 r_98 1 + v876 r_233 1 + v876 r_956 -1 + v876 r_1410 1 + v876 r_1706 1 + v876 r_2161 1 + v876 r_2162 1 + v876 r_2163 1 + v876 r_2252 1 + v876 r_2253 1 + v876 r_3015 1 + v876 r_3016 1 + v876 r_3017 1 + v877 r_98 1 + v877 r_379 1 + v877 r_595 1 + v877 r_720 1 + v877 r_847 1 + v877 r_1099 1 + v877 r_1228 1 + v877 r_1338 1 + v877 r_2058 1 + v877 r_2359 1 + v877 r_2360 1 + v877 r_2441 1 + v877 r_2539 -1 + v877 r_2540 -1 + v877 r_2541 -1 + v877 r_2615 -1 + v877 r_2616 -1 + v877 r_2711 1 + v877 r_2712 1 + v877 r_2713 1 + v877 r_2788 1 + v877 r_2789 1 + v877 r_2813 1 + v878 r_98 1 + v878 r_267 1 + v878 r_972 -1 + v878 r_1411 1 + v878 r_1837 1 + v878 r_2161 1 + v878 r_2162 1 + v878 r_2163 1 + v878 r_2252 1 + v878 r_2253 1 + v878 r_3031 1 + v878 r_3032 1 + v878 r_3033 1 + v879 r_98 1 + v879 r_285 1 + v879 r_988 -1 + v879 r_1412 1 + v879 r_1904 1 + v879 r_2161 1 + v879 r_2162 1 + v879 r_2163 1 + v879 r_2252 1 + v879 r_2253 1 + v879 r_3047 1 + v879 r_3048 1 + v879 r_3049 1 + v880 r_98 1 + v880 r_300 1 + v880 r_1001 -1 + v880 r_1413 1 + v880 r_1960 1 + v880 r_2161 1 + v880 r_2162 1 + v880 r_2163 1 + v880 r_2252 1 + v880 r_2253 1 + v880 r_2833 1 + v881 r_99 1 + v881 r_166 1 + v881 r_911 -1 + v881 r_1407 1 + v881 r_1474 1 + v881 r_2162 1 + v881 r_2163 1 + v881 r_2968 1 + v881 r_2969 1 + v882 r_99 1 + v882 r_198 1 + v882 r_926 -1 + v882 r_1408 1 + v882 r_1582 1 + v882 r_2162 1 + v882 r_2163 1 + v882 r_2984 1 + v882 r_2985 1 + v883 r_99 1 + v883 r_216 1 + v883 r_941 -1 + v883 r_1409 1 + v883 r_1642 1 + v883 r_2162 1 + v883 r_2163 1 + v883 r_2835 1 + v883 r_3000 1 + v883 r_3001 1 + v884 r_99 1 + v884 r_234 1 + v884 r_957 -1 + v884 r_1410 1 + v884 r_1707 1 + v884 r_2162 1 + v884 r_2163 1 + v884 r_3016 1 + v884 r_3017 1 + v885 r_99 1 + v885 r_380 1 + v885 r_596 1 + v885 r_721 1 + v885 r_848 1 + v885 r_1100 1 + v885 r_1229 1 + v885 r_1339 1 + v885 r_2059 1 + v885 r_2065 1 + v885 r_2360 1 + v885 r_2540 -1 + v885 r_2541 -1 + v885 r_2712 1 + v885 r_2713 1 + v886 r_99 1 + v886 r_268 1 + v886 r_973 -1 + v886 r_1411 1 + v886 r_1838 1 + v886 r_2162 1 + v886 r_2163 1 + v886 r_3032 1 + v886 r_3033 1 + v887 r_99 1 + v887 r_286 1 + v887 r_989 -1 + v887 r_1412 1 + v887 r_1905 1 + v887 r_2162 1 + v887 r_2163 1 + v887 r_3048 1 + v887 r_3049 1 + v888 r_99 1 + v888 r_2007 1 + v888 r_2026 1 + v888 r_2041 1 + v888 r_2065 1 + v888 r_2712 1 + v888 r_2713 1 + v889 r_100 1 + v889 r_150 1 + v889 r_1414 1 + v889 r_1788 -1 + v889 r_2164 1 + v890 r_100 1 + v890 r_168 1 + v890 r_1019 -1 + v890 r_1415 1 + v890 r_1797 -1 + v890 r_2164 1 + v890 r_2905 1 + v890 r_3018 1 + v891 r_100 1 + v891 r_182 1 + v891 r_1416 1 + v891 r_1804 -1 + v891 r_2164 1 + v892 r_100 1 + v892 r_200 1 + v892 r_1417 1 + v892 r_1813 -1 + v892 r_2164 1 + v893 r_100 1 + v893 r_218 1 + v893 r_1067 -1 + v893 r_1418 1 + v893 r_1822 -1 + v893 r_2164 1 + v894 r_100 1 + v894 r_236 1 + v894 r_1085 -1 + v894 r_1419 1 + v894 r_1831 -1 + v894 r_2164 1 + v894 r_2905 1 + v894 r_3018 1 + v895 r_100 1 + v895 r_480 1 + v895 r_849 1 + v895 r_958 1 + v895 r_1230 1 + v895 r_2043 1 + v895 r_2361 1 + v895 r_2542 -1 + v895 r_2714 1 + v896 r_100 1 + v896 r_270 1 + v896 r_1101 -1 + v896 r_1420 1 + v896 r_1839 -1 + v896 r_2164 1 + v897 r_101 1 + v897 r_151 1 + v897 r_1002 -1 + v897 r_1414 1 + v897 r_1789 -1 + v897 r_2164 1 + v897 r_2165 1 + v897 r_2254 1 + v898 r_101 1 + v898 r_169 1 + v898 r_1020 -1 + v898 r_1415 1 + v898 r_1798 -1 + v898 r_2164 1 + v898 r_2165 1 + v898 r_2254 1 + v898 r_2905 1 + v898 r_2906 1 + v898 r_3018 1 + v898 r_3019 1 + v899 r_101 1 + v899 r_183 1 + v899 r_1033 -1 + v899 r_1416 1 + v899 r_1805 -1 + v899 r_2164 1 + v899 r_2165 1 + v899 r_2254 1 + v900 r_101 1 + v900 r_201 1 + v900 r_1050 -1 + v900 r_1417 1 + v900 r_1814 -1 + v900 r_2164 1 + v900 r_2165 1 + v900 r_2254 1 + v901 r_101 1 + v901 r_219 1 + v901 r_1068 -1 + v901 r_1418 1 + v901 r_1823 -1 + v901 r_2164 1 + v901 r_2165 1 + v901 r_2254 1 + v902 r_101 1 + v902 r_237 1 + v902 r_1086 -1 + v902 r_1419 1 + v902 r_1832 -1 + v902 r_2164 1 + v902 r_2165 1 + v902 r_2254 1 + v902 r_2905 1 + v902 r_2906 1 + v902 r_3018 1 + v902 r_3019 1 + v903 r_101 1 + v903 r_381 1 + v903 r_481 1 + v903 r_597 1 + v903 r_722 1 + v903 r_850 1 + v903 r_959 1 + v903 r_1231 1 + v903 r_1340 1 + v903 r_2044 1 + v903 r_2361 1 + v903 r_2362 1 + v903 r_2442 1 + v903 r_2542 -1 + v903 r_2543 -1 + v903 r_2617 -1 + v903 r_2714 1 + v903 r_2715 1 + v903 r_2790 1 + v903 r_2814 1 + v903 r_2830 1 + v904 r_101 1 + v904 r_271 1 + v904 r_1102 -1 + v904 r_1420 1 + v904 r_1840 -1 + v904 r_2164 1 + v904 r_2165 1 + v904 r_2254 1 + v905 r_101 1 + v905 r_288 1 + v905 r_1119 -1 + v905 r_1421 1 + v905 r_1848 -1 + v905 r_2164 1 + v905 r_2165 1 + v905 r_2254 1 + v905 r_3018 1 + v905 r_3019 1 + v906 r_101 1 + v906 r_2008 -1 + v906 r_2027 1 + v906 r_2029 1 + v906 r_2714 1 + v906 r_2715 1 + v906 r_2790 1 + v906 r_2822 1 + v906 r_2830 1 + v907 r_102 1 + v907 r_152 1 + v907 r_1003 -1 + v907 r_1414 1 + v907 r_1790 -1 + v907 r_2164 1 + v907 r_2165 1 + v907 r_2166 1 + v908 r_102 1 + v908 r_170 1 + v908 r_1021 -1 + v908 r_1415 1 + v908 r_1799 -1 + v908 r_2164 1 + v908 r_2165 1 + v908 r_2166 1 + v908 r_2906 1 + v908 r_2907 1 + v908 r_3018 1 + v908 r_3019 1 + v908 r_3020 1 + v909 r_102 1 + v909 r_184 1 + v909 r_1034 -1 + v909 r_1416 1 + v909 r_1806 -1 + v909 r_2164 1 + v909 r_2165 1 + v909 r_2166 1 + v910 r_102 1 + v910 r_202 1 + v910 r_1051 -1 + v910 r_1417 1 + v910 r_1815 -1 + v910 r_2164 1 + v910 r_2165 1 + v910 r_2166 1 + v911 r_102 1 + v911 r_220 1 + v911 r_1069 -1 + v911 r_1418 1 + v911 r_1824 -1 + v911 r_2164 1 + v911 r_2165 1 + v911 r_2166 1 + v912 r_102 1 + v912 r_238 1 + v912 r_1087 -1 + v912 r_1419 1 + v912 r_1833 -1 + v912 r_2164 1 + v912 r_2165 1 + v912 r_2166 1 + v912 r_2906 1 + v912 r_2907 1 + v912 r_3018 1 + v912 r_3019 1 + v912 r_3020 1 + v913 r_102 1 + v913 r_382 1 + v913 r_482 1 + v913 r_598 1 + v913 r_723 1 + v913 r_851 1 + v913 r_960 1 + v913 r_1232 1 + v913 r_1341 1 + v913 r_2045 1 + v913 r_2361 1 + v913 r_2362 1 + v913 r_2363 1 + v913 r_2542 -1 + v913 r_2543 -1 + v913 r_2544 -1 + v913 r_2714 1 + v913 r_2715 1 + v913 r_2716 1 + v914 r_102 1 + v914 r_272 1 + v914 r_1103 -1 + v914 r_1420 1 + v914 r_1841 -1 + v914 r_2164 1 + v914 r_2165 1 + v914 r_2166 1 + v915 r_102 1 + v915 r_289 1 + v915 r_1120 -1 + v915 r_1421 1 + v915 r_1849 -1 + v915 r_2164 1 + v915 r_2165 1 + v915 r_2166 1 + v915 r_3018 1 + v915 r_3019 1 + v915 r_3020 1 + v916 r_102 1 + v916 r_2009 -1 + v916 r_2027 1 + v916 r_2030 1 + v916 r_2714 1 + v916 r_2715 1 + v916 r_2716 1 + v917 r_103 1 + v917 r_153 1 + v917 r_1004 -1 + v917 r_1414 1 + v917 r_1791 -1 + v917 r_2165 1 + v917 r_2166 1 + v917 r_2167 1 + v917 r_2254 1 + v917 r_2255 1 + v918 r_103 1 + v918 r_171 1 + v918 r_1022 -1 + v918 r_1415 1 + v918 r_1800 -1 + v918 r_2165 1 + v918 r_2166 1 + v918 r_2167 1 + v918 r_2254 1 + v918 r_2255 1 + v918 r_2907 1 + v918 r_2908 1 + v918 r_3019 1 + v918 r_3020 1 + v918 r_3021 1 + v919 r_103 1 + v919 r_185 1 + v919 r_1035 -1 + v919 r_1416 1 + v919 r_1807 -1 + v919 r_2165 1 + v919 r_2166 1 + v919 r_2167 1 + v919 r_2254 1 + v919 r_2255 1 + v920 r_103 1 + v920 r_203 1 + v920 r_1052 -1 + v920 r_1417 1 + v920 r_1816 -1 + v920 r_2165 1 + v920 r_2166 1 + v920 r_2167 1 + v920 r_2254 1 + v920 r_2255 1 + v921 r_103 1 + v921 r_221 1 + v921 r_1070 -1 + v921 r_1418 1 + v921 r_1825 -1 + v921 r_2165 1 + v921 r_2166 1 + v921 r_2167 1 + v921 r_2254 1 + v921 r_2255 1 + v922 r_103 1 + v922 r_239 1 + v922 r_1088 -1 + v922 r_1419 1 + v922 r_1834 -1 + v922 r_2165 1 + v922 r_2166 1 + v922 r_2167 1 + v922 r_2254 1 + v922 r_2255 1 + v922 r_2907 1 + v922 r_2908 1 + v922 r_3019 1 + v922 r_3020 1 + v922 r_3021 1 + v923 r_103 1 + v923 r_383 1 + v923 r_483 1 + v923 r_599 1 + v923 r_724 1 + v923 r_852 1 + v923 r_961 1 + v923 r_1233 1 + v923 r_1342 1 + v923 r_2046 1 + v923 r_2362 1 + v923 r_2363 1 + v923 r_2364 1 + v923 r_2442 1 + v923 r_2443 1 + v923 r_2542 -1 + v923 r_2543 -1 + v923 r_2544 -1 + v923 r_2545 -1 + v923 r_2617 -1 + v923 r_2618 -1 + v923 r_2714 1 + v923 r_2715 1 + v923 r_2716 1 + v923 r_2717 1 + v923 r_2790 1 + v923 r_2791 1 + v923 r_2814 1 + v923 r_2830 1 + v924 r_103 1 + v924 r_273 1 + v924 r_1104 -1 + v924 r_1420 1 + v924 r_1842 -1 + v924 r_2165 1 + v924 r_2166 1 + v924 r_2167 1 + v924 r_2254 1 + v924 r_2255 1 + v925 r_103 1 + v925 r_290 1 + v925 r_1121 -1 + v925 r_1421 1 + v925 r_1850 -1 + v925 r_2165 1 + v925 r_2166 1 + v925 r_2167 1 + v925 r_2254 1 + v925 r_2255 1 + v925 r_3019 1 + v925 r_3020 1 + v925 r_3021 1 + v926 r_103 1 + v926 r_2010 -1 + v926 r_2027 1 + v926 r_2031 1 + v926 r_2714 1 + v926 r_2715 1 + v926 r_2716 1 + v926 r_2717 1 + v926 r_2790 1 + v926 r_2791 1 + v926 r_2822 1 + v926 r_2830 1 + v927 r_104 1 + v927 r_154 1 + v927 r_1005 -1 + v927 r_1414 1 + v927 r_1792 -1 + v927 r_2166 1 + v927 r_2167 1 + v927 r_2168 1 + v928 r_104 1 + v928 r_172 1 + v928 r_1023 -1 + v928 r_1415 1 + v928 r_1801 -1 + v928 r_2166 1 + v928 r_2167 1 + v928 r_2168 1 + v928 r_2908 1 + v928 r_2909 1 + v928 r_3020 1 + v928 r_3021 1 + v928 r_3022 1 + v929 r_104 1 + v929 r_186 1 + v929 r_1036 -1 + v929 r_1416 1 + v929 r_1808 -1 + v929 r_2166 1 + v929 r_2167 1 + v929 r_2168 1 + v930 r_104 1 + v930 r_204 1 + v930 r_1053 -1 + v930 r_1417 1 + v930 r_1817 -1 + v930 r_2166 1 + v930 r_2167 1 + v930 r_2168 1 + v931 r_104 1 + v931 r_222 1 + v931 r_1071 -1 + v931 r_1418 1 + v931 r_1826 -1 + v931 r_2166 1 + v931 r_2167 1 + v931 r_2168 1 + v932 r_104 1 + v932 r_240 1 + v932 r_1089 -1 + v932 r_1419 1 + v932 r_1835 -1 + v932 r_2166 1 + v932 r_2167 1 + v932 r_2168 1 + v932 r_2908 1 + v932 r_2909 1 + v932 r_3020 1 + v932 r_3021 1 + v932 r_3022 1 + v933 r_104 1 + v933 r_384 1 + v933 r_484 1 + v933 r_600 1 + v933 r_725 1 + v933 r_853 1 + v933 r_962 1 + v933 r_1234 1 + v933 r_1343 1 + v933 r_2047 1 + v933 r_2363 1 + v933 r_2364 1 + v933 r_2365 1 + v933 r_2543 -1 + v933 r_2544 -1 + v933 r_2545 -1 + v933 r_2546 -1 + v933 r_2714 1 + v933 r_2715 1 + v933 r_2716 1 + v933 r_2717 1 + v933 r_2718 1 + v934 r_104 1 + v934 r_274 1 + v934 r_1105 -1 + v934 r_1420 1 + v934 r_1843 -1 + v934 r_2166 1 + v934 r_2167 1 + v934 r_2168 1 + v935 r_104 1 + v935 r_291 1 + v935 r_1122 -1 + v935 r_1421 1 + v935 r_1851 -1 + v935 r_2166 1 + v935 r_2167 1 + v935 r_2168 1 + v935 r_3020 1 + v935 r_3021 1 + v935 r_3022 1 + v936 r_104 1 + v936 r_2011 -1 + v936 r_2027 1 + v936 r_2032 1 + v936 r_2714 1 + v936 r_2715 1 + v936 r_2716 1 + v936 r_2717 1 + v936 r_2718 1 + v937 r_105 1 + v937 r_155 1 + v937 r_1006 -1 + v937 r_1414 1 + v937 r_1793 -1 + v937 r_2167 1 + v937 r_2168 1 + v937 r_2169 1 + v937 r_2254 1 + v937 r_2255 1 + v937 r_2256 1 + v938 r_105 1 + v938 r_173 1 + v938 r_1024 -1 + v938 r_1415 1 + v938 r_1802 -1 + v938 r_2167 1 + v938 r_2168 1 + v938 r_2169 1 + v938 r_2254 1 + v938 r_2255 1 + v938 r_2256 1 + v938 r_2909 1 + v938 r_2910 1 + v938 r_3021 1 + v938 r_3022 1 + v938 r_3023 1 + v939 r_105 1 + v939 r_187 1 + v939 r_1037 -1 + v939 r_1416 1 + v939 r_1809 -1 + v939 r_2167 1 + v939 r_2168 1 + v939 r_2169 1 + v939 r_2254 1 + v939 r_2255 1 + v939 r_2256 1 + v940 r_105 1 + v940 r_205 1 + v940 r_1054 -1 + v940 r_1417 1 + v940 r_1818 -1 + v940 r_2167 1 + v940 r_2168 1 + v940 r_2169 1 + v940 r_2254 1 + v940 r_2255 1 + v940 r_2256 1 + v941 r_105 1 + v941 r_223 1 + v941 r_1072 -1 + v941 r_1418 1 + v941 r_1827 -1 + v941 r_2167 1 + v941 r_2168 1 + v941 r_2169 1 + v941 r_2254 1 + v941 r_2255 1 + v941 r_2256 1 + v942 r_105 1 + v942 r_241 1 + v942 r_1090 -1 + v942 r_1419 1 + v942 r_1836 -1 + v942 r_2167 1 + v942 r_2168 1 + v942 r_2169 1 + v942 r_2254 1 + v942 r_2255 1 + v942 r_2256 1 + v942 r_2909 1 + v942 r_2910 1 + v942 r_3021 1 + v942 r_3022 1 + v942 r_3023 1 + v943 r_105 1 + v943 r_385 1 + v943 r_485 1 + v943 r_601 1 + v943 r_726 1 + v943 r_854 1 + v943 r_963 1 + v943 r_1235 1 + v943 r_1344 1 + v943 r_2048 1 + v943 r_2364 1 + v943 r_2365 1 + v943 r_2366 1 + v943 r_2442 1 + v943 r_2443 1 + v943 r_2444 1 + v943 r_2544 -1 + v943 r_2545 -1 + v943 r_2546 -1 + v943 r_2547 -1 + v943 r_2617 -1 + v943 r_2618 -1 + v943 r_2619 -1 + v943 r_2715 1 + v943 r_2716 1 + v943 r_2717 1 + v943 r_2718 1 + v943 r_2719 1 + v943 r_2790 1 + v943 r_2791 1 + v943 r_2792 1 + v943 r_2814 1 + v943 r_2830 1 + v944 r_105 1 + v944 r_275 1 + v944 r_1106 -1 + v944 r_1420 1 + v944 r_1844 -1 + v944 r_2167 1 + v944 r_2168 1 + v944 r_2169 1 + v944 r_2254 1 + v944 r_2255 1 + v944 r_2256 1 + v945 r_105 1 + v945 r_292 1 + v945 r_1123 -1 + v945 r_1421 1 + v945 r_1852 -1 + v945 r_2167 1 + v945 r_2168 1 + v945 r_2169 1 + v945 r_2254 1 + v945 r_2255 1 + v945 r_2256 1 + v945 r_3021 1 + v945 r_3022 1 + v945 r_3023 1 + v946 r_105 1 + v946 r_2012 -1 + v946 r_2027 1 + v946 r_2033 1 + v946 r_2715 1 + v946 r_2716 1 + v946 r_2717 1 + v946 r_2718 1 + v946 r_2719 1 + v946 r_2790 1 + v946 r_2791 1 + v946 r_2792 1 + v946 r_2822 1 + v946 r_2830 1 + v947 r_106 1 + v947 r_156 1 + v947 r_1007 -1 + v947 r_1414 1 + v947 r_1794 -1 + v947 r_2168 1 + v947 r_2169 1 + v947 r_2170 1 + v948 r_106 1 + v948 r_188 1 + v948 r_1038 -1 + v948 r_1416 1 + v948 r_1810 -1 + v948 r_2168 1 + v948 r_2169 1 + v948 r_2170 1 + v949 r_106 1 + v949 r_206 1 + v949 r_1055 -1 + v949 r_1417 1 + v949 r_1819 -1 + v949 r_2168 1 + v949 r_2169 1 + v949 r_2170 1 + v950 r_106 1 + v950 r_224 1 + v950 r_1073 -1 + v950 r_1418 1 + v950 r_1828 -1 + v950 r_2168 1 + v950 r_2169 1 + v950 r_2170 1 + v951 r_106 1 + v951 r_242 1 + v951 r_1091 -1 + v951 r_1419 1 + v951 r_1837 -1 + v951 r_2168 1 + v951 r_2169 1 + v951 r_2170 1 + v951 r_2910 1 + v951 r_2911 1 + v951 r_3022 1 + v951 r_3023 1 + v951 r_3024 1 + v952 r_106 1 + v952 r_386 1 + v952 r_602 1 + v952 r_727 1 + v952 r_855 1 + v952 r_964 1 + v952 r_1236 1 + v952 r_1345 1 + v952 r_2049 1 + v952 r_2365 1 + v952 r_2366 1 + v952 r_2367 1 + v952 r_2545 -1 + v952 r_2546 -1 + v952 r_2547 -1 + v952 r_2548 -1 + v952 r_2716 1 + v952 r_2717 1 + v952 r_2718 1 + v952 r_2719 1 + v952 r_2720 1 + v953 r_106 1 + v953 r_276 1 + v953 r_1107 -1 + v953 r_1420 1 + v953 r_1845 -1 + v953 r_2168 1 + v953 r_2169 1 + v953 r_2170 1 + v954 r_106 1 + v954 r_293 1 + v954 r_1124 -1 + v954 r_1421 1 + v954 r_1853 -1 + v954 r_2168 1 + v954 r_2169 1 + v954 r_2170 1 + v954 r_3022 1 + v954 r_3023 1 + v954 r_3024 1 + v955 r_107 1 + v955 r_157 1 + v955 r_1008 -1 + v955 r_1414 1 + v955 r_2169 1 + v955 r_2170 1 + v955 r_2171 1 + v955 r_2255 1 + v955 r_2256 1 + v955 r_2257 1 + v956 r_107 1 + v956 r_174 1 + v956 r_1025 -1 + v956 r_1415 1 + v956 r_1526 1 + v956 r_2169 1 + v956 r_2170 1 + v956 r_2171 1 + v956 r_2255 1 + v956 r_2256 1 + v956 r_2257 1 + v956 r_2911 1 + v956 r_2912 1 + v956 r_3023 1 + v956 r_3024 1 + v956 r_3025 1 + v957 r_107 1 + v957 r_189 1 + v957 r_1039 -1 + v957 r_1416 1 + v957 r_2169 1 + v957 r_2170 1 + v957 r_2171 1 + v957 r_2255 1 + v957 r_2256 1 + v957 r_2257 1 + v958 r_107 1 + v958 r_207 1 + v958 r_1056 -1 + v958 r_1417 1 + v958 r_2169 1 + v958 r_2170 1 + v958 r_2171 1 + v958 r_2255 1 + v958 r_2256 1 + v958 r_2257 1 + v959 r_107 1 + v959 r_225 1 + v959 r_1074 -1 + v959 r_1418 1 + v959 r_1708 1 + v959 r_2169 1 + v959 r_2170 1 + v959 r_2171 1 + v959 r_2255 1 + v959 r_2256 1 + v959 r_2257 1 + v960 r_107 1 + v960 r_243 1 + v960 r_1092 -1 + v960 r_1419 1 + v960 r_1765 1 + v960 r_2169 1 + v960 r_2170 1 + v960 r_2171 1 + v960 r_2255 1 + v960 r_2256 1 + v960 r_2257 1 + v960 r_2911 1 + v960 r_2912 1 + v960 r_3023 1 + v960 r_3024 1 + v960 r_3025 1 + v961 r_107 1 + v961 r_387 1 + v961 r_486 1 + v961 r_603 1 + v961 r_728 1 + v961 r_856 1 + v961 r_965 1 + v961 r_1237 1 + v961 r_2050 1 + v961 r_2366 1 + v961 r_2367 1 + v961 r_2368 1 + v961 r_2443 1 + v961 r_2444 1 + v961 r_2445 1 + v961 r_2546 -1 + v961 r_2547 -1 + v961 r_2548 -1 + v961 r_2549 -1 + v961 r_2617 -1 + v961 r_2618 -1 + v961 r_2619 -1 + v961 r_2620 -1 + v961 r_2717 1 + v961 r_2718 1 + v961 r_2719 1 + v961 r_2720 1 + v961 r_2721 1 + v961 r_2790 1 + v961 r_2791 1 + v961 r_2792 1 + v961 r_2793 1 + v961 r_2814 1 + v961 r_2830 1 + v962 r_107 1 + v962 r_277 1 + v962 r_1108 -1 + v962 r_1420 1 + v962 r_1906 1 + v962 r_2169 1 + v962 r_2170 1 + v962 r_2171 1 + v962 r_2255 1 + v962 r_2256 1 + v962 r_2257 1 + v963 r_108 1 + v963 r_158 1 + v963 r_1009 -1 + v963 r_1414 1 + v963 r_1475 1 + v963 r_2170 1 + v963 r_2171 1 + v963 r_2172 1 + v964 r_108 1 + v964 r_175 1 + v964 r_1026 -1 + v964 r_1415 1 + v964 r_1527 1 + v964 r_2170 1 + v964 r_2171 1 + v964 r_2172 1 + v964 r_2912 1 + v964 r_2913 1 + v964 r_3024 1 + v964 r_3025 1 + v964 r_3026 1 + v965 r_108 1 + v965 r_190 1 + v965 r_1040 -1 + v965 r_1416 1 + v965 r_1583 1 + v965 r_2170 1 + v965 r_2171 1 + v965 r_2172 1 + v966 r_108 1 + v966 r_208 1 + v966 r_1057 -1 + v966 r_1417 1 + v966 r_1643 1 + v966 r_2170 1 + v966 r_2171 1 + v966 r_2172 1 + v967 r_108 1 + v967 r_226 1 + v967 r_1075 -1 + v967 r_1418 1 + v967 r_1709 1 + v967 r_2170 1 + v967 r_2171 1 + v967 r_2172 1 + v968 r_108 1 + v968 r_244 1 + v968 r_1093 -1 + v968 r_1419 1 + v968 r_1766 1 + v968 r_2170 1 + v968 r_2171 1 + v968 r_2172 1 + v968 r_2912 1 + v968 r_2913 1 + v968 r_3024 1 + v968 r_3025 1 + v968 r_3026 1 + v969 r_108 1 + v969 r_388 1 + v969 r_487 1 + v969 r_604 1 + v969 r_729 1 + v969 r_857 1 + v969 r_966 1 + v969 r_1238 1 + v969 r_1346 1 + v969 r_2051 1 + v969 r_2367 1 + v969 r_2368 1 + v969 r_2369 1 + v969 r_2547 -1 + v969 r_2548 -1 + v969 r_2549 -1 + v969 r_2550 -1 + v969 r_2718 1 + v969 r_2719 1 + v969 r_2720 1 + v969 r_2721 1 + v969 r_2722 1 + v970 r_108 1 + v970 r_278 1 + v970 r_1109 -1 + v970 r_1420 1 + v970 r_1907 1 + v970 r_2170 1 + v970 r_2171 1 + v970 r_2172 1 + v971 r_108 1 + v971 r_294 1 + v971 r_1125 -1 + v971 r_1421 1 + v971 r_1961 1 + v971 r_2170 1 + v971 r_2171 1 + v971 r_2172 1 + v971 r_3024 1 + v971 r_3025 1 + v971 r_3026 1 + v972 r_108 1 + v972 r_2008 1 + v972 r_2027 1 + v972 r_2034 1 + v972 r_2718 1 + v972 r_2719 1 + v972 r_2720 1 + v972 r_2721 1 + v972 r_2722 1 + v973 r_109 1 + v973 r_159 1 + v973 r_1010 -1 + v973 r_1414 1 + v973 r_1795 -1 + v973 r_2171 1 + v973 r_2172 1 + v973 r_2173 1 + v973 r_2256 1 + v973 r_2257 1 + v973 r_2258 1 + v974 r_109 1 + v974 r_176 1 + v974 r_1027 -1 + v974 r_1415 1 + v974 r_1803 -1 + v974 r_2171 1 + v974 r_2172 1 + v974 r_2173 1 + v974 r_2256 1 + v974 r_2257 1 + v974 r_2258 1 + v974 r_2913 1 + v974 r_2914 1 + v974 r_3025 1 + v974 r_3026 1 + v974 r_3027 1 + v975 r_109 1 + v975 r_191 1 + v975 r_1041 -1 + v975 r_1416 1 + v975 r_1811 -1 + v975 r_2171 1 + v975 r_2172 1 + v975 r_2173 1 + v975 r_2256 1 + v975 r_2257 1 + v975 r_2258 1 + v976 r_109 1 + v976 r_209 1 + v976 r_1058 -1 + v976 r_1417 1 + v976 r_1820 -1 + v976 r_2171 1 + v976 r_2172 1 + v976 r_2173 1 + v976 r_2256 1 + v976 r_2257 1 + v976 r_2258 1 + v977 r_109 1 + v977 r_227 1 + v977 r_1076 -1 + v977 r_1418 1 + v977 r_1829 -1 + v977 r_2171 1 + v977 r_2172 1 + v977 r_2173 1 + v977 r_2256 1 + v977 r_2257 1 + v977 r_2258 1 + v978 r_109 1 + v978 r_245 1 + v978 r_1094 -1 + v978 r_1419 1 + v978 r_1838 -1 + v978 r_2171 1 + v978 r_2172 1 + v978 r_2173 1 + v978 r_2256 1 + v978 r_2257 1 + v978 r_2258 1 + v978 r_2913 1 + v978 r_2914 1 + v978 r_3025 1 + v978 r_3026 1 + v978 r_3027 1 + v979 r_109 1 + v979 r_389 1 + v979 r_488 1 + v979 r_605 1 + v979 r_730 1 + v979 r_858 1 + v979 r_967 1 + v979 r_1239 1 + v979 r_2052 1 + v979 r_2368 1 + v979 r_2369 1 + v979 r_2370 1 + v979 r_2444 1 + v979 r_2445 1 + v979 r_2446 1 + v979 r_2548 -1 + v979 r_2549 -1 + v979 r_2550 -1 + v979 r_2551 -1 + v979 r_2618 -1 + v979 r_2619 -1 + v979 r_2620 -1 + v979 r_2621 -1 + v979 r_2719 1 + v979 r_2720 1 + v979 r_2721 1 + v979 r_2722 1 + v979 r_2723 1 + v979 r_2791 1 + v979 r_2792 1 + v979 r_2793 1 + v979 r_2794 1 + v979 r_2814 1 + v979 r_2830 1 + v980 r_109 1 + v980 r_279 1 + v980 r_1110 -1 + v980 r_1420 1 + v980 r_1846 -1 + v980 r_2171 1 + v980 r_2172 1 + v980 r_2173 1 + v980 r_2256 1 + v980 r_2257 1 + v980 r_2258 1 + v981 r_109 1 + v981 r_295 1 + v981 r_1421 1 + v981 r_1854 -1 + v981 r_2171 1 + v981 r_2172 1 + v981 r_2173 1 + v981 r_2256 1 + v981 r_2257 1 + v981 r_2258 1 + v981 r_3025 1 + v981 r_3026 1 + v981 r_3027 1 + v982 r_109 1 + v982 r_2013 -1 + v982 r_2027 1 + v982 r_2035 1 + v982 r_2719 1 + v982 r_2720 1 + v982 r_2721 1 + v982 r_2722 1 + v982 r_2723 1 + v982 r_2791 1 + v982 r_2792 1 + v982 r_2793 1 + v982 r_2794 1 + v982 r_2822 1 + v982 r_2830 1 + v983 r_110 1 + v983 r_160 1 + v983 r_1011 -1 + v983 r_1414 1 + v983 r_1796 -1 + v983 r_2172 1 + v983 r_2173 1 + v983 r_2174 1 + v984 r_110 1 + v984 r_192 1 + v984 r_1042 -1 + v984 r_1416 1 + v984 r_1812 -1 + v984 r_2172 1 + v984 r_2173 1 + v984 r_2174 1 + v985 r_110 1 + v985 r_210 1 + v985 r_1059 -1 + v985 r_1417 1 + v985 r_1821 -1 + v985 r_2172 1 + v985 r_2173 1 + v985 r_2174 1 + v986 r_110 1 + v986 r_228 1 + v986 r_1077 -1 + v986 r_1418 1 + v986 r_1830 -1 + v986 r_2172 1 + v986 r_2173 1 + v986 r_2174 1 + v987 r_110 1 + v987 r_390 1 + v987 r_606 1 + v987 r_731 1 + v987 r_859 1 + v987 r_1240 1 + v987 r_1347 1 + v987 r_2053 1 + v987 r_2369 1 + v987 r_2370 1 + v987 r_2371 1 + v987 r_2549 -1 + v987 r_2550 -1 + v987 r_2551 -1 + v987 r_2552 -1 + v987 r_2720 1 + v987 r_2721 1 + v987 r_2722 1 + v987 r_2723 1 + v987 r_2724 1 + v988 r_110 1 + v988 r_280 1 + v988 r_1111 -1 + v988 r_1420 1 + v988 r_1847 -1 + v988 r_2172 1 + v988 r_2173 1 + v988 r_2174 1 + v989 r_111 1 + v989 r_161 1 + v989 r_1012 -1 + v989 r_1414 1 + v989 r_1476 1 + v989 r_2173 1 + v989 r_2174 1 + v989 r_2175 1 + v989 r_2257 1 + v989 r_2258 1 + v989 r_2259 1 + v990 r_111 1 + v990 r_177 1 + v990 r_1028 -1 + v990 r_1415 1 + v990 r_1528 1 + v990 r_2173 1 + v990 r_2174 1 + v990 r_2175 1 + v990 r_2257 1 + v990 r_2258 1 + v990 r_2259 1 + v990 r_2915 1 + v990 r_2916 1 + v990 r_3027 1 + v990 r_3028 1 + v990 r_3029 1 + v991 r_111 1 + v991 r_193 1 + v991 r_1043 -1 + v991 r_1416 1 + v991 r_1584 1 + v991 r_2173 1 + v991 r_2174 1 + v991 r_2175 1 + v991 r_2257 1 + v991 r_2258 1 + v991 r_2259 1 + v992 r_111 1 + v992 r_211 1 + v992 r_1060 -1 + v992 r_1417 1 + v992 r_1644 1 + v992 r_2173 1 + v992 r_2174 1 + v992 r_2175 1 + v992 r_2257 1 + v992 r_2258 1 + v992 r_2259 1 + v993 r_111 1 + v993 r_229 1 + v993 r_1078 -1 + v993 r_1418 1 + v993 r_1710 1 + v993 r_2173 1 + v993 r_2174 1 + v993 r_2175 1 + v993 r_2257 1 + v993 r_2258 1 + v993 r_2259 1 + v994 r_111 1 + v994 r_246 1 + v994 r_1095 -1 + v994 r_1419 1 + v994 r_1767 1 + v994 r_2173 1 + v994 r_2174 1 + v994 r_2175 1 + v994 r_2257 1 + v994 r_2258 1 + v994 r_2259 1 + v994 r_2915 1 + v994 r_2916 1 + v994 r_3027 1 + v994 r_3028 1 + v994 r_3029 1 + v995 r_111 1 + v995 r_391 1 + v995 r_489 1 + v995 r_607 1 + v995 r_732 1 + v995 r_860 1 + v995 r_968 1 + v995 r_1241 1 + v995 r_1348 1 + v995 r_2054 1 + v995 r_2370 1 + v995 r_2371 1 + v995 r_2372 1 + v995 r_2445 1 + v995 r_2446 1 + v995 r_2447 1 + v995 r_2550 -1 + v995 r_2551 -1 + v995 r_2552 -1 + v995 r_2553 -1 + v995 r_2619 -1 + v995 r_2620 -1 + v995 r_2621 -1 + v995 r_2622 -1 + v995 r_2721 1 + v995 r_2722 1 + v995 r_2723 1 + v995 r_2724 1 + v995 r_2725 1 + v995 r_2792 1 + v995 r_2793 1 + v995 r_2794 1 + v995 r_2795 1 + v995 r_2814 1 + v996 r_111 1 + v996 r_281 1 + v996 r_1112 -1 + v996 r_1420 1 + v996 r_1908 1 + v996 r_2173 1 + v996 r_2174 1 + v996 r_2175 1 + v996 r_2257 1 + v996 r_2258 1 + v996 r_2259 1 + v997 r_111 1 + v997 r_296 1 + v997 r_1126 -1 + v997 r_1421 1 + v997 r_1962 1 + v997 r_2173 1 + v997 r_2174 1 + v997 r_2175 1 + v997 r_2257 1 + v997 r_2258 1 + v997 r_2259 1 + v997 r_3027 1 + v997 r_3028 1 + v997 r_3029 1 + v998 r_111 1 + v998 r_2009 1 + v998 r_2027 1 + v998 r_2037 1 + v998 r_2721 1 + v998 r_2722 1 + v998 r_2723 1 + v998 r_2724 1 + v998 r_2725 1 + v998 r_2792 1 + v998 r_2793 1 + v998 r_2794 1 + v998 r_2795 1 + v998 r_2822 1 + v999 r_112 1 + v999 r_162 1 + v999 r_1013 -1 + v999 r_1414 1 + v999 r_1477 1 + v999 r_2174 1 + v999 r_2175 1 + v999 r_2176 1 + MARK0001 'MARKER' 'INTEND' +RHS + RHS r_1 1 + RHS r_2 1 + RHS r_3 1 + RHS r_4 1 + RHS r_5 1 + RHS r_6 1 + RHS r_7 1 + RHS r_8 1 + RHS r_9 1 + RHS r_10 1 + RHS r_11 1 + RHS r_12 1 + RHS r_13 1 + RHS r_14 1 + RHS r_15 1 + RHS r_16 1 + RHS r_17 1 + RHS r_18 1 + RHS r_19 1 + RHS r_20 1 + RHS r_21 1 + RHS r_22 1 + RHS r_23 1 + RHS r_24 1 + RHS r_25 1 + RHS r_26 1 + RHS r_27 1 + RHS r_28 1 + RHS r_29 1 + RHS r_30 1 + RHS r_31 1 + RHS r_32 1 + RHS r_33 1 + RHS r_34 1 + RHS r_35 1 + RHS r_36 1 + RHS r_37 1 + RHS r_38 1 + RHS r_39 1 + RHS r_40 1 + RHS r_41 1 + RHS r_42 1 + RHS r_43 1 + RHS r_44 1 + RHS r_45 1 + RHS r_46 1 + RHS r_47 1 + RHS r_48 1 + RHS r_49 1 + RHS r_50 1 + RHS r_51 1 + RHS r_52 1 + RHS r_53 1 + RHS r_54 1 + RHS r_55 1 + RHS r_56 1 + RHS r_57 1 + RHS r_58 1 + RHS r_59 1 + RHS r_60 1 + RHS r_61 1 + RHS r_62 1 + RHS r_63 1 + RHS r_64 1 + RHS r_65 1 + RHS r_66 1 + RHS r_67 1 + RHS r_68 1 + RHS r_69 1 + RHS r_70 1 + RHS r_71 1 + RHS r_72 1 + RHS r_73 1 + RHS r_74 1 + RHS r_75 1 + RHS r_76 1 + RHS r_77 1 + RHS r_78 1 + RHS r_79 1 + RHS r_80 1 + RHS r_81 1 + RHS r_82 1 + RHS r_83 1 + RHS r_84 1 + RHS r_85 1 + RHS r_86 1 + RHS r_87 1 + RHS r_88 1 + RHS r_89 1 + RHS r_90 1 + RHS r_91 1 + RHS r_92 1 + RHS r_93 1 + RHS r_94 1 + RHS r_95 1 + RHS r_96 1 + RHS r_97 1 + RHS r_98 1 + RHS r_99 1 + RHS r_100 1 + RHS r_101 1 + RHS r_102 1 + RHS r_103 1 + RHS r_104 1 + RHS r_105 1 + RHS r_106 1 + RHS r_107 1 + RHS r_108 1 + RHS r_109 1 + RHS r_110 1 + RHS r_111 1 + RHS r_112 1 + RHS r_113 1 + RHS r_114 1 + RHS r_115 1 + RHS r_116 1 + RHS r_117 1 + RHS r_118 1 + RHS r_119 1 + RHS r_120 1 + RHS r_121 1 + RHS r_122 1 + RHS r_123 1 + RHS r_124 1 + RHS r_125 1 + RHS r_126 1 + RHS r_127 1 + RHS r_128 1 + RHS r_129 1 + RHS r_130 1 + RHS r_131 1 + RHS r_132 1 + RHS r_133 1 + RHS r_134 1 + RHS r_135 1 + RHS r_136 1 + RHS r_137 1 + RHS r_138 1 + RHS r_139 1 + RHS r_140 1 + RHS r_141 1 + RHS r_142 1 + RHS r_143 1 + RHS r_144 1 + RHS r_145 1 + RHS r_146 1 + RHS r_147 1 + RHS r_148 1 + RHS r_149 1 + RHS r_150 1 + RHS r_151 1 + RHS r_152 1 + RHS r_153 1 + RHS r_154 1 + RHS r_155 1 + RHS r_156 1 + RHS r_157 1 + RHS r_158 1 + RHS r_159 1 + RHS r_160 1 + RHS r_161 1 + RHS r_162 1 + RHS r_163 1 + RHS r_164 1 + RHS r_165 1 + RHS r_166 1 + RHS r_167 1 + RHS r_168 1 + RHS r_169 1 + RHS r_170 1 + RHS r_171 1 + RHS r_172 1 + RHS r_173 1 + RHS r_174 1 + RHS r_175 1 + RHS r_176 1 + RHS r_177 1 + RHS r_178 1 + RHS r_179 1 + RHS r_180 1 + RHS r_181 1 + RHS r_182 1 + RHS r_183 1 + RHS r_184 1 + RHS r_185 1 + RHS r_186 1 + RHS r_187 1 + RHS r_188 1 + RHS r_189 1 + RHS r_190 1 + RHS r_191 1 + RHS r_192 1 + RHS r_193 1 + RHS r_194 1 + RHS r_195 1 + RHS r_196 1 + RHS r_197 1 + RHS r_198 1 + RHS r_199 1 + RHS r_200 1 + RHS r_201 1 + RHS r_202 1 + RHS r_203 1 + RHS r_204 1 + RHS r_205 1 + RHS r_206 1 + RHS r_207 1 + RHS r_208 1 + RHS r_209 1 + RHS r_210 1 + RHS r_211 1 + RHS r_212 1 + RHS r_213 1 + RHS r_214 1 + RHS r_215 1 + RHS r_216 1 + RHS r_217 1 + RHS r_218 1 + RHS r_219 1 + RHS r_220 1 + RHS r_221 1 + RHS r_222 1 + RHS r_223 1 + RHS r_224 1 + RHS r_225 1 + RHS r_226 1 + RHS r_227 1 + RHS r_228 1 + RHS r_229 1 + RHS r_230 1 + RHS r_231 1 + RHS r_232 1 + RHS r_233 1 + RHS r_234 1 + RHS r_235 1 + RHS r_236 1 + RHS r_237 1 + RHS r_238 1 + RHS r_239 1 + RHS r_240 1 + RHS r_241 1 + RHS r_242 1 + RHS r_243 1 + RHS r_244 1 + RHS r_245 1 + RHS r_246 1 + RHS r_247 1 + RHS r_248 1 + RHS r_249 1 + RHS r_250 1 + RHS r_251 1 + RHS r_252 1 + RHS r_253 1 + RHS r_254 1 + RHS r_255 1 + RHS r_256 1 + RHS r_257 1 + RHS r_258 1 + RHS r_259 1 + RHS r_260 1 + RHS r_261 1 + RHS r_262 1 + RHS r_263 1 + RHS r_264 1 + RHS r_265 1 + RHS r_266 1 + RHS r_267 1 + RHS r_268 1 + RHS r_269 1 + RHS r_270 1 + RHS r_271 1 + RHS r_272 1 + RHS r_273 1 + RHS r_274 1 + RHS r_275 1 + RHS r_276 1 + RHS r_277 1 + RHS r_278 1 + RHS r_279 1 + RHS r_280 1 + RHS r_281 1 + RHS r_282 1 + RHS r_283 1 + RHS r_284 1 + RHS r_285 1 + RHS r_286 1 + RHS r_287 1 + RHS r_288 1 + RHS r_289 1 + RHS r_290 1 + RHS r_291 1 + RHS r_292 1 + RHS r_293 1 + RHS r_294 1 + RHS r_295 1 + RHS r_296 1 + RHS r_297 1 + RHS r_298 1 + RHS r_299 1 + RHS r_300 1 + RHS r_301 1 + RHS r_302 -0 + RHS r_303 -0 + RHS r_304 -0 + RHS r_305 -0 + RHS r_306 -0 + RHS r_307 -0 + RHS r_308 -0 + RHS r_309 -0 + RHS r_310 -0 + RHS r_311 -0 + RHS r_312 -0 + RHS r_313 -0 + RHS r_314 -0 + RHS r_315 -0 + RHS r_316 -0 + RHS r_317 -0 + RHS r_318 -0 + RHS r_319 -0 + RHS r_320 -0 + RHS r_321 -0 + RHS r_322 -0 + RHS r_323 -0 + RHS r_324 -0 + RHS r_325 -0 + RHS r_326 -0 + RHS r_327 -0 + RHS r_328 -0 + RHS r_329 -0 + RHS r_330 -0 + RHS r_331 -0 + RHS r_332 -0 + RHS r_333 -0 + RHS r_334 -0 + RHS r_335 -0 + RHS r_336 -0 + RHS r_337 -0 + RHS r_338 -0 + RHS r_339 -0 + RHS r_340 -0 + RHS r_341 -0 + RHS r_342 -0 + RHS r_343 -0 + RHS r_344 -0 + RHS r_345 -0 + RHS r_346 -0 + RHS r_347 -0 + RHS r_348 -0 + RHS r_349 -0 + RHS r_350 -0 + RHS r_351 -0 + RHS r_352 -0 + RHS r_353 -0 + RHS r_354 -0 + RHS r_355 -0 + RHS r_356 -0 + RHS r_357 -0 + RHS r_358 -0 + RHS r_359 -0 + RHS r_360 -0 + RHS r_361 -0 + RHS r_362 -0 + RHS r_363 -0 + RHS r_364 -0 + RHS r_365 -0 + RHS r_366 -0 + RHS r_367 -0 + RHS r_368 -0 + RHS r_369 -0 + RHS r_370 -0 + RHS r_371 -0 + RHS r_372 -0 + RHS r_373 -0 + RHS r_374 -0 + RHS r_375 -0 + RHS r_376 -0 + RHS r_377 -0 + RHS r_378 -0 + RHS r_379 -0 + RHS r_380 -0 + RHS r_381 -0 + RHS r_382 -0 + RHS r_383 -0 + RHS r_384 -0 + RHS r_385 -0 + RHS r_386 -0 + RHS r_387 -0 + RHS r_388 -0 + RHS r_389 -0 + RHS r_390 -0 + RHS r_391 -0 + RHS r_392 -0 + RHS r_393 -0 + RHS r_394 -0 + RHS r_395 -0 + RHS r_396 -0 + RHS r_397 -0 + RHS r_398 -0 + RHS r_399 -0 + RHS r_400 -0 + RHS r_401 -0 + RHS r_402 -0 + RHS r_403 -0 + RHS r_404 -0 + RHS r_405 -0 + RHS r_406 -0 + RHS r_407 -0 + RHS r_408 -0 + RHS r_409 -0 + RHS r_410 -0 + RHS r_411 -0 + RHS r_412 -0 + RHS r_413 -0 + RHS r_414 -0 + RHS r_415 -0 + RHS r_416 -0 + RHS r_417 -0 + RHS r_418 -0 + RHS r_419 -0 + RHS r_420 -0 + RHS r_421 -0 + RHS r_422 -0 + RHS r_423 -0 + RHS r_424 -0 + RHS r_425 -0 + RHS r_426 -0 + RHS r_427 -0 + RHS r_428 -0 + RHS r_429 -0 + RHS r_430 -0 + RHS r_431 -0 + RHS r_432 -0 + RHS r_433 -0 + RHS r_434 -0 + RHS r_435 -0 + RHS r_436 -0 + RHS r_437 -0 + RHS r_438 -0 + RHS r_439 -0 + RHS r_440 -0 + RHS r_441 -0 + RHS r_442 -0 + RHS r_443 -0 + RHS r_444 -0 + RHS r_445 -0 + RHS r_446 -0 + RHS r_447 -0 + RHS r_448 -0 + RHS r_449 -0 + RHS r_450 -0 + RHS r_451 -0 + RHS r_452 -0 + RHS r_453 -0 + RHS r_454 -0 + RHS r_455 -0 + RHS r_456 -0 + RHS r_457 -0 + RHS r_458 -0 + RHS r_459 -0 + RHS r_460 -0 + RHS r_461 -0 + RHS r_462 -0 + RHS r_463 -0 + RHS r_464 -0 + RHS r_465 -0 + RHS r_466 -0 + RHS r_467 -0 + RHS r_468 -0 + RHS r_469 -0 + RHS r_470 -0 + RHS r_471 -0 + RHS r_472 -0 + RHS r_473 -0 + RHS r_474 -0 + RHS r_475 -0 + RHS r_476 -0 + RHS r_477 -0 + RHS r_478 -0 + RHS r_479 -0 + RHS r_480 -0 + RHS r_481 -0 + RHS r_482 -0 + RHS r_483 -0 + RHS r_484 -0 + RHS r_485 -0 + RHS r_486 -0 + RHS r_487 -0 + RHS r_488 -0 + RHS r_489 -0 + RHS r_490 -0 + RHS r_491 -0 + RHS r_492 -0 + RHS r_493 -0 + RHS r_494 -0 + RHS r_495 -0 + RHS r_496 -0 + RHS r_497 -0 + RHS r_498 -0 + RHS r_499 -0 + RHS r_500 -0 + RHS r_501 -0 + RHS r_502 -0 + RHS r_503 -0 + RHS r_504 -0 + RHS r_505 -0 + RHS r_506 -0 + RHS r_507 -0 + RHS r_508 -0 + RHS r_509 -0 + RHS r_510 -0 + RHS r_511 -0 + RHS r_512 -0 + RHS r_513 -0 + RHS r_514 -0 + RHS r_515 -0 + RHS r_516 -0 + RHS r_517 -0 + RHS r_518 -0 + RHS r_519 -0 + RHS r_520 -0 + RHS r_521 -0 + RHS r_522 -0 + RHS r_523 -0 + RHS r_524 -0 + RHS r_525 -0 + RHS r_526 -0 + RHS r_527 -0 + RHS r_528 -0 + RHS r_529 -0 + RHS r_530 -0 + RHS r_531 -0 + RHS r_532 -0 + RHS r_533 -0 + RHS r_534 -0 + RHS r_535 -0 + RHS r_536 -0 + RHS r_537 -0 + RHS r_538 -0 + RHS r_539 -0 + RHS r_540 -0 + RHS r_541 -0 + RHS r_542 -0 + RHS r_543 -0 + RHS r_544 -0 + RHS r_545 -0 + RHS r_546 -0 + RHS r_547 -0 + RHS r_548 -0 + RHS r_549 -0 + RHS r_550 -0 + RHS r_551 -0 + RHS r_552 -0 + RHS r_553 -0 + RHS r_554 -0 + RHS r_555 -0 + RHS r_556 -0 + RHS r_557 -0 + RHS r_558 -0 + RHS r_559 -0 + RHS r_560 -0 + RHS r_561 -0 + RHS r_562 -0 + RHS r_563 -0 + RHS r_564 -0 + RHS r_565 -0 + RHS r_566 -0 + RHS r_567 -0 + RHS r_568 -0 + RHS r_569 -0 + RHS r_570 -0 + RHS r_571 -0 + RHS r_572 -0 + RHS r_573 -0 + RHS r_574 -0 + RHS r_575 -0 + RHS r_576 -0 + RHS r_577 -0 + RHS r_578 -0 + RHS r_579 -0 + RHS r_580 -0 + RHS r_581 -0 + RHS r_582 -0 + RHS r_583 -0 + RHS r_584 -0 + RHS r_585 -0 + RHS r_586 -0 + RHS r_587 -0 + RHS r_588 -0 + RHS r_589 -0 + RHS r_590 -0 + RHS r_591 -0 + RHS r_592 -0 + RHS r_593 -0 + RHS r_594 -0 + RHS r_595 -0 + RHS r_596 -0 + RHS r_597 -0 + RHS r_598 -0 + RHS r_599 -0 + RHS r_600 -0 + RHS r_601 -0 + RHS r_602 -0 + RHS r_603 -0 + RHS r_604 -0 + RHS r_605 -0 + RHS r_606 -0 + RHS r_607 -0 + RHS r_608 -0 + RHS r_609 -0 + RHS r_610 -0 + RHS r_611 -0 + RHS r_612 -0 + RHS r_613 -0 + RHS r_614 -0 + RHS r_615 -0 + RHS r_616 -0 + RHS r_617 -0 + RHS r_618 -0 + RHS r_619 -0 + RHS r_620 -0 + RHS r_621 -0 + RHS r_622 -0 + RHS r_623 -0 + RHS r_624 -0 + RHS r_625 -0 + RHS r_626 -0 + RHS r_627 -0 + RHS r_628 -0 + RHS r_629 -0 + RHS r_630 -0 + RHS r_631 -0 + RHS r_632 -0 + RHS r_633 -0 + RHS r_634 -0 + RHS r_635 -0 + RHS r_636 -0 + RHS r_637 -0 + RHS r_638 -0 + RHS r_639 -0 + RHS r_640 -0 + RHS r_641 -0 + RHS r_642 -0 + RHS r_643 -0 + RHS r_644 -0 + RHS r_645 -0 + RHS r_646 -0 + RHS r_647 -0 + RHS r_648 -0 + RHS r_649 -0 + RHS r_650 -0 + RHS r_651 -0 + RHS r_652 -0 + RHS r_653 -0 + RHS r_654 -0 + RHS r_655 -0 + RHS r_656 -0 + RHS r_657 -0 + RHS r_658 -0 + RHS r_659 -0 + RHS r_660 -0 + RHS r_661 -0 + RHS r_662 -0 + RHS r_663 -0 + RHS r_664 -0 + RHS r_665 -0 + RHS r_666 -0 + RHS r_667 -0 + RHS r_668 -0 + RHS r_669 -0 + RHS r_670 -0 + RHS r_671 -0 + RHS r_672 -0 + RHS r_673 -0 + RHS r_674 -0 + RHS r_675 -0 + RHS r_676 -0 + RHS r_677 -0 + RHS r_678 -0 + RHS r_679 -0 + RHS r_680 -0 + RHS r_681 -0 + RHS r_682 -0 + RHS r_683 -0 + RHS r_684 -0 + RHS r_685 -0 + RHS r_686 -0 + RHS r_687 -0 + RHS r_688 -0 + RHS r_689 -0 + RHS r_690 -0 + RHS r_691 -0 + RHS r_692 -0 + RHS r_693 -0 + RHS r_694 -0 + RHS r_695 -0 + RHS r_696 -0 + RHS r_697 -0 + RHS r_698 -0 + RHS r_699 -0 + RHS r_700 -0 + RHS r_701 -0 + RHS r_702 -0 + RHS r_703 -0 + RHS r_704 -0 + RHS r_705 -0 + RHS r_706 -0 + RHS r_707 -0 + RHS r_708 -0 + RHS r_709 -0 + RHS r_710 -0 + RHS r_711 -0 + RHS r_712 -0 + RHS r_713 -0 + RHS r_714 -0 + RHS r_715 -0 + RHS r_716 -0 + RHS r_717 -0 + RHS r_718 -0 + RHS r_719 -0 + RHS r_720 -0 + RHS r_721 -0 + RHS r_722 -0 + RHS r_723 -0 + RHS r_724 -0 + RHS r_725 -0 + RHS r_726 -0 + RHS r_727 -0 + RHS r_728 -0 + RHS r_729 -0 + RHS r_730 -0 + RHS r_731 -0 + RHS r_732 -0 + RHS r_733 -0 + RHS r_734 -0 + RHS r_735 -0 + RHS r_736 -0 + RHS r_737 -0 + RHS r_738 -0 + RHS r_739 -0 + RHS r_740 -0 + RHS r_741 -0 + RHS r_742 -0 + RHS r_743 -0 + RHS r_744 -0 + RHS r_745 -0 + RHS r_746 -0 + RHS r_747 -0 + RHS r_748 -0 + RHS r_749 -0 + RHS r_750 -0 + RHS r_751 -0 + RHS r_752 -0 + RHS r_753 -0 + RHS r_754 -0 + RHS r_755 -0 + RHS r_756 -0 + RHS r_757 -0 + RHS r_758 -0 + RHS r_759 -0 + RHS r_760 -0 + RHS r_761 -0 + RHS r_762 -0 + RHS r_763 -0 + RHS r_764 -0 + RHS r_765 -0 + RHS r_766 -0 + RHS r_767 -0 + RHS r_768 -0 + RHS r_769 -0 + RHS r_770 -0 + RHS r_771 -0 + RHS r_772 -0 + RHS r_773 -0 + RHS r_774 -0 + RHS r_775 -0 + RHS r_776 -0 + RHS r_777 -0 + RHS r_778 -0 + RHS r_779 -0 + RHS r_780 -0 + RHS r_781 -0 + RHS r_782 -0 + RHS r_783 -0 + RHS r_784 -0 + RHS r_785 -0 + RHS r_786 -0 + RHS r_787 -0 + RHS r_788 -0 + RHS r_789 -0 + RHS r_790 -0 + RHS r_791 -0 + RHS r_792 -0 + RHS r_793 -0 + RHS r_794 -0 + RHS r_795 -0 + RHS r_796 -0 + RHS r_797 -0 + RHS r_798 -0 + RHS r_799 -0 + RHS r_800 -0 + RHS r_801 -0 + RHS r_802 -0 + RHS r_803 -0 + RHS r_804 -0 + RHS r_805 -0 + RHS r_806 -0 + RHS r_807 -0 + RHS r_808 -0 + RHS r_809 -0 + RHS r_810 -0 + RHS r_811 -0 + RHS r_812 -0 + RHS r_813 -0 + RHS r_814 -0 + RHS r_815 -0 + RHS r_816 -0 + RHS r_817 -0 + RHS r_818 -0 + RHS r_819 -0 + RHS r_820 -0 + RHS r_821 -0 + RHS r_822 -0 + RHS r_823 -0 + RHS r_824 -0 + RHS r_825 -0 + RHS r_826 -0 + RHS r_827 -0 + RHS r_828 -0 + RHS r_829 -0 + RHS r_830 -0 + RHS r_831 -0 + RHS r_832 -0 + RHS r_833 -0 + RHS r_834 -0 + RHS r_835 -0 + RHS r_836 -0 + RHS r_837 -0 + RHS r_838 -0 + RHS r_839 -0 + RHS r_840 -0 + RHS r_841 -0 + RHS r_842 -0 + RHS r_843 -0 + RHS r_844 -0 + RHS r_845 -0 + RHS r_846 -0 + RHS r_847 -0 + RHS r_848 -0 + RHS r_849 -0 + RHS r_850 -0 + RHS r_851 -0 + RHS r_852 -0 + RHS r_853 -0 + RHS r_854 -0 + RHS r_855 -0 + RHS r_856 -0 + RHS r_857 -0 + RHS r_858 -0 + RHS r_859 -0 + RHS r_860 -0 + RHS r_861 -0 + RHS r_862 -0 + RHS r_863 -0 + RHS r_864 -0 + RHS r_865 -0 + RHS r_866 -0 + RHS r_867 -0 + RHS r_868 -0 + RHS r_869 -0 + RHS r_870 -0 + RHS r_871 -0 + RHS r_872 -0 + RHS r_873 -0 + RHS r_874 -0 + RHS r_875 -0 + RHS r_876 -0 + RHS r_877 -0 + RHS r_878 -0 + RHS r_879 -0 + RHS r_880 -0 + RHS r_881 -0 + RHS r_882 -0 + RHS r_883 -0 + RHS r_884 -0 + RHS r_885 -0 + RHS r_886 -0 + RHS r_887 -0 + RHS r_888 -0 + RHS r_889 -0 + RHS r_890 -0 + RHS r_891 -0 + RHS r_892 -0 + RHS r_893 -0 + RHS r_894 -0 + RHS r_895 -0 + RHS r_896 -0 + RHS r_897 -0 + RHS r_898 -0 + RHS r_899 -0 + RHS r_900 -0 + RHS r_901 -0 + RHS r_902 -0 + RHS r_903 -0 + RHS r_904 -0 + RHS r_905 -0 + RHS r_906 -0 + RHS r_907 -0 + RHS r_908 -0 + RHS r_909 -0 + RHS r_910 -0 + RHS r_911 -0 + RHS r_912 -0 + RHS r_913 -0 + RHS r_914 -0 + RHS r_915 -0 + RHS r_916 -0 + RHS r_917 -0 + RHS r_918 -0 + RHS r_919 -0 + RHS r_920 -0 + RHS r_921 -0 + RHS r_922 -0 + RHS r_923 -0 + RHS r_924 -0 + RHS r_925 -0 + RHS r_926 -0 + RHS r_927 -0 + RHS r_928 -0 + RHS r_929 -0 + RHS r_930 -0 + RHS r_931 -0 + RHS r_932 -0 + RHS r_933 -0 + RHS r_934 -0 + RHS r_935 -0 + RHS r_936 -0 + RHS r_937 -0 + RHS r_938 -0 + RHS r_939 -0 + RHS r_940 -0 + RHS r_941 -0 + RHS r_942 -0 + RHS r_943 -0 + RHS r_944 -0 + RHS r_945 -0 + RHS r_946 -0 + RHS r_947 -0 + RHS r_948 -0 + RHS r_949 -0 + RHS r_950 -0 + RHS r_951 -0 + RHS r_952 -0 + RHS r_953 -0 + RHS r_954 -0 + RHS r_955 -0 + RHS r_956 -0 + RHS r_957 -0 + RHS r_958 -0 + RHS r_959 -0 + RHS r_960 -0 + RHS r_961 -0 + RHS r_962 -0 + RHS r_963 -0 + RHS r_964 -0 + RHS r_965 -0 + RHS r_966 -0 + RHS r_967 -0 + RHS r_968 -0 + RHS r_969 -0 + RHS r_970 -0 + RHS r_971 -0 + RHS r_972 -0 + RHS r_973 -0 + RHS r_974 -0 + RHS r_975 -0 + RHS r_976 -0 + RHS r_977 -0 + RHS r_978 -0 + RHS r_979 -0 + RHS r_980 -0 + RHS r_981 -0 + RHS r_982 -0 + RHS r_983 -0 + RHS r_984 -0 + RHS r_985 -0 + RHS r_986 -0 + RHS r_987 -0 + RHS r_988 -0 + RHS r_989 -0 + RHS r_990 -0 + RHS r_991 -0 + RHS r_992 -0 + RHS r_993 -0 + RHS r_994 -0 + RHS r_995 -0 + RHS r_996 -0 + RHS r_997 -0 + RHS r_998 -0 + RHS r_999 -0 + RHS r_1000 -0 + RHS r_1001 -0 + RHS r_1002 -0 + RHS r_1003 -0 + RHS r_1004 -0 + RHS r_1005 -0 + RHS r_1006 -0 + RHS r_1007 -0 + RHS r_1008 -0 + RHS r_1009 -0 + RHS r_1010 -0 + RHS r_1011 -0 + RHS r_1012 -0 + RHS r_1013 -0 + RHS r_1014 -0 + RHS r_1015 -0 + RHS r_1016 -0 + RHS r_1017 -0 + RHS r_1018 -0 + RHS r_1019 -0 + RHS r_1020 -0 + RHS r_1021 -0 + RHS r_1022 -0 + RHS r_1023 -0 + RHS r_1024 -0 + RHS r_1025 -0 + RHS r_1026 -0 + RHS r_1027 -0 + RHS r_1028 -0 + RHS r_1029 -0 + RHS r_1030 -0 + RHS r_1031 -0 + RHS r_1032 -0 + RHS r_1033 -0 + RHS r_1034 -0 + RHS r_1035 -0 + RHS r_1036 -0 + RHS r_1037 -0 + RHS r_1038 -0 + RHS r_1039 -0 + RHS r_1040 -0 + RHS r_1041 -0 + RHS r_1042 -0 + RHS r_1043 -0 + RHS r_1044 -0 + RHS r_1045 -0 + RHS r_1046 -0 + RHS r_1047 -0 + RHS r_1048 -0 + RHS r_1049 -0 + RHS r_1050 -0 + RHS r_1051 -0 + RHS r_1052 -0 + RHS r_1053 -0 + RHS r_1054 -0 + RHS r_1055 -0 + RHS r_1056 -0 + RHS r_1057 -0 + RHS r_1058 -0 + RHS r_1059 -0 + RHS r_1060 -0 + RHS r_1061 -0 + RHS r_1062 -0 + RHS r_1063 -0 + RHS r_1064 -0 + RHS r_1065 -0 + RHS r_1066 -0 + RHS r_1067 -0 + RHS r_1068 -0 + RHS r_1069 -0 + RHS r_1070 -0 + RHS r_1071 -0 + RHS r_1072 -0 + RHS r_1073 -0 + RHS r_1074 -0 + RHS r_1075 -0 + RHS r_1076 -0 + RHS r_1077 -0 + RHS r_1078 -0 + RHS r_1079 -0 + RHS r_1080 -0 + RHS r_1081 -0 + RHS r_1082 -0 + RHS r_1083 -0 + RHS r_1084 -0 + RHS r_1085 -0 + RHS r_1086 -0 + RHS r_1087 -0 + RHS r_1088 -0 + RHS r_1089 -0 + RHS r_1090 -0 + RHS r_1091 -0 + RHS r_1092 -0 + RHS r_1093 -0 + RHS r_1094 -0 + RHS r_1095 -0 + RHS r_1096 -0 + RHS r_1097 -0 + RHS r_1098 -0 + RHS r_1099 -0 + RHS r_1100 -0 + RHS r_1101 -0 + RHS r_1102 -0 + RHS r_1103 -0 + RHS r_1104 -0 + RHS r_1105 -0 + RHS r_1106 -0 + RHS r_1107 -0 + RHS r_1108 -0 + RHS r_1109 -0 + RHS r_1110 -0 + RHS r_1111 -0 + RHS r_1112 -0 + RHS r_1113 -0 + RHS r_1114 -0 + RHS r_1115 -0 + RHS r_1116 -0 + RHS r_1117 -0 + RHS r_1118 -0 + RHS r_1119 -0 + RHS r_1120 -0 + RHS r_1121 -0 + RHS r_1122 -0 + RHS r_1123 -0 + RHS r_1124 -0 + RHS r_1125 -0 + RHS r_1126 -0 + RHS r_1127 -0 + RHS r_1128 -0 + RHS r_1129 -0 + RHS r_1130 -0 + RHS r_1131 -0 + RHS r_1132 -0 + RHS r_1133 -0 + RHS r_1134 -0 + RHS r_1135 -0 + RHS r_1136 -0 + RHS r_1137 -0 + RHS r_1138 -0 + RHS r_1139 -0 + RHS r_1140 -0 + RHS r_1141 -0 + RHS r_1142 -0 + RHS r_1143 -0 + RHS r_1144 -0 + RHS r_1145 -0 + RHS r_1146 -0 + RHS r_1147 -0 + RHS r_1148 -0 + RHS r_1149 -0 + RHS r_1150 -0 + RHS r_1151 -0 + RHS r_1152 -0 + RHS r_1153 -0 + RHS r_1154 -0 + RHS r_1155 -0 + RHS r_1156 -0 + RHS r_1157 -0 + RHS r_1158 -0 + RHS r_1159 -0 + RHS r_1160 -0 + RHS r_1161 -0 + RHS r_1162 -0 + RHS r_1163 -0 + RHS r_1164 -0 + RHS r_1165 -0 + RHS r_1166 -0 + RHS r_1167 -0 + RHS r_1168 -0 + RHS r_1169 -0 + RHS r_1170 -0 + RHS r_1171 -0 + RHS r_1172 -0 + RHS r_1173 -0 + RHS r_1174 -0 + RHS r_1175 -0 + RHS r_1176 -0 + RHS r_1177 -0 + RHS r_1178 -0 + RHS r_1179 -0 + RHS r_1180 -0 + RHS r_1181 -0 + RHS r_1182 -0 + RHS r_1183 -0 + RHS r_1184 -0 + RHS r_1185 -0 + RHS r_1186 -0 + RHS r_1187 -0 + RHS r_1188 -0 + RHS r_1189 -0 + RHS r_1190 -0 + RHS r_1191 -0 + RHS r_1192 -0 + RHS r_1193 -0 + RHS r_1194 -0 + RHS r_1195 -0 + RHS r_1196 -0 + RHS r_1197 -0 + RHS r_1198 -0 + RHS r_1199 -0 + RHS r_1200 -0 + RHS r_1201 -0 + RHS r_1202 -0 + RHS r_1203 -0 + RHS r_1204 -0 + RHS r_1205 -0 + RHS r_1206 -0 + RHS r_1207 -0 + RHS r_1208 -0 + RHS r_1209 -0 + RHS r_1210 -0 + RHS r_1211 -0 + RHS r_1212 -0 + RHS r_1213 -0 + RHS r_1214 -0 + RHS r_1215 -0 + RHS r_1216 -0 + RHS r_1217 -0 + RHS r_1218 -0 + RHS r_1219 -0 + RHS r_1220 -0 + RHS r_1221 -0 + RHS r_1222 -0 + RHS r_1223 -0 + RHS r_1224 -0 + RHS r_1225 -0 + RHS r_1226 -0 + RHS r_1227 -0 + RHS r_1228 -0 + RHS r_1229 -0 + RHS r_1230 -0 + RHS r_1231 -0 + RHS r_1232 -0 + RHS r_1233 -0 + RHS r_1234 -0 + RHS r_1235 -0 + RHS r_1236 -0 + RHS r_1237 -0 + RHS r_1238 -0 + RHS r_1239 -0 + RHS r_1240 -0 + RHS r_1241 -0 + RHS r_1242 -0 + RHS r_1243 -0 + RHS r_1244 -0 + RHS r_1245 -0 + RHS r_1246 -0 + RHS r_1247 -0 + RHS r_1248 -0 + RHS r_1249 -0 + RHS r_1250 -0 + RHS r_1251 -0 + RHS r_1252 -0 + RHS r_1253 -0 + RHS r_1254 -0 + RHS r_1255 -0 + RHS r_1256 -0 + RHS r_1257 -0 + RHS r_1258 -0 + RHS r_1259 -0 + RHS r_1260 -0 + RHS r_1261 -0 + RHS r_1262 -0 + RHS r_1263 -0 + RHS r_1264 -0 + RHS r_1265 -0 + RHS r_1266 -0 + RHS r_1267 -0 + RHS r_1268 -0 + RHS r_1269 -0 + RHS r_1270 -0 + RHS r_1271 -0 + RHS r_1272 -0 + RHS r_1273 -0 + RHS r_1274 -0 + RHS r_1275 -0 + RHS r_1276 -0 + RHS r_1277 -0 + RHS r_1278 -0 + RHS r_1279 -0 + RHS r_1280 -0 + RHS r_1281 -0 + RHS r_1282 -0 + RHS r_1283 -0 + RHS r_1284 -0 + RHS r_1285 -0 + RHS r_1286 -0 + RHS r_1287 -0 + RHS r_1288 -0 + RHS r_1289 -0 + RHS r_1290 -0 + RHS r_1291 -0 + RHS r_1292 -0 + RHS r_1293 -0 + RHS r_1294 -0 + RHS r_1295 -0 + RHS r_1296 -0 + RHS r_1297 -0 + RHS r_1298 -0 + RHS r_1299 -0 + RHS r_1300 -0 + RHS r_1301 -0 + RHS r_1302 -0 + RHS r_1303 -0 + RHS r_1304 -0 + RHS r_1305 -0 + RHS r_1306 -0 + RHS r_1307 -0 + RHS r_1308 -0 + RHS r_1309 -0 + RHS r_1310 -0 + RHS r_1311 -0 + RHS r_1312 -0 + RHS r_1313 -0 + RHS r_1314 -0 + RHS r_1315 -0 + RHS r_1316 -0 + RHS r_1317 -0 + RHS r_1318 -0 + RHS r_1319 -0 + RHS r_1320 -0 + RHS r_1321 -0 + RHS r_1322 -0 + RHS r_1323 -0 + RHS r_1324 -0 + RHS r_1325 -0 + RHS r_1326 -0 + RHS r_1327 -0 + RHS r_1328 -0 + RHS r_1329 -0 + RHS r_1330 -0 + RHS r_1331 -0 + RHS r_1332 -0 + RHS r_1333 -0 + RHS r_1334 -0 + RHS r_1335 -0 + RHS r_1336 -0 + RHS r_1337 -0 + RHS r_1338 -0 + RHS r_1339 -0 + RHS r_1340 -0 + RHS r_1341 -0 + RHS r_1342 -0 + RHS r_1343 -0 + RHS r_1344 -0 + RHS r_1345 -0 + RHS r_1346 -0 + RHS r_1347 -0 + RHS r_1348 -0 + RHS r_1349 -0 + RHS r_1350 -0 + RHS r_1351 -0 + RHS r_1352 -0 + RHS r_1353 -0 + RHS r_1354 -0 + RHS r_1355 -0 + RHS r_1356 -0 + RHS r_1357 -0 + RHS r_1358 -0 + RHS r_1359 -0 + RHS r_1360 -0 + RHS r_1361 -0 + RHS r_1362 -0 + RHS r_1363 -0 + RHS r_1364 -0 + RHS r_1365 -0 + RHS r_1366 -0 + RHS r_1367 -0 + RHS r_1368 1 + RHS r_1369 1 + RHS r_1370 1 + RHS r_1371 1 + RHS r_1372 1 + RHS r_1373 1 + RHS r_1374 1 + RHS r_1375 1 + RHS r_1376 1 + RHS r_1377 1 + RHS r_1378 1 + RHS r_1379 1 + RHS r_1380 1 + RHS r_1381 1 + RHS r_1382 1 + RHS r_1383 1 + RHS r_1384 1 + RHS r_1385 1 + RHS r_1386 1 + RHS r_1387 1 + RHS r_1388 1 + RHS r_1389 1 + RHS r_1390 1 + RHS r_1391 1 + RHS r_1392 1 + RHS r_1393 1 + RHS r_1394 1 + RHS r_1395 1 + RHS r_1396 1 + RHS r_1397 1 + RHS r_1398 1 + RHS r_1399 1 + RHS r_1400 1 + RHS r_1401 1 + RHS r_1402 1 + RHS r_1403 1 + RHS r_1404 1 + RHS r_1405 1 + RHS r_1406 1 + RHS r_1407 1 + RHS r_1408 1 + RHS r_1409 1 + RHS r_1410 1 + RHS r_1411 1 + RHS r_1412 1 + RHS r_1413 1 + RHS r_1414 1 + RHS r_1415 1 + RHS r_1416 1 + RHS r_1417 1 + RHS r_1418 1 + RHS r_1419 1 + RHS r_1420 1 + RHS r_1421 1 + RHS r_1422 1 + RHS r_1423 1 + RHS r_1424 1 + RHS r_1425 1 + RHS r_1426 1 + RHS r_1427 1 + RHS r_1428 1 + RHS r_1429 1 + RHS r_1430 1 + RHS r_1431 1 + RHS r_1432 1 + RHS r_1433 1 + RHS r_1434 1 + RHS r_1435 1 + RHS r_1436 1 + RHS r_1437 1 + RHS r_1438 -0 + RHS r_1439 -0 + RHS r_1440 -0 + RHS r_1441 -0 + RHS r_1442 -0 + RHS r_1443 -0 + RHS r_1444 -0 + RHS r_1445 -0 + RHS r_1446 -0 + RHS r_1447 -0 + RHS r_1448 -0 + RHS r_1449 -0 + RHS r_1450 -0 + RHS r_1451 -0 + RHS r_1452 -0 + RHS r_1453 -0 + RHS r_1454 -0 + RHS r_1455 -0 + RHS r_1456 -0 + RHS r_1457 -0 + RHS r_1458 -0 + RHS r_1459 -0 + RHS r_1460 -0 + RHS r_1461 -0 + RHS r_1462 -0 + RHS r_1463 -0 + RHS r_1464 -0 + RHS r_1465 -0 + RHS r_1466 -0 + RHS r_1467 -0 + RHS r_1468 -0 + RHS r_1469 -0 + RHS r_1470 -0 + RHS r_1471 -0 + RHS r_1472 -0 + RHS r_1473 -0 + RHS r_1474 -0 + RHS r_1475 -0 + RHS r_1476 -0 + RHS r_1477 -0 + RHS r_1478 -0 + RHS r_1479 -0 + RHS r_1480 -0 + RHS r_1481 -0 + RHS r_1482 -0 + RHS r_1483 -0 + RHS r_1484 -0 + RHS r_1485 -0 + RHS r_1486 -0 + RHS r_1487 -0 + RHS r_1488 -0 + RHS r_1489 -0 + RHS r_1490 -0 + RHS r_1491 -0 + RHS r_1492 -0 + RHS r_1493 -0 + RHS r_1494 -0 + RHS r_1495 -0 + RHS r_1496 -0 + RHS r_1497 -0 + RHS r_1498 -0 + RHS r_1499 -0 + RHS r_1500 -0 + RHS r_1501 -0 + RHS r_1502 -0 + RHS r_1503 -0 + RHS r_1504 -0 + RHS r_1505 -0 + RHS r_1506 -0 + RHS r_1507 -0 + RHS r_1508 -0 + RHS r_1509 -0 + RHS r_1510 -0 + RHS r_1511 -0 + RHS r_1512 -0 + RHS r_1513 -0 + RHS r_1514 -0 + RHS r_1515 -0 + RHS r_1516 -0 + RHS r_1517 -0 + RHS r_1518 -0 + RHS r_1519 -0 + RHS r_1520 -0 + RHS r_1521 -0 + RHS r_1522 -0 + RHS r_1523 -0 + RHS r_1524 -0 + RHS r_1525 -0 + RHS r_1526 -0 + RHS r_1527 -0 + RHS r_1528 -0 + RHS r_1529 -0 + RHS r_1530 -0 + RHS r_1531 -0 + RHS r_1532 -0 + RHS r_1533 -0 + RHS r_1534 -0 + RHS r_1535 -0 + RHS r_1536 -0 + RHS r_1537 -0 + RHS r_1538 -0 + RHS r_1539 -0 + RHS r_1540 -0 + RHS r_1541 -0 + RHS r_1542 -0 + RHS r_1543 -0 + RHS r_1544 -0 + RHS r_1545 -0 + RHS r_1546 -0 + RHS r_1547 -0 + RHS r_1548 -0 + RHS r_1549 -0 + RHS r_1550 -0 + RHS r_1551 -0 + RHS r_1552 -0 + RHS r_1553 -0 + RHS r_1554 -0 + RHS r_1555 -0 + RHS r_1556 -0 + RHS r_1557 -0 + RHS r_1558 -0 + RHS r_1559 -0 + RHS r_1560 -0 + RHS r_1561 -0 + RHS r_1562 -0 + RHS r_1563 -0 + RHS r_1564 -0 + RHS r_1565 -0 + RHS r_1566 -0 + RHS r_1567 -0 + RHS r_1568 -0 + RHS r_1569 -0 + RHS r_1570 -0 + RHS r_1571 -0 + RHS r_1572 -0 + RHS r_1573 -0 + RHS r_1574 -0 + RHS r_1575 -0 + RHS r_1576 -0 + RHS r_1577 -0 + RHS r_1578 -0 + RHS r_1579 -0 + RHS r_1580 -0 + RHS r_1581 -0 + RHS r_1582 -0 + RHS r_1583 -0 + RHS r_1584 -0 + RHS r_1585 -0 + RHS r_1586 -0 + RHS r_1587 -0 + RHS r_1588 -0 + RHS r_1589 -0 + RHS r_1590 -0 + RHS r_1591 -0 + RHS r_1592 -0 + RHS r_1593 -0 + RHS r_1594 -0 + RHS r_1595 -0 + RHS r_1596 -0 + RHS r_1597 -0 + RHS r_1598 -0 + RHS r_1599 -0 + RHS r_1600 -0 + RHS r_1601 -0 + RHS r_1602 -0 + RHS r_1603 -0 + RHS r_1604 -0 + RHS r_1605 -0 + RHS r_1606 -0 + RHS r_1607 -0 + RHS r_1608 -0 + RHS r_1609 -0 + RHS r_1610 -0 + RHS r_1611 -0 + RHS r_1612 -0 + RHS r_1613 -0 + RHS r_1614 -0 + RHS r_1615 -0 + RHS r_1616 -0 + RHS r_1617 -0 + RHS r_1618 -0 + RHS r_1619 -0 + RHS r_1620 -0 + RHS r_1621 -0 + RHS r_1622 -0 + RHS r_1623 -0 + RHS r_1624 -0 + RHS r_1625 -0 + RHS r_1626 -0 + RHS r_1627 -0 + RHS r_1628 -0 + RHS r_1629 -0 + RHS r_1630 -0 + RHS r_1631 -0 + RHS r_1632 -0 + RHS r_1633 -0 + RHS r_1634 -0 + RHS r_1635 -0 + RHS r_1636 -0 + RHS r_1637 -0 + RHS r_1638 -0 + RHS r_1639 -0 + RHS r_1640 -0 + RHS r_1641 -0 + RHS r_1642 -0 + RHS r_1643 -0 + RHS r_1644 -0 + RHS r_1645 -0 + RHS r_1646 -0 + RHS r_1647 -0 + RHS r_1648 -0 + RHS r_1649 -0 + RHS r_1650 -0 + RHS r_1651 -0 + RHS r_1652 -0 + RHS r_1653 -0 + RHS r_1654 -0 + RHS r_1655 -0 + RHS r_1656 -0 + RHS r_1657 -0 + RHS r_1658 -0 + RHS r_1659 -0 + RHS r_1660 -0 + RHS r_1661 -0 + RHS r_1662 -0 + RHS r_1663 -0 + RHS r_1664 -0 + RHS r_1665 -0 + RHS r_1666 -0 + RHS r_1667 -0 + RHS r_1668 -0 + RHS r_1669 -0 + RHS r_1670 -0 + RHS r_1671 -0 + RHS r_1672 -0 + RHS r_1673 -0 + RHS r_1674 -0 + RHS r_1675 -0 + RHS r_1676 -0 + RHS r_1677 -0 + RHS r_1678 -0 + RHS r_1679 -0 + RHS r_1680 -0 + RHS r_1681 -0 + RHS r_1682 -0 + RHS r_1683 -0 + RHS r_1684 -0 + RHS r_1685 -0 + RHS r_1686 -0 + RHS r_1687 -0 + RHS r_1688 -0 + RHS r_1689 -0 + RHS r_1690 -0 + RHS r_1691 -0 + RHS r_1692 -0 + RHS r_1693 -0 + RHS r_1694 -0 + RHS r_1695 -0 + RHS r_1696 -0 + RHS r_1697 -0 + RHS r_1698 -0 + RHS r_1699 -0 + RHS r_1700 -0 + RHS r_1701 -0 + RHS r_1702 -0 + RHS r_1703 -0 + RHS r_1704 -0 + RHS r_1705 -0 + RHS r_1706 -0 + RHS r_1707 -0 + RHS r_1708 -0 + RHS r_1709 -0 + RHS r_1710 -0 + RHS r_1711 -0 + RHS r_1712 -0 + RHS r_1713 -0 + RHS r_1714 -0 + RHS r_1715 -0 + RHS r_1716 -0 + RHS r_1717 -0 + RHS r_1718 -0 + RHS r_1719 -0 + RHS r_1720 -0 + RHS r_1721 -0 + RHS r_1722 -0 + RHS r_1723 -0 + RHS r_1724 -0 + RHS r_1725 -0 + RHS r_1726 -0 + RHS r_1727 -0 + RHS r_1728 -0 + RHS r_1729 -0 + RHS r_1730 -0 + RHS r_1731 -0 + RHS r_1732 -0 + RHS r_1733 -0 + RHS r_1734 -0 + RHS r_1735 -0 + RHS r_1736 -0 + RHS r_1737 -0 + RHS r_1738 -0 + RHS r_1739 -0 + RHS r_1740 -0 + RHS r_1741 -0 + RHS r_1742 -0 + RHS r_1743 -0 + RHS r_1744 -0 + RHS r_1745 -0 + RHS r_1746 -0 + RHS r_1747 -0 + RHS r_1748 -0 + RHS r_1749 -0 + RHS r_1750 -0 + RHS r_1751 -0 + RHS r_1752 -0 + RHS r_1753 -0 + RHS r_1754 -0 + RHS r_1755 -0 + RHS r_1756 -0 + RHS r_1757 -0 + RHS r_1758 -0 + RHS r_1759 -0 + RHS r_1760 -0 + RHS r_1761 -0 + RHS r_1762 -0 + RHS r_1763 -0 + RHS r_1764 -0 + RHS r_1765 -0 + RHS r_1766 -0 + RHS r_1767 -0 + RHS r_1768 -0 + RHS r_1769 -0 + RHS r_1770 -0 + RHS r_1771 -0 + RHS r_1772 -0 + RHS r_1773 -0 + RHS r_1774 -0 + RHS r_1775 -0 + RHS r_1776 -0 + RHS r_1777 -0 + RHS r_1778 -0 + RHS r_1779 -0 + RHS r_1780 -0 + RHS r_1781 -0 + RHS r_1782 -0 + RHS r_1783 -0 + RHS r_1784 -0 + RHS r_1785 -0 + RHS r_1786 -0 + RHS r_1787 -0 + RHS r_1788 -0 + RHS r_1789 -0 + RHS r_1790 -0 + RHS r_1791 -0 + RHS r_1792 -0 + RHS r_1793 -0 + RHS r_1794 -0 + RHS r_1795 -0 + RHS r_1796 -0 + RHS r_1797 -0 + RHS r_1798 -0 + RHS r_1799 -0 + RHS r_1800 -0 + RHS r_1801 -0 + RHS r_1802 -0 + RHS r_1803 -0 + RHS r_1804 -0 + RHS r_1805 -0 + RHS r_1806 -0 + RHS r_1807 -0 + RHS r_1808 -0 + RHS r_1809 -0 + RHS r_1810 -0 + RHS r_1811 -0 + RHS r_1812 -0 + RHS r_1813 -0 + RHS r_1814 -0 + RHS r_1815 -0 + RHS r_1816 -0 + RHS r_1817 -0 + RHS r_1818 -0 + RHS r_1819 -0 + RHS r_1820 -0 + RHS r_1821 -0 + RHS r_1822 -0 + RHS r_1823 -0 + RHS r_1824 -0 + RHS r_1825 -0 + RHS r_1826 -0 + RHS r_1827 -0 + RHS r_1828 -0 + RHS r_1829 -0 + RHS r_1830 -0 + RHS r_1831 -0 + RHS r_1832 -0 + RHS r_1833 -0 + RHS r_1834 -0 + RHS r_1835 -0 + RHS r_1836 -0 + RHS r_1837 -0 + RHS r_1838 -0 + RHS r_1839 -0 + RHS r_1840 -0 + RHS r_1841 -0 + RHS r_1842 -0 + RHS r_1843 -0 + RHS r_1844 -0 + RHS r_1845 -0 + RHS r_1846 -0 + RHS r_1847 -0 + RHS r_1848 -0 + RHS r_1849 -0 + RHS r_1850 -0 + RHS r_1851 -0 + RHS r_1852 -0 + RHS r_1853 -0 + RHS r_1854 -0 + RHS r_1855 -0 + RHS r_1856 -0 + RHS r_1857 -0 + RHS r_1858 -0 + RHS r_1859 -0 + RHS r_1860 -0 + RHS r_1861 -0 + RHS r_1862 -0 + RHS r_1863 -0 + RHS r_1864 -0 + RHS r_1865 -0 + RHS r_1866 -0 + RHS r_1867 -0 + RHS r_1868 -0 + RHS r_1869 -0 + RHS r_1870 -0 + RHS r_1871 -0 + RHS r_1872 -0 + RHS r_1873 -0 + RHS r_1874 -0 + RHS r_1875 -0 + RHS r_1876 -0 + RHS r_1877 -0 + RHS r_1878 -0 + RHS r_1879 -0 + RHS r_1880 -0 + RHS r_1881 -0 + RHS r_1882 -0 + RHS r_1883 -0 + RHS r_1884 -0 + RHS r_1885 -0 + RHS r_1886 -0 + RHS r_1887 -0 + RHS r_1888 -0 + RHS r_1889 -0 + RHS r_1890 -0 + RHS r_1891 -0 + RHS r_1892 -0 + RHS r_1893 -0 + RHS r_1894 -0 + RHS r_1895 -0 + RHS r_1896 -0 + RHS r_1897 -0 + RHS r_1898 -0 + RHS r_1899 -0 + RHS r_1900 -0 + RHS r_1901 -0 + RHS r_1902 -0 + RHS r_1903 -0 + RHS r_1904 -0 + RHS r_1905 -0 + RHS r_1906 -0 + RHS r_1907 -0 + RHS r_1908 -0 + RHS r_1909 -0 + RHS r_1910 -0 + RHS r_1911 -0 + RHS r_1912 -0 + RHS r_1913 -0 + RHS r_1914 -0 + RHS r_1915 -0 + RHS r_1916 -0 + RHS r_1917 -0 + RHS r_1918 -0 + RHS r_1919 -0 + RHS r_1920 -0 + RHS r_1921 -0 + RHS r_1922 -0 + RHS r_1923 -0 + RHS r_1924 -0 + RHS r_1925 -0 + RHS r_1926 -0 + RHS r_1927 -0 + RHS r_1928 -0 + RHS r_1929 -0 + RHS r_1930 -0 + RHS r_1931 -0 + RHS r_1932 -0 + RHS r_1933 -0 + RHS r_1934 -0 + RHS r_1935 -0 + RHS r_1936 -0 + RHS r_1937 -0 + RHS r_1938 -0 + RHS r_1939 -0 + RHS r_1940 -0 + RHS r_1941 -0 + RHS r_1942 -0 + RHS r_1943 -0 + RHS r_1944 -0 + RHS r_1945 -0 + RHS r_1946 -0 + RHS r_1947 -0 + RHS r_1948 -0 + RHS r_1949 -0 + RHS r_1950 -0 + RHS r_1951 -0 + RHS r_1952 -0 + RHS r_1953 -0 + RHS r_1954 -0 + RHS r_1955 -0 + RHS r_1956 -0 + RHS r_1957 -0 + RHS r_1958 -0 + RHS r_1959 -0 + RHS r_1960 -0 + RHS r_1961 -0 + RHS r_1962 -0 + RHS r_1963 -0 + RHS r_1964 -0 + RHS r_1965 -0 + RHS r_1966 -0 + RHS r_1967 -0 + RHS r_1968 -0 + RHS r_1969 -0 + RHS r_1970 -0 + RHS r_1971 -0 + RHS r_1972 -0 + RHS r_1973 -0 + RHS r_1974 -0 + RHS r_1975 -0 + RHS r_1976 -0 + RHS r_1977 -0 + RHS r_1978 -0 + RHS r_1979 -0 + RHS r_1980 -0 + RHS r_1981 -0 + RHS r_1982 -0 + RHS r_1983 -0 + RHS r_1984 -0 + RHS r_1985 -0 + RHS r_1986 -0 + RHS r_1987 -0 + RHS r_1988 -0 + RHS r_1989 -0 + RHS r_1990 -0 + RHS r_1991 -0 + RHS r_1992 -0 + RHS r_1993 -0 + RHS r_1994 -0 + RHS r_1995 -0 + RHS r_1996 -0 + RHS r_1997 -0 + RHS r_1998 -0 + RHS r_1999 -0 + RHS r_2000 -0 + RHS r_2001 -0 + RHS r_2002 -0 + RHS r_2003 -0 + RHS r_2004 -0 + RHS r_2005 -0 + RHS r_2006 -0 + RHS r_2007 -0 + RHS r_2008 -0 + RHS r_2009 -0 + RHS r_2010 -0 + RHS r_2011 -0 + RHS r_2012 -0 + RHS r_2013 -0 + RHS r_2014 -0 + RHS r_2015 -0 + RHS r_2016 -0 + RHS r_2017 -0 + RHS r_2018 -0 + RHS r_2019 -0 + RHS r_2020 -0 + RHS r_2021 2 + RHS r_2022 0 + RHS r_2023 2 + RHS r_2024 2 + RHS r_2025 2 + RHS r_2026 2 + RHS r_2027 2 + RHS r_2028 2 + RHS r_2029 1 + RHS r_2030 1 + RHS r_2031 1 + RHS r_2032 1 + RHS r_2033 1 + RHS r_2034 1 + RHS r_2035 1 + RHS r_2036 1 + RHS r_2037 1 + RHS r_2038 1 + RHS r_2039 1 + RHS r_2040 1 + RHS r_2041 1 + RHS r_2042 1 + RHS r_2043 1 + RHS r_2044 4 + RHS r_2045 4 + RHS r_2046 4 + RHS r_2047 4 + RHS r_2048 4 + RHS r_2049 4 + RHS r_2050 4 + RHS r_2051 4 + RHS r_2052 3 + RHS r_2053 3 + RHS r_2054 4 + RHS r_2055 4 + RHS r_2056 4 + RHS r_2057 4 + RHS r_2058 4 + RHS r_2059 4 + RHS r_2060 2 + RHS r_2061 1 + RHS r_2062 1 + RHS r_2063 1 + RHS r_2064 1 + RHS r_2065 1 + RHS r_2066 1 + RHS r_2067 1 + RHS r_2068 2 + RHS r_2069 2 + RHS r_2070 2 + RHS r_2071 2 + RHS r_2072 2 + RHS r_2073 2 + RHS r_2074 2 + RHS r_2075 2 + RHS r_2076 2 + RHS r_2077 2 + RHS r_2078 2 + RHS r_2079 2 + RHS r_2080 2 + RHS r_2081 2 + RHS r_2082 2 + RHS r_2083 2 + RHS r_2084 2 + RHS r_2085 2 + RHS r_2086 2 + RHS r_2087 2 + RHS r_2088 2 + RHS r_2089 2 + RHS r_2090 2 + RHS r_2091 2 + RHS r_2092 1 + RHS r_2093 1 + RHS r_2094 1 + RHS r_2095 2 + RHS r_2096 2 + RHS r_2097 2 + RHS r_2098 2 + RHS r_2099 2 + RHS r_2100 2 + RHS r_2101 2 + RHS r_2102 2 + RHS r_2103 2 + RHS r_2104 2 + RHS r_2105 2 + RHS r_2106 2 + RHS r_2107 2 + RHS r_2108 2 + RHS r_2109 2 + RHS r_2110 2 + RHS r_2111 2 + RHS r_2112 2 + RHS r_2113 2 + RHS r_2114 2 + RHS r_2115 2 + RHS r_2116 2 + RHS r_2117 2 + RHS r_2118 2 + RHS r_2119 2 + RHS r_2120 2 + RHS r_2121 2 + RHS r_2122 2 + RHS r_2123 2 + RHS r_2124 2 + RHS r_2125 2 + RHS r_2126 2 + RHS r_2127 2 + RHS r_2128 2 + RHS r_2129 2 + RHS r_2130 2 + RHS r_2131 2 + RHS r_2132 2 + RHS r_2133 2 + RHS r_2134 2 + RHS r_2135 2 + RHS r_2136 2 + RHS r_2137 2 + RHS r_2138 2 + RHS r_2139 2 + RHS r_2140 2 + RHS r_2141 2 + RHS r_2142 2 + RHS r_2143 2 + RHS r_2144 2 + RHS r_2145 2 + RHS r_2146 2 + RHS r_2147 2 + RHS r_2148 2 + RHS r_2149 2 + RHS r_2150 2 + RHS r_2151 2 + RHS r_2152 2 + RHS r_2153 2 + RHS r_2154 2 + RHS r_2155 2 + RHS r_2156 2 + RHS r_2157 2 + RHS r_2158 2 + RHS r_2159 2 + RHS r_2160 2 + RHS r_2161 2 + RHS r_2162 2 + RHS r_2163 1 + RHS r_2164 2 + RHS r_2165 2 + RHS r_2166 2 + RHS r_2167 2 + RHS r_2168 2 + RHS r_2169 2 + RHS r_2170 2 + RHS r_2171 2 + RHS r_2172 2 + RHS r_2173 2 + RHS r_2174 2 + RHS r_2175 2 + RHS r_2176 2 + RHS r_2177 2 + RHS r_2178 2 + RHS r_2179 2 + RHS r_2180 2 + RHS r_2181 2 + RHS r_2182 2 + RHS r_2183 2 + RHS r_2184 2 + RHS r_2185 2 + RHS r_2186 2 + RHS r_2187 2 + RHS r_2188 2 + RHS r_2189 2 + RHS r_2190 2 + RHS r_2191 2 + RHS r_2192 2 + RHS r_2193 2 + RHS r_2194 2 + RHS r_2195 2 + RHS r_2196 2 + RHS r_2197 2 + RHS r_2198 2 + RHS r_2199 2 + RHS r_2200 2 + RHS r_2201 2 + RHS r_2202 2 + RHS r_2203 2 + RHS r_2204 2 + RHS r_2205 2 + RHS r_2206 2 + RHS r_2207 2 + RHS r_2208 2 + RHS r_2209 2 + RHS r_2210 2 + RHS r_2211 2 + RHS r_2212 2 + RHS r_2213 2 + RHS r_2214 2 + RHS r_2215 2 + RHS r_2216 2 + RHS r_2217 2 + RHS r_2218 2 + RHS r_2219 2 + RHS r_2220 2 + RHS r_2221 2 + RHS r_2222 2 + RHS r_2223 2 + RHS r_2224 2 + RHS r_2225 2 + RHS r_2226 2 + RHS r_2227 2 + RHS r_2228 2 + RHS r_2229 2 + RHS r_2230 2 + RHS r_2231 2 + RHS r_2232 2 + RHS r_2233 2 + RHS r_2234 2 + RHS r_2235 2 + RHS r_2236 2 + RHS r_2237 2 + RHS r_2238 2 + RHS r_2239 2 + RHS r_2240 2 + RHS r_2241 2 + RHS r_2242 2 + RHS r_2243 2 + RHS r_2244 2 + RHS r_2245 2 + RHS r_2246 2 + RHS r_2247 2 + RHS r_2248 2 + RHS r_2249 2 + RHS r_2250 2 + RHS r_2251 2 + RHS r_2252 2 + RHS r_2253 1 + RHS r_2254 2 + RHS r_2255 2 + RHS r_2256 2 + RHS r_2257 2 + RHS r_2258 2 + RHS r_2259 2 + RHS r_2260 2 + RHS r_2261 2 + RHS r_2262 2 + RHS r_2263 2 + RHS r_2264 2 + RHS r_2265 2 + RHS r_2266 2 + RHS r_2267 2 + RHS r_2268 2 + RHS r_2269 2 + RHS r_2270 2 + RHS r_2271 2 + RHS r_2272 2 + RHS r_2273 2 + RHS r_2274 2 + RHS r_2275 1 + RHS r_2276 2 + RHS r_2277 2 + RHS r_2278 2 + RHS r_2279 2 + RHS r_2280 2 + RHS r_2281 2 + RHS r_2282 2 + RHS r_2283 2 + RHS r_2284 2 + RHS r_2285 2 + RHS r_2286 2 + RHS r_2287 2 + RHS r_2288 2 + RHS r_2289 2 + RHS r_2290 2 + RHS r_2291 2 + RHS r_2292 2 + RHS r_2293 2 + RHS r_2294 2 + RHS r_2295 2 + RHS r_2296 2 + RHS r_2297 2 + RHS r_2298 1 + RHS r_2299 2 + RHS r_2300 2 + RHS r_2301 2 + RHS r_2302 2 + RHS r_2303 2 + RHS r_2304 2 + RHS r_2305 2 + RHS r_2306 2 + RHS r_2307 2 + RHS r_2308 2 + RHS r_2309 2 + RHS r_2310 2 + RHS r_2311 2 + RHS r_2312 2 + RHS r_2313 2 + RHS r_2314 1 + RHS r_2315 2 + RHS r_2316 2 + RHS r_2317 2 + RHS r_2318 2 + RHS r_2319 2 + RHS r_2320 2 + RHS r_2321 2 + RHS r_2322 2 + RHS r_2323 2 + RHS r_2324 2 + RHS r_2325 2 + RHS r_2326 2 + RHS r_2327 2 + RHS r_2328 2 + RHS r_2329 2 + RHS r_2330 2 + RHS r_2331 2 + RHS r_2332 2 + RHS r_2333 2 + RHS r_2334 2 + RHS r_2335 2 + RHS r_2336 2 + RHS r_2337 2 + RHS r_2338 2 + RHS r_2339 2 + RHS r_2340 2 + RHS r_2341 2 + RHS r_2342 2 + RHS r_2343 2 + RHS r_2344 2 + RHS r_2345 2 + RHS r_2346 2 + RHS r_2347 2 + RHS r_2348 2 + RHS r_2349 2 + RHS r_2350 2 + RHS r_2351 2 + RHS r_2352 2 + RHS r_2353 2 + RHS r_2354 1 + RHS r_2355 1 + RHS r_2356 1 + RHS r_2357 2 + RHS r_2358 2 + RHS r_2359 2 + RHS r_2360 2 + RHS r_2361 2 + RHS r_2362 2 + RHS r_2363 2 + RHS r_2364 2 + RHS r_2365 2 + RHS r_2366 2 + RHS r_2367 2 + RHS r_2368 2 + RHS r_2369 2 + RHS r_2370 2 + RHS r_2371 2 + RHS r_2372 2 + RHS r_2373 2 + RHS r_2374 2 + RHS r_2375 2 + RHS r_2376 2 + RHS r_2377 2 + RHS r_2378 2 + RHS r_2379 2 + RHS r_2380 2 + RHS r_2381 2 + RHS r_2382 2 + RHS r_2383 2 + RHS r_2384 2 + RHS r_2385 2 + RHS r_2386 2 + RHS r_2387 2 + RHS r_2388 2 + RHS r_2389 2 + RHS r_2390 2 + RHS r_2391 2 + RHS r_2392 2 + RHS r_2393 2 + RHS r_2394 2 + RHS r_2395 2 + RHS r_2396 2 + RHS r_2397 1 + RHS r_2398 1 + RHS r_2399 2 + RHS r_2400 2 + RHS r_2401 2 + RHS r_2402 2 + RHS r_2403 2 + RHS r_2404 2 + RHS r_2405 2 + RHS r_2406 2 + RHS r_2407 2 + RHS r_2408 2 + RHS r_2409 2 + RHS r_2410 2 + RHS r_2411 2 + RHS r_2412 2 + RHS r_2413 2 + RHS r_2414 2 + RHS r_2415 2 + RHS r_2416 2 + RHS r_2417 2 + RHS r_2418 2 + RHS r_2419 2 + RHS r_2420 2 + RHS r_2421 2 + RHS r_2422 2 + RHS r_2423 2 + RHS r_2424 2 + RHS r_2425 2 + RHS r_2426 2 + RHS r_2427 2 + RHS r_2428 2 + RHS r_2429 2 + RHS r_2430 2 + RHS r_2431 2 + RHS r_2432 2 + RHS r_2433 2 + RHS r_2434 2 + RHS r_2435 2 + RHS r_2436 2 + RHS r_2437 2 + RHS r_2438 2 + RHS r_2439 2 + RHS r_2440 2 + RHS r_2441 2 + RHS r_2442 2 + RHS r_2443 2 + RHS r_2444 2 + RHS r_2445 2 + RHS r_2446 2 + RHS r_2447 2 + RHS r_2448 2 + RHS r_2449 2 + RHS r_2450 2 + RHS r_2451 2 + RHS r_2452 2 + RHS r_2453 2 + RHS r_2454 2 + RHS r_2455 2 + RHS r_2456 2 + RHS r_2457 1 + RHS r_2458 2 + RHS r_2459 1 + RHS r_2460 -1 + RHS r_2461 -1 + RHS r_2462 -1 + RHS r_2463 -1 + RHS r_2464 -1 + RHS r_2465 -1 + RHS r_2466 -1 + RHS r_2467 -1 + RHS r_2468 -1 + RHS r_2469 -1 + RHS r_2470 -1 + RHS r_2471 -1 + RHS r_2472 -1 + RHS r_2473 -1 + RHS r_2474 -1 + RHS r_2475 -1 + RHS r_2476 -1 + RHS r_2477 -1 + RHS r_2478 -1 + RHS r_2479 -1 + RHS r_2480 -1 + RHS r_2481 -1 + RHS r_2482 -1 + RHS r_2483 -1 + RHS r_2484 -1 + RHS r_2485 -1 + RHS r_2486 -1 + RHS r_2487 -1 + RHS r_2488 -1 + RHS r_2489 -1 + RHS r_2490 -1 + RHS r_2491 -1 + RHS r_2492 -1 + RHS r_2493 -1 + RHS r_2494 -1 + RHS r_2495 -1 + RHS r_2496 -1 + RHS r_2497 -1 + RHS r_2498 -1 + RHS r_2499 -1 + RHS r_2500 -1 + RHS r_2501 -1 + RHS r_2502 -1 + RHS r_2503 -1 + RHS r_2504 -1 + RHS r_2505 -1 + RHS r_2506 -1 + RHS r_2507 -1 + RHS r_2508 -1 + RHS r_2509 -1 + RHS r_2510 -1 + RHS r_2511 -1 + RHS r_2512 -1 + RHS r_2513 -1 + RHS r_2514 -1 + RHS r_2515 -1 + RHS r_2516 -1 + RHS r_2517 -1 + RHS r_2518 -1 + RHS r_2519 -1 + RHS r_2520 -1 + RHS r_2521 -1 + RHS r_2522 -1 + RHS r_2523 -1 + RHS r_2524 -1 + RHS r_2525 -1 + RHS r_2526 -1 + RHS r_2527 -1 + RHS r_2528 -1 + RHS r_2529 -1 + RHS r_2530 -1 + RHS r_2531 -1 + RHS r_2532 -1 + RHS r_2533 -1 + RHS r_2534 -1 + RHS r_2535 -1 + RHS r_2536 -1 + RHS r_2537 -1 + RHS r_2538 -1 + RHS r_2539 -1 + RHS r_2540 -1 + RHS r_2541 -1 + RHS r_2542 -1 + RHS r_2543 -1 + RHS r_2544 -1 + RHS r_2545 -1 + RHS r_2546 -1 + RHS r_2547 -1 + RHS r_2548 -1 + RHS r_2549 -1 + RHS r_2550 -1 + RHS r_2551 -1 + RHS r_2552 -1 + RHS r_2553 -1 + RHS r_2554 -1 + RHS r_2555 -1 + RHS r_2556 -1 + RHS r_2557 -1 + RHS r_2558 -1 + RHS r_2559 -1 + RHS r_2560 -1 + RHS r_2561 -1 + RHS r_2562 -1 + RHS r_2563 -1 + RHS r_2564 -1 + RHS r_2565 -1 + RHS r_2566 -1 + RHS r_2567 -1 + RHS r_2568 -1 + RHS r_2569 -1 + RHS r_2570 -1 + RHS r_2571 -1 + RHS r_2572 -1 + RHS r_2573 -1 + RHS r_2574 -1 + RHS r_2575 -1 + RHS r_2576 -1 + RHS r_2577 -1 + RHS r_2578 -1 + RHS r_2579 -1 + RHS r_2580 -1 + RHS r_2581 -1 + RHS r_2582 -1 + RHS r_2583 -1 + RHS r_2584 -1 + RHS r_2585 -1 + RHS r_2586 -1 + RHS r_2587 -1 + RHS r_2588 -1 + RHS r_2589 -1 + RHS r_2590 -1 + RHS r_2591 -1 + RHS r_2592 -1 + RHS r_2593 -1 + RHS r_2594 -1 + RHS r_2595 -1 + RHS r_2596 -1 + RHS r_2597 -1 + RHS r_2598 -1 + RHS r_2599 -1 + RHS r_2600 -1 + RHS r_2601 -1 + RHS r_2602 -1 + RHS r_2603 -1 + RHS r_2604 -1 + RHS r_2605 -1 + RHS r_2606 -1 + RHS r_2607 -1 + RHS r_2608 -1 + RHS r_2609 -1 + RHS r_2610 -1 + RHS r_2611 -1 + RHS r_2612 -1 + RHS r_2613 -1 + RHS r_2614 -1 + RHS r_2615 -1 + RHS r_2616 -1 + RHS r_2617 -1 + RHS r_2618 -1 + RHS r_2619 -1 + RHS r_2620 -1 + RHS r_2621 -1 + RHS r_2622 -1 + RHS r_2623 -1 + RHS r_2624 -1 + RHS r_2625 -1 + RHS r_2626 -1 + RHS r_2627 -1 + RHS r_2628 -1 + RHS r_2629 -1 + RHS r_2630 3 + RHS r_2631 4 + RHS r_2632 4 + RHS r_2633 4 + RHS r_2634 4 + RHS r_2635 4 + RHS r_2636 4 + RHS r_2637 4 + RHS r_2638 4 + RHS r_2639 4 + RHS r_2640 4 + RHS r_2641 4 + RHS r_2642 4 + RHS r_2643 4 + RHS r_2644 4 + RHS r_2645 4 + RHS r_2646 3 + RHS r_2647 3 + RHS r_2648 3 + RHS r_2649 3 + RHS r_2650 3 + RHS r_2651 4 + RHS r_2652 4 + RHS r_2653 4 + RHS r_2654 4 + RHS r_2655 3 + RHS r_2656 3 + RHS r_2657 2 + RHS r_2658 3 + RHS r_2659 4 + RHS r_2660 4 + RHS r_2661 4 + RHS r_2662 4 + RHS r_2663 4 + RHS r_2664 4 + RHS r_2665 4 + RHS r_2666 4 + RHS r_2667 4 + RHS r_2668 4 + RHS r_2669 4 + RHS r_2670 4 + RHS r_2671 4 + RHS r_2672 3 + RHS r_2673 4 + RHS r_2674 4 + RHS r_2675 4 + RHS r_2676 4 + RHS r_2677 4 + RHS r_2678 4 + RHS r_2679 4 + RHS r_2680 4 + RHS r_2681 4 + RHS r_2682 4 + RHS r_2683 4 + RHS r_2684 4 + RHS r_2685 4 + RHS r_2686 4 + RHS r_2687 4 + RHS r_2688 4 + RHS r_2689 4 + RHS r_2690 4 + RHS r_2691 4 + RHS r_2692 4 + RHS r_2693 4 + RHS r_2694 4 + RHS r_2695 4 + RHS r_2696 4 + RHS r_2697 4 + RHS r_2698 4 + RHS r_2699 4 + RHS r_2700 4 + RHS r_2701 4 + RHS r_2702 4 + RHS r_2703 4 + RHS r_2704 4 + RHS r_2705 4 + RHS r_2706 3 + RHS r_2707 3 + RHS r_2708 3 + RHS r_2709 3 + RHS r_2710 3 + RHS r_2711 4 + RHS r_2712 4 + RHS r_2713 4 + RHS r_2714 4 + RHS r_2715 4 + RHS r_2716 4 + RHS r_2717 4 + RHS r_2718 4 + RHS r_2719 4 + RHS r_2720 4 + RHS r_2721 4 + RHS r_2722 4 + RHS r_2723 4 + RHS r_2724 4 + RHS r_2725 4 + RHS r_2726 4 + RHS r_2727 4 + RHS r_2728 4 + RHS r_2729 4 + RHS r_2730 4 + RHS r_2731 4 + RHS r_2732 4 + RHS r_2733 4 + RHS r_2734 4 + RHS r_2735 4 + RHS r_2736 4 + RHS r_2737 4 + RHS r_2738 4 + RHS r_2739 4 + RHS r_2740 4 + RHS r_2741 4 + RHS r_2742 3 + RHS r_2743 4 + RHS r_2744 4 + RHS r_2745 3 + RHS r_2746 3 + RHS r_2747 2 + RHS r_2748 2 + RHS r_2749 2 + RHS r_2750 3 + RHS r_2751 3 + RHS r_2752 4 + RHS r_2753 4 + RHS r_2754 3 + RHS r_2755 3 + RHS r_2756 3 + RHS r_2757 3 + RHS r_2758 3 + RHS r_2759 3 + RHS r_2760 3 + RHS r_2761 3 + RHS r_2762 3 + RHS r_2763 3 + RHS r_2764 2 + RHS r_2765 1 + RHS r_2766 3 + RHS r_2767 3 + RHS r_2768 3 + RHS r_2769 3 + RHS r_2770 3 + RHS r_2771 3 + RHS r_2772 3 + RHS r_2773 3 + RHS r_2774 3 + RHS r_2775 3 + RHS r_2776 3 + RHS r_2777 3 + RHS r_2778 3 + RHS r_2779 3 + RHS r_2780 3 + RHS r_2781 3 + RHS r_2782 3 + RHS r_2783 3 + RHS r_2784 3 + RHS r_2785 3 + RHS r_2786 3 + RHS r_2787 3 + RHS r_2788 3 + RHS r_2789 3 + RHS r_2790 3 + RHS r_2791 3 + RHS r_2792 3 + RHS r_2793 3 + RHS r_2794 3 + RHS r_2795 3 + RHS r_2796 3 + RHS r_2797 3 + RHS r_2798 3 + RHS r_2799 3 + RHS r_2800 3 + RHS r_2801 3 + RHS r_2802 2 + RHS r_2803 1 + RHS r_2804 1 + RHS r_2805 1 + RHS r_2806 2 + RHS r_2807 2 + RHS r_2808 4 + RHS r_2809 3 + RHS r_2810 4 + RHS r_2811 4 + RHS r_2812 4 + RHS r_2813 4 + RHS r_2814 4 + RHS r_2815 4 + RHS r_2816 2 + RHS r_2817 1 + RHS r_2818 1 + RHS r_2819 1 + RHS r_2820 1 + RHS r_2821 1 + RHS r_2822 1 + RHS r_2823 1 + RHS r_2824 2 + RHS r_2825 2 + RHS r_2826 2 + RHS r_2827 2 + RHS r_2828 2 + RHS r_2829 2 + RHS r_2830 2 + RHS r_2831 2 + RHS r_2832 2 + RHS r_2833 1 + RHS r_2834 1 + RHS r_2835 1 + RHS r_2836 1 + RHS r_2837 1 + RHS r_2838 1 + RHS r_2839 1 + RHS r_2840 1 + RHS r_2841 1 + RHS r_2842 1 + RHS r_2843 1 + RHS r_2844 1 + RHS r_2845 1 + RHS r_2846 1 + RHS r_2847 1 + RHS r_2848 1 + RHS r_2849 1 + RHS r_2850 1 + RHS r_2851 1 + RHS r_2852 1 + RHS r_2853 1 + RHS r_2854 1 + RHS r_2855 1 + RHS r_2856 1 + RHS r_2857 1 + RHS r_2858 1 + RHS r_2859 1 + RHS r_2860 1 + RHS r_2861 1 + RHS r_2862 1 + RHS r_2863 1 + RHS r_2864 1 + RHS r_2865 1 + RHS r_2866 1 + RHS r_2867 1 + RHS r_2868 1 + RHS r_2869 1 + RHS r_2870 1 + RHS r_2871 1 + RHS r_2872 1 + RHS r_2873 1 + RHS r_2874 1 + RHS r_2875 1 + RHS r_2876 1 + RHS r_2877 1 + RHS r_2878 1 + RHS r_2879 1 + RHS r_2880 1 + RHS r_2881 1 + RHS r_2882 1 + RHS r_2883 1 + RHS r_2884 1 + RHS r_2885 1 + RHS r_2886 1 + RHS r_2887 1 + RHS r_2888 1 + RHS r_2889 1 + RHS r_2890 1 + RHS r_2891 1 + RHS r_2892 1 + RHS r_2893 1 + RHS r_2894 1 + RHS r_2895 1 + RHS r_2896 1 + RHS r_2897 1 + RHS r_2898 1 + RHS r_2899 1 + RHS r_2900 1 + RHS r_2901 1 + RHS r_2902 1 + RHS r_2903 1 + RHS r_2904 1 + RHS r_2905 1 + RHS r_2906 1 + RHS r_2907 1 + RHS r_2908 1 + RHS r_2909 1 + RHS r_2910 1 + RHS r_2911 1 + RHS r_2912 1 + RHS r_2913 1 + RHS r_2914 1 + RHS r_2915 1 + RHS r_2916 1 + RHS r_2917 1 + RHS r_2918 1 + RHS r_2919 1 + RHS r_2920 1 + RHS r_2921 1 + RHS r_2922 1 + RHS r_2923 1 + RHS r_2924 1 + RHS r_2925 1 + RHS r_2926 1 + RHS r_2927 1 + RHS r_2928 1 + RHS r_2929 1 + RHS r_2930 1 + RHS r_2931 1 + RHS r_2932 1 + RHS r_2933 1 + RHS r_2934 1 + RHS r_2935 1 + RHS r_2936 1 + RHS r_2937 1 + RHS r_2938 1 + RHS r_2939 1 + RHS r_2940 1 + RHS r_2941 1 + RHS r_2942 1 + RHS r_2943 1 + RHS r_2944 1 + RHS r_2945 1 + RHS r_2946 1 + RHS r_2947 1 + RHS r_2948 1 + RHS r_2949 1 + RHS r_2950 1 + RHS r_2951 1 + RHS r_2952 1 + RHS r_2953 1 + RHS r_2954 2 + RHS r_2955 2 + RHS r_2956 2 + RHS r_2957 2 + RHS r_2958 2 + RHS r_2959 2 + RHS r_2960 2 + RHS r_2961 2 + RHS r_2962 2 + RHS r_2963 2 + RHS r_2964 2 + RHS r_2965 2 + RHS r_2966 2 + RHS r_2967 2 + RHS r_2968 2 + RHS r_2969 2 + RHS r_2970 2 + RHS r_2971 2 + RHS r_2972 2 + RHS r_2973 2 + RHS r_2974 2 + RHS r_2975 2 + RHS r_2976 2 + RHS r_2977 2 + RHS r_2978 2 + RHS r_2979 2 + RHS r_2980 2 + RHS r_2981 2 + RHS r_2982 2 + RHS r_2983 2 + RHS r_2984 2 + RHS r_2985 2 + RHS r_2986 2 + RHS r_2987 2 + RHS r_2988 2 + RHS r_2989 2 + RHS r_2990 2 + RHS r_2991 2 + RHS r_2992 2 + RHS r_2993 2 + RHS r_2994 2 + RHS r_2995 2 + RHS r_2996 2 + RHS r_2997 2 + RHS r_2998 2 + RHS r_2999 2 + RHS r_3000 2 + RHS r_3001 2 + RHS r_3002 2 + RHS r_3003 2 + RHS r_3004 2 + RHS r_3005 2 + RHS r_3006 2 + RHS r_3007 2 + RHS r_3008 2 + RHS r_3009 2 + RHS r_3010 2 + RHS r_3011 2 + RHS r_3012 2 + RHS r_3013 2 + RHS r_3014 2 + RHS r_3015 2 + RHS r_3016 2 + RHS r_3017 2 + RHS r_3018 2 + RHS r_3019 2 + RHS r_3020 2 + RHS r_3021 2 + RHS r_3022 2 + RHS r_3023 2 + RHS r_3024 2 + RHS r_3025 2 + RHS r_3026 2 + RHS r_3027 2 + RHS r_3028 2 + RHS r_3029 2 + RHS r_3030 2 + RHS r_3031 2 + RHS r_3032 2 + RHS r_3033 2 + RHS r_3034 2 + RHS r_3035 2 + RHS r_3036 2 + RHS r_3037 2 + RHS r_3038 2 + RHS r_3039 2 + RHS r_3040 2 + RHS r_3041 2 + RHS r_3042 2 + RHS r_3043 2 + RHS r_3044 2 + RHS r_3045 2 + RHS r_3046 2 + RHS r_3047 2 + RHS r_3048 2 + RHS r_3049 2 + RHS r_3050 1 + RHS r_3051 1 + RHS r_3052 1 +BOUNDS + UP BND v10 1 + UP BND v11 1 + UP BND v12 1 + UP BND v13 1 + UP BND v14 1 + UP BND v15 1 + UP BND v16 1 + UP BND v17 1 + UP BND v18 1 + UP BND v19 1 + UP BND v20 1 + UP BND v21 1 + UP BND v22 1 + UP BND v23 1 + UP BND v24 1 + UP BND v25 1 + UP BND v26 1 + UP BND v27 1 + UP BND v28 1 + UP BND v29 1 + UP BND v30 1 + UP BND v31 1 + UP BND v32 1 + UP BND v33 1 + UP BND v34 1 + UP BND v35 1 + UP BND v36 1 + UP BND v37 1 + UP BND v38 1 + UP BND v39 1 + UP BND v40 1 + UP BND v41 1 + UP BND v42 1 + UP BND v43 1 + UP BND v44 1 + UP BND v45 1 + UP BND v46 1 + UP BND v47 1 + UP BND v48 1 + UP BND v49 1 + UP BND v50 1 + UP BND v51 1 + UP BND v52 1 + UP BND v53 1 + UP BND v54 1 + UP BND v55 1 + UP BND v56 1 + UP BND v57 1 + UP BND v58 1 + UP BND v59 1 + UP BND v60 1 + UP BND v61 1 + UP BND v62 1 + UP BND v63 1 + UP BND v64 1 + UP BND v65 1 + UP BND v66 1 + UP BND v67 1 + UP BND v68 1 + UP BND v69 1 + UP BND v70 1 + UP BND v71 1 + UP BND v72 1 + UP BND v73 1 + UP BND v74 1 + UP BND v75 1 + UP BND v76 1 + UP BND v77 1 + UP BND v78 1 + UP BND v79 1 + UP BND v80 1 + UP BND v81 1 + UP BND v82 1 + UP BND v83 1 + UP BND v84 1 + UP BND v85 1 + UP BND v86 1 + UP BND v87 1 + UP BND v88 1 + UP BND v89 1 + UP BND v90 1 + UP BND v91 1 + UP BND v92 1 + UP BND v93 1 + UP BND v94 1 + UP BND v95 1 + UP BND v96 1 + UP BND v97 1 + UP BND v98 1 + UP BND v99 1 + UP BND v1000 1 + UP BND v1001 1 + UP BND v1002 1 + UP BND v1003 1 + UP BND v1004 1 + UP BND v1005 1 + UP BND v1006 1 + UP BND v1007 1 + UP BND v1008 1 + UP BND v1009 1 + UP BND v1010 1 + UP BND v1011 1 + UP BND v1012 1 + UP BND v1013 1 + UP BND v1014 1 + UP BND v1015 1 + UP BND v1016 1 + UP BND v1017 1 + UP BND v1018 1 + UP BND v1019 1 + UP BND v1020 1 + UP BND v1021 1 + UP BND v1022 1 + UP BND v1023 1 + UP BND v1024 1 + UP BND v1025 1 + UP BND v1026 1 + UP BND v1027 1 + UP BND v1028 1 + UP BND v1029 1 + UP BND v1030 1 + UP BND v1031 1 + UP BND v1032 1 + UP BND v1033 1 + UP BND v1034 1 + UP BND v1035 1 + UP BND v1036 1 + UP BND v1037 1 + UP BND v1038 1 + UP BND v1039 1 + UP BND v1040 1 + UP BND v1041 1 + UP BND v1042 1 + UP BND v1043 1 + UP BND v1044 1 + UP BND v1045 1 + UP BND v1046 1 + UP BND v1047 1 + UP BND v1048 1 + UP BND v1049 1 + UP BND v1050 1 + UP BND v1051 1 + UP BND v1052 1 + UP BND v1053 1 + UP BND v1054 1 + UP BND v1055 1 + UP BND v1056 1 + UP BND v1057 1 + UP BND v1058 1 + UP BND v1059 1 + UP BND v1060 1 + UP BND v1061 1 + UP BND v1062 1 + UP BND v1063 1 + UP BND v1064 1 + UP BND v1065 1 + UP BND v1066 1 + UP BND v1067 1 + UP BND v1068 1 + UP BND v1069 1 + UP BND v1070 1 + UP BND v1071 1 + UP BND v1072 1 + UP BND v1073 1 + UP BND v1074 1 + UP BND v1075 1 + UP BND v1076 1 + UP BND v1077 1 + UP BND v1078 1 + UP BND v1079 1 + UP BND v1080 1 + UP BND v1081 1 + UP BND v1082 1 + UP BND v1083 1 + UP BND v1084 1 + UP BND v1085 1 + UP BND v1086 1 + UP BND v1087 1 + UP BND v1088 1 + UP BND v1089 1 + UP BND v1090 1 + UP BND v1091 1 + UP BND v1092 1 + UP BND v1093 1 + UP BND v1094 1 + UP BND v1095 1 + UP BND v1096 1 + UP BND v1097 1 + UP BND v1098 1 + UP BND v1099 1 + UP BND v1100 1 + UP BND v1101 1 + UP BND v1102 1 + UP BND v1103 1 + UP BND v1104 1 + UP BND v1105 1 + UP BND v1106 1 + UP BND v1107 1 + UP BND v1108 1 + UP BND v1109 1 + UP BND v1110 1 + UP BND v1111 1 + UP BND v1112 1 + UP BND v1113 1 + UP BND v1114 1 + UP BND v1115 1 + UP BND v1116 1 + UP BND v1117 1 + UP BND v1118 1 + UP BND v1119 1 + UP BND v1120 1 + UP BND v1121 1 + UP BND v1122 1 + UP BND v1123 1 + UP BND v1124 1 + UP BND v1125 1 + UP BND v1126 1 + UP BND v1127 1 + UP BND v1128 1 + UP BND v1129 1 + UP BND v1130 1 + UP BND v1131 1 + UP BND v1132 1 + UP BND v1133 1 + UP BND v1134 1 + UP BND v1135 1 + UP BND v1136 1 + UP BND v1137 1 + UP BND v1138 1 + UP BND v1139 1 + UP BND v1140 1 + UP BND v1141 1 + UP BND v1142 1 + UP BND v1143 1 + UP BND v1144 1 + UP BND v1145 1 + UP BND v1146 1 + UP BND v1147 1 + UP BND v1148 1 + UP BND v1149 1 + UP BND v1150 1 + UP BND v1151 1 + UP BND v1152 1 + UP BND v1153 1 + UP BND v1154 1 + UP BND v1155 1 + UP BND v1156 1 + UP BND v1157 1 + UP BND v1158 1 + UP BND v1159 1 + UP BND v1160 1 + UP BND v1161 1 + UP BND v1162 1 + UP BND v1163 1 + UP BND v1164 1 + UP BND v1165 1 + UP BND v1166 1 + UP BND v1167 1 + UP BND v1168 1 + UP BND v1169 1 + UP BND v1170 1 + UP BND v1171 1 + UP BND v1172 1 + UP BND v1173 1 + UP BND v1174 1 + UP BND v1175 1 + UP BND v1176 1 + UP BND v1177 1 + UP BND v1178 1 + UP BND v1179 1 + UP BND v1180 1 + UP BND v1181 1 + UP BND v1182 1 + UP BND v1183 1 + UP BND v1184 1 + UP BND v1185 1 + UP BND v1186 1 + UP BND v1187 1 + UP BND v1188 1 + UP BND v1189 1 + UP BND v1190 1 + UP BND v1191 1 + UP BND v1192 1 + UP BND v1193 1 + UP BND v1194 1 + UP BND v1195 1 + UP BND v1196 1 + UP BND v1197 1 + UP BND v1198 1 + UP BND v1199 1 + UP BND v1 1 + UP BND v2 1 + UP BND v3 1 + UP BND v4 1 + UP BND v5 1 + UP BND v6 1 + UP BND v7 1 + UP BND v8 1 + UP BND v9 1 + UP BND v1200 1 + UP BND v1201 1 + UP BND v1202 1 + UP BND v1203 1 + UP BND v1204 1 + UP BND v1205 1 + UP BND v1206 1 + UP BND v1207 1 + UP BND v1208 1 + UP BND v1209 1 + UP BND v1210 1 + UP BND v1211 1 + UP BND v1212 1 + UP BND v1213 1 + UP BND v1214 1 + UP BND v1215 1 + UP BND v1216 1 + UP BND v1217 1 + UP BND v1218 1 + UP BND v1219 1 + UP BND v1220 1 + UP BND v1221 1 + UP BND v1222 1 + UP BND v1223 1 + UP BND v1224 1 + UP BND v1225 1 + UP BND v1226 1 + UP BND v1227 1 + UP BND v1228 1 + UP BND v1229 1 + UP BND v1230 1 + UP BND v1231 1 + UP BND v1232 1 + UP BND v1233 1 + UP BND v1234 1 + UP BND v1235 1 + UP BND v1236 1 + UP BND v1237 1 + UP BND v1238 1 + UP BND v1239 1 + UP BND v1240 1 + UP BND v1241 1 + UP BND v1242 1 + UP BND v1243 1 + UP BND v1244 1 + UP BND v1245 1 + UP BND v1246 1 + UP BND v1247 1 + UP BND v1248 1 + UP BND v1249 1 + UP BND v1250 1 + UP BND v1251 1 + UP BND v1252 1 + UP BND v1253 1 + UP BND v1254 1 + UP BND v1255 1 + UP BND v1256 1 + UP BND v1257 1 + UP BND v1258 1 + UP BND v1259 1 + UP BND v1260 1 + UP BND v1261 1 + UP BND v1262 1 + UP BND v1263 1 + UP BND v1264 1 + UP BND v1265 1 + UP BND v1266 1 + UP BND v1267 1 + UP BND v1268 1 + UP BND v1269 1 + UP BND v1270 1 + UP BND v1271 1 + UP BND v1272 1 + UP BND v1273 1 + UP BND v1274 1 + UP BND v1275 1 + UP BND v1276 1 + UP BND v1277 1 + UP BND v1278 1 + UP BND v1279 1 + UP BND v1280 1 + UP BND v1281 1 + UP BND v1282 1 + UP BND v1283 1 + UP BND v1284 1 + UP BND v1285 1 + UP BND v1286 1 + UP BND v1287 1 + UP BND v1288 1 + UP BND v1289 1 + UP BND v1290 1 + UP BND v1291 1 + UP BND v1292 1 + UP BND v1293 1 + UP BND v1294 1 + UP BND v1295 1 + UP BND v1296 1 + UP BND v1297 1 + UP BND v1298 1 + UP BND v1299 1 + UP BND v1300 1 + UP BND v1301 1 + UP BND v1302 1 + UP BND v1303 1 + UP BND v1304 1 + UP BND v1305 1 + UP BND v1306 1 + UP BND v1307 1 + UP BND v1308 1 + UP BND v1309 1 + UP BND v1310 1 + UP BND v1311 1 + UP BND v1312 1 + UP BND v1313 1 + UP BND v1314 1 + UP BND v1315 1 + UP BND v1316 1 + UP BND v1317 1 + UP BND v1318 1 + UP BND v1319 1 + UP BND v1320 1 + UP BND v1321 1 + UP BND v1322 1 + UP BND v1323 1 + UP BND v1324 1 + UP BND v1325 1 + UP BND v1326 1 + UP BND v1327 1 + UP BND v1328 1 + UP BND v1329 1 + UP BND v1330 1 + UP BND v1331 1 + UP BND v1332 1 + UP BND v1333 1 + UP BND v1334 1 + UP BND v1335 1 + UP BND v1336 1 + UP BND v1337 1 + UP BND v1338 1 + UP BND v1339 1 + UP BND v100 1 + UP BND v101 1 + UP BND v102 1 + UP BND v103 1 + UP BND v104 1 + UP BND v105 1 + UP BND v106 1 + UP BND v107 1 + UP BND v108 1 + UP BND v109 1 + UP BND v110 1 + UP BND v111 1 + UP BND v112 1 + UP BND v113 1 + UP BND v114 1 + UP BND v115 1 + UP BND v116 1 + UP BND v117 1 + UP BND v118 1 + UP BND v119 1 + UP BND v120 1 + UP BND v121 1 + UP BND v122 1 + UP BND v123 1 + UP BND v124 1 + UP BND v125 1 + UP BND v126 1 + UP BND v127 1 + UP BND v128 1 + UP BND v129 1 + UP BND v130 1 + UP BND v131 1 + UP BND v132 1 + UP BND v133 1 + UP BND v134 1 + UP BND v135 1 + UP BND v136 1 + UP BND v137 1 + UP BND v138 1 + UP BND v139 1 + UP BND v140 1 + UP BND v141 1 + UP BND v142 1 + UP BND v143 1 + UP BND v144 1 + UP BND v145 1 + UP BND v146 1 + UP BND v147 1 + UP BND v148 1 + UP BND v149 1 + UP BND v150 1 + UP BND v151 1 + UP BND v152 1 + UP BND v153 1 + UP BND v154 1 + UP BND v155 1 + UP BND v156 1 + UP BND v157 1 + UP BND v158 1 + UP BND v159 1 + UP BND v160 1 + UP BND v161 1 + UP BND v162 1 + UP BND v163 1 + UP BND v164 1 + UP BND v165 1 + UP BND v166 1 + UP BND v167 1 + UP BND v168 1 + UP BND v169 1 + UP BND v170 1 + UP BND v171 1 + UP BND v172 1 + UP BND v173 1 + UP BND v174 1 + UP BND v175 1 + UP BND v176 1 + UP BND v177 1 + UP BND v178 1 + UP BND v179 1 + UP BND v180 1 + UP BND v181 1 + UP BND v182 1 + UP BND v183 1 + UP BND v184 1 + UP BND v185 1 + UP BND v186 1 + UP BND v187 1 + UP BND v188 1 + UP BND v189 1 + UP BND v190 1 + UP BND v191 1 + UP BND v192 1 + UP BND v193 1 + UP BND v194 1 + UP BND v195 1 + UP BND v196 1 + UP BND v197 1 + UP BND v198 1 + UP BND v199 1 + UP BND v200 1 + UP BND v201 1 + UP BND v202 1 + UP BND v203 1 + UP BND v204 1 + UP BND v205 1 + UP BND v206 1 + UP BND v207 1 + UP BND v208 1 + UP BND v209 1 + UP BND v210 1 + UP BND v211 1 + UP BND v212 1 + UP BND v213 1 + UP BND v214 1 + UP BND v215 1 + UP BND v216 1 + UP BND v217 1 + UP BND v218 1 + UP BND v219 1 + UP BND v220 1 + UP BND v221 1 + UP BND v222 1 + UP BND v223 1 + UP BND v224 1 + UP BND v225 1 + UP BND v226 1 + UP BND v227 1 + UP BND v228 1 + UP BND v229 1 + UP BND v230 1 + UP BND v231 1 + UP BND v232 1 + UP BND v233 1 + UP BND v234 1 + UP BND v235 1 + UP BND v236 1 + UP BND v237 1 + UP BND v238 1 + UP BND v239 1 + UP BND v240 1 + UP BND v241 1 + UP BND v242 1 + UP BND v243 1 + UP BND v244 1 + UP BND v245 1 + UP BND v246 1 + UP BND v247 1 + UP BND v248 1 + UP BND v249 1 + UP BND v250 1 + UP BND v251 1 + UP BND v252 1 + UP BND v253 1 + UP BND v254 1 + UP BND v255 1 + UP BND v256 1 + UP BND v257 1 + UP BND v258 1 + UP BND v259 1 + UP BND v260 1 + UP BND v261 1 + UP BND v262 1 + UP BND v263 1 + UP BND v264 1 + UP BND v265 1 + UP BND v266 1 + UP BND v267 1 + UP BND v268 1 + UP BND v269 1 + UP BND v270 1 + UP BND v271 1 + UP BND v272 1 + UP BND v273 1 + UP BND v274 1 + UP BND v275 1 + UP BND v276 1 + UP BND v277 1 + UP BND v278 1 + UP BND v279 1 + UP BND v280 1 + UP BND v281 1 + UP BND v282 1 + UP BND v283 1 + UP BND v284 1 + UP BND v285 1 + UP BND v286 1 + UP BND v287 1 + UP BND v288 1 + UP BND v289 1 + UP BND v290 1 + UP BND v291 1 + UP BND v292 1 + UP BND v293 1 + UP BND v294 1 + UP BND v295 1 + UP BND v296 1 + UP BND v297 1 + UP BND v298 1 + UP BND v299 1 + UP BND v300 1 + UP BND v301 1 + UP BND v302 1 + UP BND v303 1 + UP BND v304 1 + UP BND v305 1 + UP BND v306 1 + UP BND v307 1 + UP BND v308 1 + UP BND v309 1 + UP BND v310 1 + UP BND v311 1 + UP BND v312 1 + UP BND v313 1 + UP BND v314 1 + UP BND v315 1 + UP BND v316 1 + UP BND v317 1 + UP BND v318 1 + UP BND v319 1 + UP BND v320 1 + UP BND v321 1 + UP BND v322 1 + UP BND v323 1 + UP BND v324 1 + UP BND v325 1 + UP BND v326 1 + UP BND v327 1 + UP BND v328 1 + UP BND v329 1 + UP BND v330 1 + UP BND v331 1 + UP BND v332 1 + UP BND v333 1 + UP BND v334 1 + UP BND v335 1 + UP BND v336 1 + UP BND v337 1 + UP BND v338 1 + UP BND v339 1 + UP BND v340 1 + UP BND v341 1 + UP BND v342 1 + UP BND v343 1 + UP BND v344 1 + UP BND v345 1 + UP BND v346 1 + UP BND v347 1 + UP BND v348 1 + UP BND v349 1 + UP BND v350 1 + UP BND v351 1 + UP BND v352 1 + UP BND v353 1 + UP BND v354 1 + UP BND v355 1 + UP BND v356 1 + UP BND v357 1 + UP BND v358 1 + UP BND v359 1 + UP BND v360 1 + UP BND v361 1 + UP BND v362 1 + UP BND v363 1 + UP BND v364 1 + UP BND v365 1 + UP BND v366 1 + UP BND v367 1 + UP BND v368 1 + UP BND v369 1 + UP BND v370 1 + UP BND v371 1 + UP BND v372 1 + UP BND v373 1 + UP BND v374 1 + UP BND v375 1 + UP BND v376 1 + UP BND v377 1 + UP BND v378 1 + UP BND v379 1 + UP BND v380 1 + UP BND v381 1 + UP BND v382 1 + UP BND v383 1 + UP BND v384 1 + UP BND v385 1 + UP BND v386 1 + UP BND v387 1 + UP BND v388 1 + UP BND v389 1 + UP BND v390 1 + UP BND v391 1 + UP BND v392 1 + UP BND v393 1 + UP BND v394 1 + UP BND v395 1 + UP BND v396 1 + UP BND v397 1 + UP BND v398 1 + UP BND v399 1 + UP BND v400 1 + UP BND v401 1 + UP BND v402 1 + UP BND v403 1 + UP BND v404 1 + UP BND v405 1 + UP BND v406 1 + UP BND v407 1 + UP BND v408 1 + UP BND v409 1 + UP BND v410 1 + UP BND v411 1 + UP BND v412 1 + UP BND v413 1 + UP BND v414 1 + UP BND v415 1 + UP BND v416 1 + UP BND v417 1 + UP BND v418 1 + UP BND v419 1 + UP BND v420 1 + UP BND v421 1 + UP BND v422 1 + UP BND v423 1 + UP BND v424 1 + UP BND v425 1 + UP BND v426 1 + UP BND v427 1 + UP BND v428 1 + UP BND v429 1 + UP BND v430 1 + UP BND v431 1 + UP BND v432 1 + UP BND v433 1 + UP BND v434 1 + UP BND v435 1 + UP BND v436 1 + UP BND v437 1 + UP BND v438 1 + UP BND v439 1 + UP BND v440 1 + UP BND v441 1 + UP BND v442 1 + UP BND v443 1 + UP BND v444 1 + UP BND v445 1 + UP BND v446 1 + UP BND v447 1 + UP BND v448 1 + UP BND v449 1 + UP BND v450 1 + UP BND v451 1 + UP BND v452 1 + UP BND v453 1 + UP BND v454 1 + UP BND v455 1 + UP BND v456 1 + UP BND v457 1 + UP BND v458 1 + UP BND v459 1 + UP BND v460 1 + UP BND v461 1 + UP BND v462 1 + UP BND v463 1 + UP BND v464 1 + UP BND v465 1 + UP BND v466 1 + UP BND v467 1 + UP BND v468 1 + UP BND v469 1 + UP BND v470 1 + UP BND v471 1 + UP BND v472 1 + UP BND v473 1 + UP BND v474 1 + UP BND v475 1 + UP BND v476 1 + UP BND v477 1 + UP BND v478 1 + UP BND v479 1 + UP BND v480 1 + UP BND v481 1 + UP BND v482 1 + UP BND v483 1 + UP BND v484 1 + UP BND v485 1 + UP BND v486 1 + UP BND v487 1 + UP BND v488 1 + UP BND v489 1 + UP BND v490 1 + UP BND v491 1 + UP BND v492 1 + UP BND v493 1 + UP BND v494 1 + UP BND v495 1 + UP BND v496 1 + UP BND v497 1 + UP BND v498 1 + UP BND v499 1 + UP BND v500 1 + UP BND v501 1 + UP BND v502 1 + UP BND v503 1 + UP BND v504 1 + UP BND v505 1 + UP BND v506 1 + UP BND v507 1 + UP BND v508 1 + UP BND v509 1 + UP BND v510 1 + UP BND v511 1 + UP BND v512 1 + UP BND v513 1 + UP BND v514 1 + UP BND v515 1 + UP BND v516 1 + UP BND v517 1 + UP BND v518 1 + UP BND v519 1 + UP BND v520 1 + UP BND v521 1 + UP BND v522 1 + UP BND v523 1 + UP BND v524 1 + UP BND v525 1 + UP BND v526 1 + UP BND v527 1 + UP BND v528 1 + UP BND v529 1 + UP BND v530 1 + UP BND v531 1 + UP BND v532 1 + UP BND v533 1 + UP BND v534 1 + UP BND v535 1 + UP BND v536 1 + UP BND v537 1 + UP BND v538 1 + UP BND v539 1 + UP BND v540 1 + UP BND v541 1 + UP BND v542 1 + UP BND v543 1 + UP BND v544 1 + UP BND v545 1 + UP BND v546 1 + UP BND v547 1 + UP BND v548 1 + UP BND v549 1 + UP BND v550 1 + UP BND v551 1 + UP BND v552 1 + UP BND v553 1 + UP BND v554 1 + UP BND v555 1 + UP BND v556 1 + UP BND v557 1 + UP BND v558 1 + UP BND v559 1 + UP BND v560 1 + UP BND v561 1 + UP BND v562 1 + UP BND v563 1 + UP BND v564 1 + UP BND v565 1 + UP BND v566 1 + UP BND v567 1 + UP BND v568 1 + UP BND v569 1 + UP BND v570 1 + UP BND v571 1 + UP BND v572 1 + UP BND v573 1 + UP BND v574 1 + UP BND v575 1 + UP BND v576 1 + UP BND v577 1 + UP BND v578 1 + UP BND v579 1 + UP BND v580 1 + UP BND v581 1 + UP BND v582 1 + UP BND v583 1 + UP BND v584 1 + UP BND v585 1 + UP BND v586 1 + UP BND v587 1 + UP BND v588 1 + UP BND v589 1 + UP BND v590 1 + UP BND v591 1 + UP BND v592 1 + UP BND v593 1 + UP BND v594 1 + UP BND v595 1 + UP BND v596 1 + UP BND v597 1 + UP BND v598 1 + UP BND v599 1 + UP BND v600 1 + UP BND v601 1 + UP BND v602 1 + UP BND v603 1 + UP BND v604 1 + UP BND v605 1 + UP BND v606 1 + UP BND v607 1 + UP BND v608 1 + UP BND v609 1 + UP BND v610 1 + UP BND v611 1 + UP BND v612 1 + UP BND v613 1 + UP BND v614 1 + UP BND v615 1 + UP BND v616 1 + UP BND v617 1 + UP BND v618 1 + UP BND v619 1 + UP BND v620 1 + UP BND v621 1 + UP BND v622 1 + UP BND v623 1 + UP BND v624 1 + UP BND v625 1 + UP BND v626 1 + UP BND v627 1 + UP BND v628 1 + UP BND v629 1 + UP BND v630 1 + UP BND v631 1 + UP BND v632 1 + UP BND v633 1 + UP BND v634 1 + UP BND v635 1 + UP BND v636 1 + UP BND v637 1 + UP BND v638 1 + UP BND v639 1 + UP BND v640 1 + UP BND v641 1 + UP BND v642 1 + UP BND v643 1 + UP BND v644 1 + UP BND v645 1 + UP BND v646 1 + UP BND v647 1 + UP BND v648 1 + UP BND v649 1 + UP BND v650 1 + UP BND v651 1 + UP BND v652 1 + UP BND v653 1 + UP BND v654 1 + UP BND v655 1 + UP BND v656 1 + UP BND v657 1 + UP BND v658 1 + UP BND v659 1 + UP BND v660 1 + UP BND v661 1 + UP BND v662 1 + UP BND v663 1 + UP BND v664 1 + UP BND v665 1 + UP BND v666 1 + UP BND v667 1 + UP BND v668 1 + UP BND v669 1 + UP BND v670 1 + UP BND v671 1 + UP BND v672 1 + UP BND v673 1 + UP BND v674 1 + UP BND v675 1 + UP BND v676 1 + UP BND v677 1 + UP BND v678 1 + UP BND v679 1 + UP BND v680 1 + UP BND v681 1 + UP BND v682 1 + UP BND v683 1 + UP BND v684 1 + UP BND v685 1 + UP BND v686 1 + UP BND v687 1 + UP BND v688 1 + UP BND v689 1 + UP BND v690 1 + UP BND v691 1 + UP BND v692 1 + UP BND v693 1 + UP BND v694 1 + UP BND v695 1 + UP BND v696 1 + UP BND v697 1 + UP BND v698 1 + UP BND v699 1 + UP BND v700 1 + UP BND v701 1 + UP BND v702 1 + UP BND v703 1 + UP BND v704 1 + UP BND v705 1 + UP BND v706 1 + UP BND v707 1 + UP BND v708 1 + UP BND v709 1 + UP BND v710 1 + UP BND v711 1 + UP BND v712 1 + UP BND v713 1 + UP BND v714 1 + UP BND v715 1 + UP BND v716 1 + UP BND v717 1 + UP BND v718 1 + UP BND v719 1 + UP BND v720 1 + UP BND v721 1 + UP BND v722 1 + UP BND v723 1 + UP BND v724 1 + UP BND v725 1 + UP BND v726 1 + UP BND v727 1 + UP BND v728 1 + UP BND v729 1 + UP BND v730 1 + UP BND v731 1 + UP BND v732 1 + UP BND v733 1 + UP BND v734 1 + UP BND v735 1 + UP BND v736 1 + UP BND v737 1 + UP BND v738 1 + UP BND v739 1 + UP BND v740 1 + UP BND v741 1 + UP BND v742 1 + UP BND v743 1 + UP BND v744 1 + UP BND v745 1 + UP BND v746 1 + UP BND v747 1 + UP BND v748 1 + UP BND v749 1 + UP BND v750 1 + UP BND v751 1 + UP BND v752 1 + UP BND v753 1 + UP BND v754 1 + UP BND v755 1 + UP BND v756 1 + UP BND v757 1 + UP BND v758 1 + UP BND v759 1 + UP BND v760 1 + UP BND v761 1 + UP BND v762 1 + UP BND v763 1 + UP BND v764 1 + UP BND v765 1 + UP BND v766 1 + UP BND v767 1 + UP BND v768 1 + UP BND v769 1 + UP BND v770 1 + UP BND v771 1 + UP BND v772 1 + UP BND v773 1 + UP BND v774 1 + UP BND v775 1 + UP BND v776 1 + UP BND v777 1 + UP BND v778 1 + UP BND v779 1 + UP BND v780 1 + UP BND v781 1 + UP BND v782 1 + UP BND v783 1 + UP BND v784 1 + UP BND v785 1 + UP BND v786 1 + UP BND v787 1 + UP BND v788 1 + UP BND v789 1 + UP BND v790 1 + UP BND v791 1 + UP BND v792 1 + UP BND v793 1 + UP BND v794 1 + UP BND v795 1 + UP BND v796 1 + UP BND v797 1 + UP BND v798 1 + UP BND v799 1 + UP BND v800 1 + UP BND v801 1 + UP BND v802 1 + UP BND v803 1 + UP BND v804 1 + UP BND v805 1 + UP BND v806 1 + UP BND v807 1 + UP BND v808 1 + UP BND v809 1 + UP BND v810 1 + UP BND v811 1 + UP BND v812 1 + UP BND v813 1 + UP BND v814 1 + UP BND v815 1 + UP BND v816 1 + UP BND v817 1 + UP BND v818 1 + UP BND v819 1 + UP BND v820 1 + UP BND v821 1 + UP BND v822 1 + UP BND v823 1 + UP BND v824 1 + UP BND v825 1 + UP BND v826 1 + UP BND v827 1 + UP BND v828 1 + UP BND v829 1 + UP BND v830 1 + UP BND v831 1 + UP BND v832 1 + UP BND v833 1 + UP BND v834 1 + UP BND v835 1 + UP BND v836 1 + UP BND v837 1 + UP BND v838 1 + UP BND v839 1 + UP BND v840 1 + UP BND v841 1 + UP BND v842 1 + UP BND v843 1 + UP BND v844 1 + UP BND v845 1 + UP BND v846 1 + UP BND v847 1 + UP BND v848 1 + UP BND v849 1 + UP BND v850 1 + UP BND v851 1 + UP BND v852 1 + UP BND v853 1 + UP BND v854 1 + UP BND v855 1 + UP BND v856 1 + UP BND v857 1 + UP BND v858 1 + UP BND v859 1 + UP BND v860 1 + UP BND v861 1 + UP BND v862 1 + UP BND v863 1 + UP BND v864 1 + UP BND v865 1 + UP BND v866 1 + UP BND v867 1 + UP BND v868 1 + UP BND v869 1 + UP BND v870 1 + UP BND v871 1 + UP BND v872 1 + UP BND v873 1 + UP BND v874 1 + UP BND v875 1 + UP BND v876 1 + UP BND v877 1 + UP BND v878 1 + UP BND v879 1 + UP BND v880 1 + UP BND v881 1 + UP BND v882 1 + UP BND v883 1 + UP BND v884 1 + UP BND v885 1 + UP BND v886 1 + UP BND v887 1 + UP BND v888 1 + UP BND v889 1 + UP BND v890 1 + UP BND v891 1 + UP BND v892 1 + UP BND v893 1 + UP BND v894 1 + UP BND v895 1 + UP BND v896 1 + UP BND v897 1 + UP BND v898 1 + UP BND v899 1 + UP BND v900 1 + UP BND v901 1 + UP BND v902 1 + UP BND v903 1 + UP BND v904 1 + UP BND v905 1 + UP BND v906 1 + UP BND v907 1 + UP BND v908 1 + UP BND v909 1 + UP BND v910 1 + UP BND v911 1 + UP BND v912 1 + UP BND v913 1 + UP BND v914 1 + UP BND v915 1 + UP BND v916 1 + UP BND v917 1 + UP BND v918 1 + UP BND v919 1 + UP BND v920 1 + UP BND v921 1 + UP BND v922 1 + UP BND v923 1 + UP BND v924 1 + UP BND v925 1 + UP BND v926 1 + UP BND v927 1 + UP BND v928 1 + UP BND v929 1 + UP BND v930 1 + UP BND v931 1 + UP BND v932 1 + UP BND v933 1 + UP BND v934 1 + UP BND v935 1 + UP BND v936 1 + UP BND v937 1 + UP BND v938 1 + UP BND v939 1 + UP BND v940 1 + UP BND v941 1 + UP BND v942 1 + UP BND v943 1 + UP BND v944 1 + UP BND v945 1 + UP BND v946 1 + UP BND v947 1 + UP BND v948 1 + UP BND v949 1 + UP BND v950 1 + UP BND v951 1 + UP BND v952 1 + UP BND v953 1 + UP BND v954 1 + UP BND v955 1 + UP BND v956 1 + UP BND v957 1 + UP BND v958 1 + UP BND v959 1 + UP BND v960 1 + UP BND v961 1 + UP BND v962 1 + UP BND v963 1 + UP BND v964 1 + UP BND v965 1 + UP BND v966 1 + UP BND v967 1 + UP BND v968 1 + UP BND v969 1 + UP BND v970 1 + UP BND v971 1 + UP BND v972 1 + UP BND v973 1 + UP BND v974 1 + UP BND v975 1 + UP BND v976 1 + UP BND v977 1 + UP BND v978 1 + UP BND v979 1 + UP BND v980 1 + UP BND v981 1 + UP BND v982 1 + UP BND v983 1 + UP BND v984 1 + UP BND v985 1 + UP BND v986 1 + UP BND v987 1 + UP BND v988 1 + UP BND v989 1 + UP BND v990 1 + UP BND v991 1 + UP BND v992 1 + UP BND v993 1 + UP BND v994 1 + UP BND v995 1 + UP BND v996 1 + UP BND v997 1 + UP BND v998 1 + UP BND v999 1 +ENDATA diff --git a/src/tests/util/lp/test_files/netlib.tar.gz b/src/tests/util/lp/test_files/netlib.tar.gz new file mode 100644 index 0000000000..3eccb97282 Binary files /dev/null and b/src/tests/util/lp/test_files/netlib.tar.gz differ diff --git a/src/util/lp/CMakeLists.txt b/src/util/lp/CMakeLists.txt new file mode 100644 index 0000000000..ca24943a74 --- /dev/null +++ b/src/util/lp/CMakeLists.txt @@ -0,0 +1 @@ +add_library(lp OBJECT lp.cpp) diff --git a/src/util/lp/binary_heap_priority_queue.h b/src/util/lp/binary_heap_priority_queue.h new file mode 100644 index 0000000000..6300820f2f --- /dev/null +++ b/src/util/lp/binary_heap_priority_queue.h @@ -0,0 +1,230 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +namespace lean { +using std::vector; + // the elements with the smallest priority are dequeued first +template +class binary_heap_priority_queue { + vector m_priorities; + + // indexing for A starts from 1 + vector m_heap; // keeps the elements of the queue + vector m_heap_inverse; // o = m_heap[m_heap_inverse[o]] + unsigned m_heap_size = 0; + + // is is the child place in heap + void swap_with_parent(unsigned i) { + unsigned parent = m_heap[i >> 1]; + put_at(i >> 1, m_heap[i]); + put_at(i, parent); + } + + + void put_at(unsigned i, unsigned h) { + m_heap[i] = h; + m_heap_inverse[h] = i; + } + + void decrease_priority(unsigned o, T newPriority) { + m_priorities[o] = newPriority; + int i = m_heap_inverse[o]; + while (i > 1) { + if (m_priorities[m_heap[i]] < m_priorities[m_heap[i >> 1]]) + swap_with_parent(i); + else + break; + i >>= 1; + } + } + +public: + bool is_consistent() const { + for (int i = 0; i < m_heap_inverse.size(); i++) { + int i_index = m_heap_inverse[i]; + lean_assert(i_index <= static_cast(m_heap_size)); + lean_assert(i_index == -1 || m_heap[i_index] == i); + } + for (unsigned i = 1; i < m_heap_size; i++) { + unsigned ch = i << 1; + for (int k = 0; k < 2; k++) { + if (ch > m_heap_size) break; + if (!(m_priorities[m_heap[i]] <= m_priorities[m_heap[ch]])){ + cout << "m_heap_size = " << m_heap_size << endl; + cout << "i = " << i << endl; + cout << "m_heap[i] = " << m_heap[i] << endl; + cout << "ch = " << ch << endl; + cout << "m_heap[ch] = " << m_heap[ch] << endl; + cout << "m_priorities[m_heap[i]] = " << m_priorities[m_heap[i]] << endl; + cout << "m_priorities[m_heap[ch]] = " << m_priorities[m_heap[ch]]<< endl; + return false; + } + ch++; + } + } + return true; + } + +public: + void remove(unsigned o) { + T priority_of_o = m_priorities[o]; + int o_in_heap = m_heap_inverse[o]; + if (o_in_heap == -1) { + return; // nothing to do + } + lean_assert(o_in_heap <= m_heap_size); + if (o_in_heap < m_heap_size) { + put_at(o_in_heap, m_heap[m_heap_size--]); + if (m_priorities[m_heap[o_in_heap]] > priority_of_o) { + fix_heap_under(o_in_heap); + } else { // we need to propogate the m_heap[o_in_heap] up + unsigned i = o_in_heap; + while (i > 1) { + unsigned ip = i >> 1; + if (m_priorities[m_heap[i]] < m_priorities[m_heap[ip]]) + swap_with_parent(i); + else + break; + i = ip; + } + } + } else { + lean_assert(o_in_heap == m_heap_size); + m_heap_size--; + } + m_heap_inverse[o] = -1; + // lean_assert(is_consistent()); + } + unsigned size() const { return m_heap_size; } + binary_heap_priority_queue(): m_heap(1) {} // the empty constructror + // n is the initial queue capacity. + // The capacity will be enlarged two times automatically if needed + binary_heap_priority_queue(unsigned n) : + m_priorities(n), + m_heap(n + 1), // because the indexing for A starts from 1 + m_heap_inverse(n, -1) + { } + + void clear() { + m_heap_size = 0; + } + + void resize(unsigned n) { + m_priorities.resize(n); + m_heap.resize(n + 1); + m_heap_inverse.resize(n, -1); + } + + void put_to_heap(unsigned i, unsigned o) { + m_heap[i] = o; + m_heap_inverse[o] = i; + } + + void enqueue_new(unsigned o, const T& priority) { + m_heap_size++; + int i = m_heap_size; + lean_assert(o < m_priorities.size()); + m_priorities[o] = priority; + put_at(i, o); + while (i > 1 && m_priorities[m_heap[i >> 1]] > priority) { + swap_with_parent(i); + i >>= 1; + } + } + // This method can work with an element that is already in the queue. + // In this case the priority will be changed and the queue adjusted. + void enqueue(unsigned o, const T & priority) { + if (o >= m_priorities.size()) { + resize(o << 1); // make the size twice larger + } + if (m_heap_inverse[o] == -1) + enqueue_new(o, priority); + else + change_priority_for_existing(o, priority); + } + + void change_priority_for_existing(unsigned o, const T & priority) { + if (m_priorities[o] > priority) { + decrease_priority(o, priority); + } else { + m_priorities[o] = priority; + fix_heap_under(m_heap_inverse[o]); + } + } + + T get_priority(unsigned o) const { + lean_assert(m_priorities.size() > o); + return m_priorities[o]; + } + bool is_empty() const { + return m_heap_size == 0; + } + + /// return the first element of the queue and removes it from the queue + unsigned dequeue_and_get_priority(T & priority) { + if (m_heap_size == 0) { + throw "invalid size"; + } + int ret = m_heap[1]; + priority = m_priorities[ret]; + put_the_last_at_the_top_and_fix_the_heap(); + return ret; + } + + void fix_heap_under(unsigned i) { + while (true) { + int smallest = i; + int l = i << 1; + if (l <= m_heap_size && m_priorities[m_heap[l]] < m_priorities[m_heap[i]]) + smallest = l; + int r = l + 1; + if (r <= m_heap_size && m_priorities[m_heap[r]] < m_priorities[m_heap[smallest]]) + smallest = r; + if (smallest != i) + swap_with_parent(smallest); + else + break; + i = smallest; + } + } + + void put_the_last_at_the_top_and_fix_the_heap() { + if (m_heap_size > 1) { + put_at(1, m_heap[m_heap_size--]); + fix_heap_under(1); + } else { + m_heap_size--; + } + } + /// return the first element of the queue and removes it from the queue + unsigned dequeue() { + lean_assert(m_heap_size); + int ret = m_heap[1]; + put_the_last_at_the_top_and_fix_the_heap(); + m_heap_inverse[ret] = -1; + return ret; + } + + void print() { + vector index; + vector prs; + while (size()) { + T prior; + int j = dequeue_and_get_priority(prior); + index.push_back(j); + prs.push_back(prior); + cout << "(" << j << ", " << prior << ")"; + } + cout << endl; + // restore the queue + for (int i = 0; i < index.size(); i++) + enqueue(index[i], prs[i]); + } +}; +} diff --git a/src/util/lp/binary_heap_upair_queue.h b/src/util/lp/binary_heap_upair_queue.h new file mode 100644 index 0000000000..59f0ed941d --- /dev/null +++ b/src/util/lp/binary_heap_upair_queue.h @@ -0,0 +1,142 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE + + Author: Lev Nachmanson +*/ + +#pragma once +#include "util/lp/binary_heap_priority_queue.h" +#include +#include +#include +#include +#include +typedef std::pair upair; + +namespace lean { +template +class binary_heap_upair_queue { + binary_heap_priority_queue m_q; + unordered_map m_pairs_to_index; + vector m_pairs; // inverse to index + std::vector m_available_spots; +public: + binary_heap_upair_queue(unsigned size) : m_q(size), m_pairs(size) { + lean_assert(size); + for (unsigned i = 0; i < size; i++) + m_available_spots.push_back(i); + } + + unsigned dequeue_available_spot() { + lean_assert(m_available_spots.empty() == false); + unsigned ret = m_available_spots.back(); + m_available_spots.pop_back(); + return ret; + } + + void remove(unsigned i, unsigned j) { + upair p(i, j); + auto it = m_pairs_to_index.find(p); + if (it == m_pairs_to_index.end()) + return; // nothing to do + m_q.remove(it->second); + m_available_spots.push_back(it->second); + m_pairs_to_index.erase(it); + } + + + bool ij_index_is_new(unsigned ij_index) const { + for (auto it : m_pairs_to_index) { + if (it.second == ij_index) + return false; + } + return true; + } + + void enqueue(unsigned i, unsigned j, const T & priority) { + upair p(i, j); + auto it = m_pairs_to_index.find(p); + unsigned ij_index; + if (it == m_pairs_to_index.end()) { + // it is a new pair, let us find a spot for it + if (m_available_spots.empty()) { + // we ran out of empty spots + unsigned size_was = m_pairs.size(); + unsigned new_size = size_was << 1; + for (unsigned i = size_was; i < new_size; i++) + m_available_spots.push_back(i); + m_pairs.resize(new_size); + } + ij_index = dequeue_available_spot(); + // lean_assert(ij_indexsecond; + } + m_q.enqueue(ij_index, priority); + } + + void dequeue(unsigned & i, unsigned &j) { + lean_assert(!m_q.is_empty()); + unsigned ij_index = m_q.dequeue(); + upair & p = m_pairs[ij_index]; + i = p.first; + j = p.second; + m_available_spots.push_back(ij_index); + m_pairs_to_index.erase(p); + } + + bool is_empty() const { + return m_q.is_empty(); + } + + unsigned size() const { + return m_q.size(); + } + + bool contains(unsigned i, unsigned j) const { + return m_pairs_to_index.find(std::make_pair(i, j)) != m_pairs_to_index.end(); + } + + T get_priority(unsigned i, unsigned j) const { + auto it = m_pairs_to_index.find(std::make_pair(i, j)); + if (it == m_pairs_to_index.end()) + return T(0xFFFFFF); // big number + return m_q.get_priority(it->second); + } + + bool pair_to_index_is_a_bijection() const { + std::set tmp; + for (auto p : m_pairs_to_index) { + unsigned j = p.second; + auto it = tmp.find(j); + if (it != tmp.end()) { + cout << "for pair (" << p.first.first << ", " << p.first.second << "), the index " << j << " is already inside " << endl; + lean_assert(false); + } else { + tmp.insert(j); + } + } + return true; + } + + bool available_spots_are_correct() const { + std::set tmp; + for (auto p : m_available_spots){ + tmp.insert(p); + } + if (tmp.size() != m_available_spots.size()) + return false; + for (auto it : m_pairs_to_index) + if (tmp.find(it.second) != tmp.end()) + return false; + return true; + } + + bool is_correct() const { + return m_q.is_consistent() && pair_to_index_is_a_bijection() && available_spots_are_correct(); + } +}; +} diff --git a/src/util/lp/breakpoint.h b/src/util/lp/breakpoint.h new file mode 100644 index 0000000000..12fc29ed80 --- /dev/null +++ b/src/util/lp/breakpoint.h @@ -0,0 +1,22 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once + +namespace lean { +enum breakpoint_type { + low_break, upper_break, fixed_break +}; +template +struct breakpoint { + unsigned m_j; // the basic column + breakpoint_type m_type; + X m_delta; + breakpoint(){} + breakpoint(unsigned j, X delta, breakpoint_type type):m_j(j), m_type(type), m_delta(delta) {} +}; +} diff --git a/src/util/lp/canonic_left_side.h b/src/util/lp/canonic_left_side.h new file mode 100644 index 0000000000..bc898200a1 --- /dev/null +++ b/src/util/lp/canonic_left_side.h @@ -0,0 +1,84 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include +#include + +namespace lean { + typedef unsigned var_index; + typedef unsigned constraint_index; + enum lconstraint_kind { + LE = -2, LT = -1 , GE = 2, GT = 1, EQ = 0 + }; + + class lar_normalized_constraint; // forward definition + bool compare(const pair & a, const pair & b) { + return a.second < b.second; + } + + class canonic_left_side { + public: + int m_row_index = -1; + int m_column_index = -1; // this is the column of the left side variable in the matrix + std::vector> m_coeffs; + column_info m_column_info; + lar_normalized_constraint * m_low_bound_witness = nullptr; + lar_normalized_constraint * m_upper_bound_witness = nullptr; + + canonic_left_side(buffer> buffer) { + for (auto it : buffer) { + if (numeric_traits::is_zero(it.first)) continue; + m_coeffs.push_back(it); + } + + std::sort(m_coeffs.begin(), m_coeffs.end(), compare); + normalize(); + } + + void set_name(string name) { + m_column_info.set_name(name); + } + + unsigned size() const { return m_coeffs.size(); } + + void normalize() { + if (m_coeffs.size() == 0) return; + auto t = m_coeffs[0].first; + for (auto & it : m_coeffs) + it.first /= t; + } + + bool operator==(const canonic_left_side& a) const { + if (m_coeffs.size() != a.m_coeffs.size()) return false; + for (unsigned i = 0; i < m_coeffs.size(); i++) { + if (m_coeffs[i] != a.m_coeffs[i]) + return false; + } + return true; + } + + std::size_t hash_of_ls() const { + std::size_t ret = 0; + std::hash> hash_fun; + for (auto v : m_coeffs) { + ret |= (hash_fun(v) << 2); + } + return ret; + } + }; + + struct hash_and_equal_of_canonic_left_side_struct { + std::size_t operator() (const canonic_left_side* ls) const { + return ls->hash_of_ls(); + } + bool operator() (const canonic_left_side* a, const canonic_left_side* b) const { + return (*a) == (*b); + } + }; +} diff --git a/src/util/lp/column_info.h b/src/util/lp/column_info.h new file mode 100644 index 0000000000..6df23f8596 --- /dev/null +++ b/src/util/lp/column_info.h @@ -0,0 +1,199 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include "util/lp/lp_primal_core_solver.h" +#include "util/lp/lp_solver.h" +#include +#include +#include +#include +namespace lean { +using std::vector; +using std::tuple; + +template +class column_info { + string m_name; + bool m_low_bound_is_set = false; + bool m_low_bound_is_strict = false; + bool m_upper_bound_is_set = false; + bool m_upper_bound_is_strict = false; + T m_low_bound; + T m_upper_bound; + T m_cost = numeric_traits::zero(); + T m_fixed_value; + bool m_is_fixed = false; + +public: + column_type get_column_type() { + if (m_is_fixed) { + return column_type::fixed; + } + + if (m_low_bound_is_set) { + return m_upper_bound_is_set? boxed: low_bound; + } + // we are flipping the bounds! + return m_upper_bound_is_set? low_bound: free_column; + } + + column_type get_column_type_no_flipping() { + if (m_is_fixed) { + return column_type::fixed; + } + + if (m_low_bound_is_set) { + return m_upper_bound_is_set? boxed: low_bound; + } + // we are flipping the bounds! + return m_upper_bound_is_set? upper_bound + : free_column; + } + + T get_low_bound() const { + lean_assert(m_low_bound_is_set); + return m_low_bound; + } + T get_upper_bound() const { + lean_assert(m_upper_bound_is_set); + return m_upper_bound; + } + + bool low_bound_is_set() const { + return m_low_bound_is_set; + } + + bool upper_bound_is_set() const { + return m_upper_bound_is_set; + } + + T get_shift() { + if (is_fixed()) { + return m_fixed_value; + } + if (is_flipped()){ + return m_upper_bound; + } + return m_low_bound_is_set? m_low_bound : numeric_traits::zero(); + } + + bool is_flipped() { + return m_upper_bound_is_set && !m_low_bound_is_set; + } + + bool adjusted_low_bound_is_set() { + return !is_flipped()? low_bound_is_set(): upper_bound_is_set(); + } + + bool adjusted_upper_bound_is_set() { + return !is_flipped()? upper_bound_is_set(): low_bound_is_set(); + } + + T get_adjusted_upper_bound() { + return get_upper_bound() - get_low_bound(); + } + + bool is_fixed() const { + return m_is_fixed; + } + + bool is_free() { + return !m_low_bound_is_set && !m_upper_bound_is_set; + } + + void set_fixed_value(T v) { + m_is_fixed = true; + m_fixed_value = v; + } + + T get_fixed_value() const { + lean_assert(m_is_fixed) + return m_fixed_value; + } + + T get_cost() const { + return m_cost; + } + + void set_cost(T const & cost) { + m_cost = cost; + } + + void set_name(string const & s) { + m_name = s; + } + + string get_name() const { + return m_name; + } + + void set_low_bound(T const & l) { + m_low_bound = l; + m_low_bound_is_set = true; + } + + void set_upper_bound(T const & l) { + m_upper_bound = l; + m_upper_bound_is_set = true; + } + + void unset_low_bound() { + m_low_bound_is_set = false; + } + + void unset_upper_bound() { + m_upper_bound_is_set = false; + } + + void unset_fixed() { + m_is_fixed = false; + } + + bool low_bound_holds(T v) { + return !low_bound_is_set() || v >= m_low_bound -T(0.0000001); + } + + bool upper_bound_holds(T v) { + return !upper_bound_is_set() || v <= m_upper_bound + T(0.000001); + } + + bool bounds_hold(T v) { + return low_bound_holds(v) && upper_bound_holds(v); + } + + bool adjusted_bounds_hold(T v) { + return adjusted_low_bound_holds(v) && adjusted_upper_bound_holds(v); + } + + bool adjusted_low_bound_holds(T v) { + return !adjusted_low_bound_is_set() || v >= -T(0.0000001); + } + + bool adjusted_upper_bound_holds(T v) { + return !adjusted_upper_bound_is_set() || v <= get_adjusted_upper_bound() + T(0.000001); + } + bool is_infeasible() { + return upper_bound_is_set() && low_bound_is_set() && get_upper_bound() < get_low_bound(); + } + bool low_bound_is_strict() const { + return m_low_bound_is_strict; + } + + void set_low_bound_strict(bool val) { + m_low_bound_is_strict = val; + } + + bool upper_bound_is_strict() const { + return m_upper_bound_is_strict; + } + + void set_upper_bound_strict(bool val) { + m_upper_bound_is_strict = val; + } +}; +} diff --git a/src/util/lp/core_solver_pretty_printer.h b/src/util/lp/core_solver_pretty_printer.h new file mode 100644 index 0000000000..be4681f6c1 --- /dev/null +++ b/src/util/lp/core_solver_pretty_printer.h @@ -0,0 +1,388 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include +namespace lean { +template class lp_core_solver_base; // forward definition + +template +class core_solver_pretty_printer { + lp_core_solver_base & m_core_solver; + vector m_column_widths; + vector> m_A; + vector> m_signs; + vector m_costs; + vector m_cost_signs; + vector m_lows; // low bounds + vector m_upps; // upper bounds + vector m_lows_signs; + vector m_upps_signs; + unsigned m_rs_width; + vector m_rs; + unsigned m_title_width; + std::string m_cost_title; + std::string m_basis_heading_title; + std::string m_x_title; + std::string m_low_bounds_title = "low"; + std::string m_upp_bounds_title = "upp"; + std::string m_exact_norm_title = "exact cn"; + std::string m_approx_norm_title = "approx cn"; + + + unsigned ncols() { return m_core_solver.m_A.column_count(); } + unsigned nrows() { return m_core_solver.m_A.row_count(); } + unsigned m_artificial_start = UINT_MAX; + T * m_w_buff; + T * m_ed_buff; + vector m_exact_column_norms; + +public: + core_solver_pretty_printer(lp_core_solver_base & core_solver): m_core_solver(core_solver), + m_column_widths(core_solver.m_A.column_count(), 0), + m_A(core_solver.m_A.row_count(), vector(core_solver.m_A.column_count(), "")), + m_signs(core_solver.m_A.row_count(), vector(core_solver.m_A.column_count(), " ")), + m_costs(ncols(), ""), + m_cost_signs(ncols(), " "), + m_rs(ncols(), zero_of_type()) { + m_w_buff = new T[m_core_solver.m_m]; + m_ed_buff = new T[m_core_solver.m_m]; + m_core_solver.save_state(m_w_buff, m_ed_buff); + init_m_A_and_signs(); + init_costs(); + init_column_widths(); + init_rs_width(); + m_cost_title = "costs"; + m_basis_heading_title = "heading"; + m_x_title = "x*"; + m_title_width = std::max(std::max(m_cost_title.size(), std::max(m_basis_heading_title.size(), m_x_title.size())), m_approx_norm_title.size()); + } + + void init_costs() { + vector local_y(m_core_solver.m_m); + m_core_solver.solve_yB(local_y); + for (unsigned i = 0; i < ncols(); i++) { + if (m_core_solver.m_basis_heading[i] < 0) { + T t = m_core_solver.m_costs[i] - m_core_solver.m_A.dot_product_with_column(local_y, i); + set_coeff(m_costs, m_cost_signs, i, t, m_core_solver.column_name(i)); + } + } + } + + ~core_solver_pretty_printer() { + m_core_solver.restore_state(m_w_buff, m_ed_buff); + delete [] m_w_buff; + delete [] m_ed_buff; + } + void init_rs_width() { + m_rs_width = T_to_string(m_core_solver.get_cost()).size(); + for (unsigned i = 0; i < nrows(); i++) { + auto wt = T_to_string(m_rs[i]).size(); + if (wt > m_rs_width) { + m_rs_width = wt; + } + } + } + + T current_column_norm() { + T ret = zero_of_type(); + for (T & ed : m_core_solver.m_ed) + ret += ed * ed; + return ret; + } + + void init_m_A_and_signs() { + for (unsigned column = 0; column < ncols(); column++) { + m_core_solver.solve_Bd(column); // puts the result into m_core_solver.m_ed + string name = m_core_solver.column_name(column); + for (unsigned row = 0; row < nrows(); row ++) { + set_coeff( + m_A[row], + m_signs[row], + column, + m_core_solver.m_ed[row], + name); + m_rs[row] += m_core_solver.m_ed[row] * m_core_solver.m_x[column]; + } + m_exact_column_norms.push_back(current_column_norm() + 1); + } + } + + void init_column_widths() { + for (unsigned i = 0; i < ncols(); i++) { + m_column_widths[i] = get_column_width(i); + } + } + + void adjust_width_with_low_bound(unsigned column, unsigned & w) { + if (!m_core_solver.low_bounds_are_set()) return; + w = std::max(w, (unsigned)T_to_string(m_core_solver.low_bound_value(column)).size()); + } + void adjust_width_with_upper_bound(unsigned column, unsigned & w) { + w = std::max(w, (unsigned)T_to_string(m_core_solver.upper_bound_value(column)).size()); + } + + void adjust_width_with_bounds(unsigned column, unsigned & w) { + switch (m_core_solver.get_column_type(column)) { + case fixed: + case boxed: + adjust_width_with_low_bound(column, w); + adjust_width_with_upper_bound(column, w); + break; + case low_bound: + adjust_width_with_low_bound(column, w); + break; + case upper_bound: + adjust_width_with_upper_bound(column, w); + break; + case free_column: + break; + default: + lean_assert(false); + break; + } + } + + void adjust_width_with_basis_heading(unsigned column, unsigned & w) { + w = std::max(w, (unsigned)T_to_string(m_core_solver.m_basis_heading[column]).size()); + } + + unsigned get_column_width(unsigned column) { + unsigned w = std::max(m_costs[column].size(), T_to_string(m_core_solver.m_x[column]).size()); + adjust_width_with_bounds(column, w); + adjust_width_with_basis_heading(column, w); + for (unsigned i = 0; i < nrows(); i++) { + unsigned cellw = m_A[i][column].size(); + if (cellw > w) { + w = cellw; + } + } + w = std::max(w, (unsigned)T_to_string(m_exact_column_norms[column]).size()); + w = std::max(w, (unsigned)T_to_string(m_core_solver.m_column_norms[column]).size()); + return w; + } + + unsigned regular_cell_width(unsigned row, unsigned column, std::string name) { + return regular_cell_string(row, column, name).size(); + } + + std::string regular_cell_string(unsigned row, unsigned column, std::string name) { + T t = fabs(m_core_solver.m_ed[row]); + if ( t == 1) return name; + return T_to_string(t) + name; + } + + + void set_coeff(vector& row, vector & row_signs, unsigned col, const T & t, string name) { + if (numeric_traits::is_zero(t)) { + return; + } + if (col > 0) { + if (t > 0) { + row_signs[col] = "+"; + row[col] = t != 1? T_to_string(t) + name : name; + } else { + row_signs[col] = "-"; + row[col] = t != -1? T_to_string(-t) + name: name; + } + } else { // col == 0 + if (t == -1) { + row[col] = "-" + name; + } else if (t == 1) { + row[col] = name; + } else { + row[col] = T_to_string(t) + name; + } + } + } + + void print_x() { + if (ncols() == 0) { + return; + } + + int blanks = m_title_width + 1 - m_x_title.size(); + cout << m_x_title; + print_blanks(blanks); + + auto bh = m_core_solver.m_x; + for (unsigned i = 0; i < ncols(); i++) { + string s = T_to_string(bh[i]); + int blanks = m_column_widths[i] - s.size(); + print_blanks(blanks); + cout << s << " "; // the column interval + } + cout << endl; + } + + std::string get_low_bound_string(unsigned j) { + switch (m_core_solver.get_column_type(j)){ + case boxed: + case low_bound: + case fixed: + if (m_core_solver.low_bounds_are_set()) + return T_to_string(m_core_solver.low_bound_value(j)); + else + return string("0"); + break; + default: + return std::string(); + } + } + + std::string get_upp_bound_string(unsigned j) { + switch (m_core_solver.get_column_type(j)){ + case boxed: + case upper_bound: + case fixed: + return T_to_string(m_core_solver.upper_bound_value(j)); + break; + default: + return std::string(); + } + } + + + void print_lows() { + if (ncols() == 0) { + return; + } + int blanks = m_title_width + 1 - m_low_bounds_title.size(); + cout << m_low_bounds_title; + print_blanks(blanks); + + for (unsigned i = 0; i < ncols(); i++) { + string s = get_low_bound_string(i); + int blanks = m_column_widths[i] - s.size(); + print_blanks(blanks); + cout << s << " "; // the column interval + } + cout << endl; + } + + void print_upps() { + if (ncols() == 0) { + return; + } + int blanks = m_title_width + 1 - m_upp_bounds_title.size(); + cout << m_upp_bounds_title; + print_blanks(blanks); + + for (unsigned i = 0; i < ncols(); i++) { + string s = get_upp_bound_string(i); + int blanks = m_column_widths[i] - s.size(); + print_blanks(blanks); + cout << s << " "; // the column interval + } + cout << endl; + } + + string get_exact_column_norm_string(unsigned col) { + return T_to_string(m_exact_column_norms[col]); + } + + void print_exact_norms() { + int blanks = m_title_width + 1 - m_exact_norm_title.size(); + cout << m_exact_norm_title; + print_blanks(blanks); + for (unsigned i = 0; i < ncols(); i++) { + string s = get_exact_column_norm_string(i); + int blanks = m_column_widths[i] - s.size(); + print_blanks(blanks); + cout << s << " "; + } + cout << endl; + } + + void print_approx_norms() { + int blanks = m_title_width + 1 - m_approx_norm_title.size(); + cout << m_approx_norm_title; + print_blanks(blanks); + for (unsigned i = 0; i < ncols(); i++) { + string s = T_to_string(m_core_solver.m_column_norms[i]); + int blanks = m_column_widths[i] - s.size(); + print_blanks(blanks); + cout << s << " "; + } + cout << endl; + } + + void print() { + for (unsigned i = 0; i < nrows(); i++) { + print_row(i); + } + print_bottom_line(); + print_cost(); + print_x(); + print_basis_heading(); + print_lows(); + print_upps(); + print_exact_norms(); + print_approx_norms(); + cout << endl; + } + + void print_basis_heading() { + int blanks = m_title_width + 1 - m_basis_heading_title.size(); + cout << m_basis_heading_title; + print_blanks(blanks); + + if (ncols() == 0) { + return; + } + auto bh = m_core_solver.m_basis_heading; + for (unsigned i = 0; i < ncols(); i++) { + string s = T_to_string(bh[i]); + int blanks = m_column_widths[i] - s.size(); + print_blanks(blanks); + cout << s << " "; // the column interval + } + cout << endl; + } + + void print_bottom_line() { + std::cout << "----------------------" << std::endl; + } + + void print_cost() { + int blanks = m_title_width + 1 - m_cost_title.size(); + cout << m_cost_title; + print_blanks(blanks); + print_given_rows(m_costs, m_cost_signs, m_core_solver.get_cost()); + } + + void print_given_rows(vector & row, vector & signs, X rst) { + for (unsigned col = 0; col < row.size(); col++) { + unsigned width = m_column_widths[col]; + string s = row[col]; + int number_of_blanks = width - s.size(); + lean_assert(number_of_blanks >= 0); + print_blanks(number_of_blanks); + cout << s << ' '; + if (col < row.size() - 1) { + cout << signs[col + 1] << ' '; + } + } + cout << '='; + + string rs = T_to_string(rst); + int nb = m_rs_width - rs.size(); + lean_assert(nb >= 0); + print_blanks(nb + 1); + cout << rs << std::endl; + } + + void print_row(unsigned i){ + print_blanks(m_title_width + 1); + auto row = m_A[i]; + auto sign_row = m_signs[i]; + auto rs = m_rs[i]; + print_given_rows(row, sign_row, rs); + } +}; +} diff --git a/src/util/lp/eta_matrix.h b/src/util/lp/eta_matrix.h new file mode 100644 index 0000000000..9de0fe91f9 --- /dev/null +++ b/src/util/lp/eta_matrix.h @@ -0,0 +1,179 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +namespace lean { + + // This is the sum of a unit matrix and a one-column matrix + template + class eta_matrix + : public tail_matrix { +#ifndef NDEBUG + unsigned m_length; +#endif + unsigned m_column_index; + sparse_vector m_column_vector; + T m_diagonal_element; + public: +#ifndef NDEBUG + eta_matrix(unsigned column_index, unsigned length): +#else + eta_matrix(unsigned column_index): +#endif + +#ifndef NDEBUG + m_length(length), +#endif + m_column_index(column_index) { + } + + + // T & get_column_element(unsigned j) { + // return m_column[j]; + // } + + void print() { + print_matrix(*this); + } + + bool is_unit() { + return m_column_vector.size() == 0 && m_diagonal_element == 1; + } + + void set_diagonal_element(T const & diagonal_element) { + lean_assert(!lp_settings::is_eps_small_general(diagonal_element, 1e-12)); + m_diagonal_element = diagonal_element; + } + + const T & get_diagonal_element() const { + return m_diagonal_element; + } + + void apply_from_left(vector & w, lp_settings & ) { + auto w_at_column_index = w[m_column_index]; + w[m_column_index] /= m_diagonal_element; + for (auto it = sparse_vector_iterator(m_column_vector); !it.done(); it.move()) { + w[it.index()] += w_at_column_index * it.value(); + } + } + + template + void apply_from_left_local(indexed_vector & w, lp_settings & settings) { + const L w_at_column_index = w[m_column_index]; + if (is_zero(w_at_column_index)) return; + + if (settings.abs_val_is_smaller_than_drop_tolerance(w[m_column_index] /= m_diagonal_element)) { + w[m_column_index] = zero_of_type(); + w.erase_from_index(m_column_index); + } + + for (auto it = sparse_vector_iterator(m_column_vector); !it.done(); it.move()) { + unsigned i = it.index(); + if (is_zero(w[i])) { + L v = w[i] = w_at_column_index * it.value(); + if (settings.abs_val_is_smaller_than_drop_tolerance(v)) { + w[i] = zero_of_type(); + continue; + } + w.m_index.push_back(i); + } else { + L v = w[i] += w_at_column_index * it.value(); // todo indexed_vector + if (settings.abs_val_is_smaller_than_drop_tolerance(v)) { + w[i] = zero_of_type(); + w.erase_from_index(i); + } + } + } + } + + void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) { + apply_from_left_local(w, settings); + } + + + void push_back(unsigned row_index, T val ) { + lean_assert(row_index != m_column_index); + m_column_vector.push_back(row_index, val); + } + + void apply_from_right(vector & w) { +#ifndef NDEBUG + // dense_matrix deb(*this); + // auto clone_w = clone_vector(w, get_number_of_rows()); + // deb.apply_from_right(clone_w); +#endif + T t = w[m_column_index] / m_diagonal_element; + for (auto it = sparse_vector_iterator(m_column_vector); !it.done(); it.move()) { + t += w[it.index()] * it.value(); + } + w[m_column_index] = t; +#ifndef NDEBUG + // lean_assert(vectors_are_equal(clone_w, w, get_number_of_rows())); + // delete clone_w; +#endif + } + +// void apply_from_right(indexed_vector & w) { +// #ifndef NDEBUG +// // dense_matrix deb(*this); +// // auto clone_w = clone_vector(w, get_number_of_rows()); +// // deb.apply_from_right(clone_w); +// #endif +// T t = w[m_column_index] / m_diagonal_element; +// for (auto it = sparse_vector_iterator(m_column_vector); !it.done(); it.move()) { +// t += w[it.index()] * it.value(); +// } +// if (numeric_traits::is_zero(w[m_column_index])) { +// w.m_index.push_back(m_column_index); +// } +// w[m_column_index] = t; // we might get a zero here +// #ifndef NDEBUG +// // lean_assert(vectors_are_equal(clone_w, w, get_number_of_rows())); +// // delete clone_w; +// #endif +// } + + T get_elem(unsigned i, unsigned j) const { + if (j == m_column_index){ + if (i == j) { + return 1 / m_diagonal_element; + } + return m_column_vector[i]; + } + + return i == j ? numeric_traits::one() : numeric_traits::zero(); + } +#ifndef NDEBUG + unsigned row_count() const { return m_length; } + unsigned column_count() const { return m_length; } + void set_number_of_rows(unsigned /*m*/) { } + void set_number_of_columns(unsigned /*n*/) { } +#endif + sparse_vector_iterator get_sparse_vector_iterator() { + return sparse_vector_iterator(m_column_vector); + } + + void divide_by_diagonal_element() { + m_column_vector.divide(m_diagonal_element); + } + void conjugate_by_permutation(permutation_matrix & p) { + // this = p * this * p(-1) +#ifndef NDEBUG + // auto rev = p.get_reverse(); + // auto deb = ((*this) * rev); + // deb = p * deb; +#endif + m_column_index = p.get_rev(m_column_index); + for (auto & pair : m_column_vector.m_data) { + pair.first = p.get_rev(pair.first); + } +#ifndef NDEBUG + // lean_assert(deb == *this); +#endif +} + }; +} diff --git a/src/util/lp/indexed_value.h b/src/util/lp/indexed_value.h new file mode 100644 index 0000000000..e5dc627956 --- /dev/null +++ b/src/util/lp/indexed_value.h @@ -0,0 +1,58 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ +#pragma once +#include "util/numerics/float.h" +#include "util/numerics/double.h" +#include "util/numerics/mpq.h" + +namespace lean { +template +class indexed_value { +public: + T m_value; + // the idea is that m_index for a row element gives its column, and for a column element its row + unsigned m_index; + // m_other point is the offset of the corresponding element in its vector : for a row element it point to the column element offset, + // for a column element it points to the row element offset + unsigned m_other; + indexed_value() {} + indexed_value(T v, unsigned i) : m_value(v), m_index(i) {} + indexed_value(T v, unsigned i, unsigned other) : + m_value(v), m_index(i), m_other(other) { + } + + indexed_value(const indexed_value & iv) { + m_value = iv.m_value; + m_index = iv.m_index; + m_other = iv.m_other; + } + + indexed_value & operator=(const indexed_value & right_side) { + m_value = right_side.m_value; + m_index = right_side.m_index; + m_other = right_side.m_other; + return *this; + } + + T value() const { + return m_value; + } + + void set_value(T val) { + m_value = val; + } +}; + template + bool check_vector_for_small_values(indexed_vector & w, lp_settings & settings) { + for (unsigned i : w.m_index) { + const X & v = w[i]; + if ((!is_zero(v)) && settings.abs_val_is_smaller_than_drop_tolerance(v)) + return false; + } + return true; + } +} diff --git a/src/util/lp/indexed_vector.h b/src/util/lp/indexed_vector.h new file mode 100644 index 0000000000..a8b93d276d --- /dev/null +++ b/src/util/lp/indexed_vector.h @@ -0,0 +1,144 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/debug.h" +#include "util/numerics/numeric_traits.h" +#include "util/numerics/xnumeral.h" +#include "util/numerics/mpq.h" +#include "util/numerics/mpz.h" +#include "util/numerics/mpbq.h" +#include "util/numerics/double.h" +#include "util/numerics/float.h" +#include "util/numerics/mpfp.h" +#include +#include "util/lp/sparse_vector.h" +#include +namespace lean { +using std::string; +using std::cout; +using std::endl; +using std::vector; + +template +void print_vector(const T * t, unsigned l) { + for (unsigned i = 0; i < l; i++) + std::cout << t[i] << " "; + std::cout << std::endl; +} + +template +void print_vector(const vector & t) { + for (unsigned i = 0; i < t.size(); i++) + std::cout << t[i] << " "; + std::cout << std::endl; +} + +template +void print_vector(const buffer & t) { + for (unsigned i = 0; i < t.size(); i++) + std::cout << t[i] << " "; + std::cout << std::endl; +} + +template +void print_sparse_vector(const vector & t) { + for (unsigned i = 0; i < t.size(); i++) { + if (is_zero(t[i]))continue; + std::cout << "[" << i << "] = " << t[i] << ", "; + } + std::cout << std::endl; +} + +void print_vector(const vector & t) { + for (unsigned i = 0; i < t.size(); i++) + std::cout << t[i].get_double() << std::setprecision(3) << " "; + std::cout << std::endl; +} + +template +class indexed_vector { +public: + // m_index points to non-zero elements of m_data + buffer m_data; + vector m_index; + indexed_vector(unsigned data_size) { + m_data.resize(data_size, numeric_traits::zero()); + } + + void resize(unsigned data_size) { + m_index.clear(); + m_data.resize(data_size, numeric_traits::zero()); + } + + unsigned data_size() const { + return m_data.size(); + } + + unsigned size() { + return m_index.size(); + } + + void set_value(T value, unsigned index) { + m_data[index] = value; + m_index.push_back(index); + } + + void clear() { + for (unsigned i : m_index) { + m_data[i] = numeric_traits::zero(); + } + m_index.clear(); + } + + void clear_all() { + unsigned i = m_data.size(); + while (i--) m_data[i] = numeric_traits::zero(); + + m_index.clear(); + } + + const T& operator[] (unsigned i) const { + return m_data[i]; + } + + T& operator[] (unsigned i) { + return m_data[i]; + } + + + void erase_from_index(unsigned j) { + auto it = std::find(m_index.begin(), m_index.end(), j); + if (it != m_index.end()) m_index.erase(it); + } + + + +#ifndef NDEBUG + bool is_OK() const { + int size = 0; + for (unsigned i = 0; i < m_data.size(); i++) { + if (!is_zero(m_data[i])) { + if (std::find(m_index.begin(), m_index.end(), i) == m_index.end()) + return false; + size++; + } + } + return size == m_index.size(); + } + void print() { + cout << "m_index " << endl; + for (unsigned i = 0; i < m_index.size(); i++) { + cout << m_index[i] << " "; + } + cout << endl; + print_vector(m_data); + } +#endif +}; +} diff --git a/src/util/lp/lar_constraints.h b/src/util/lp/lar_constraints.h new file mode 100644 index 0000000000..9a8bf61544 --- /dev/null +++ b/src/util/lp/lar_constraints.h @@ -0,0 +1,116 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/debug.h" +#include "util/buffer.h" +#include "util/numerics/numeric_traits.h" +#include "util/numerics/xnumeral.h" +#include +#include +#include +#include "util/lp/canonic_left_side.h" +namespace lean { + lconstraint_kind flip_kind(lconstraint_kind t) { + return static_cast( - static_cast(t)); + } + + std::string lconstraint_kind_string(lconstraint_kind t) { + switch (t) { + case LE: return string("<="); + case LT: return string("<"); + case GE: return string(">="); + case GT: return string(">"); + case EQ: return string("="); + + default: + throw "unexpected"; + } + } + + class lar_base_constraint { + public: + lconstraint_kind m_kind; + mpq m_right_side; + virtual buffer> get_left_side_coefficients() const = 0; + constraint_index m_index; // the index of constraint + lar_base_constraint() {} + lar_base_constraint(lconstraint_kind kind, mpq right_side, constraint_index index) :m_kind(kind), m_right_side(right_side), m_index(index) {} + + virtual unsigned size() const = 0; + virtual ~lar_base_constraint(){} + }; + + class lar_constraint : public lar_base_constraint { + public: + std::unordered_map m_left_side; + lar_constraint() {} + lar_constraint(const buffer> & left_side, lconstraint_kind kind, mpq right_side, constraint_index index) : lar_base_constraint(kind, right_side, index) { + for (auto & it : left_side) { + auto r = m_left_side.find(it.second); + if (r == m_left_side.end()) { + m_left_side[it.second] = it.first; + } else { + r->second += it.first; + } + } + } + + lar_constraint(const lar_base_constraint & c): lar_base_constraint(c.m_kind, c.m_right_side, c.m_index) { + for (auto t : c.get_left_side_coefficients()) + m_left_side.insert(std::make_pair(t.second, t.first)); + } + + unsigned size() const { + return m_left_side.size(); + } + + buffer> get_left_side_coefficients() const { + buffer> ret; + for (auto it : m_left_side) { + ret.push_back(std::make_pair(it.second, it.first)); + } + return ret; + } + }; + + class lar_normalized_constraint : public lar_base_constraint { + public: + canonic_left_side* m_canonic_left_side; + mpq m_ratio_to_original; // by multiplying this constraint by m_ratio_to_original we get the original one + lar_constraint m_origin_constraint; + lar_normalized_constraint(canonic_left_side * ls, mpq ratio, lconstraint_kind kind, mpq right_side, const lar_constraint & origin): + lar_base_constraint(kind, right_side, origin.m_index), + m_canonic_left_side(ls), + m_ratio_to_original(ratio), + m_origin_constraint(origin) { + } + + lar_normalized_constraint() {} + + // lar_normalized_constraint & operator=(lar_normalized_constraint & other) { + // m_canonic_left_side = other.m_canonic_left_side; + // m_origin_constraint = other.m_origin_constraint; + // m_kind = other.m_kind; + // m_right_side = other.m_right_side; + // return *this; + // } + + + + + virtual buffer> get_left_side_coefficients() const { + buffer> ret; + for (auto t : m_canonic_left_side->m_coeffs) ret.push_back(t); + return ret; + } + virtual unsigned size() const { + return m_canonic_left_side->size(); + } + }; +} diff --git a/src/util/lp/lar_core_solver.h b/src/util/lp/lar_core_solver.h new file mode 100644 index 0000000000..e21c4aeb66 --- /dev/null +++ b/src/util/lp/lar_core_solver.h @@ -0,0 +1,870 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ +#pragma once +#include +#include +#include "util/lp/lp_core_solver_base.h" +#include +#include "util/lp/indexed_vector.h" +#include "util/lp/binary_heap_priority_queue.h" +#include "util/lp/breakpoint.h" +namespace lean { + + template + class lar_core_solver : public lp_core_solver_base { + // m_sign_of_entering is set to 1 if the entering variable needs + // to grow and is set to -1 otherwise + int m_sign_of_entering_delta; + X m_infeasibility; + vector m_tight_basic_columns; + vector> m_breakpoints; + binary_heap_priority_queue m_breakpoint_indices_queue; + vector> m_infeasible_row; + int m_infeasible_row_sign = 0; + // with a breakpoint at this delta + public: + lar_core_solver(std::vector & x, std::vector & column_types, + std::vector & low_bounds, std::vector & upper_bounds, + std::vector & basis, + static_matrix & A, + lp_settings & settings, + std::unordered_map & column_names, + vector & right_side, + vector & costs) : // right_side and costs are redundant + lp_core_solver_base(A, + right_side, + basis, + x, + costs, + settings, + column_names, + column_types, + low_bounds, + upper_bounds) { + } + + int get_infeasible_row_sign() const { + return m_infeasible_row_sign; + } + + const vector> & get_infeasibility_info(int & inf_sign) const { + inf_sign = m_infeasible_row_sign; + return m_infeasible_row; + } + + void init_costs() { + lean_assert(this->m_x.size() >= this->m_n); + lean_assert(this->m_column_type.size() >= this->m_n); + X inf = m_infeasibility; + m_infeasibility = zero_of_type(); + for (unsigned j = this->m_n; j--;) + init_cost_for_column(j); + if (!(this->m_total_iterations ==0 || inf >= m_infeasibility)) { + cout << "inf was " << T_to_string(inf) << " and now " << T_to_string(m_infeasibility) << endl; + } + lean_assert(this->m_total_iterations ==0 || inf >= m_infeasibility); + if (inf == m_infeasibility) + this->m_iters_with_no_cost_growing++; + } + + + void init_cost_for_column(unsigned j) { + // If j is a breakpoint column, then we set the cost zero. + // When anylyzing an entering column candidate we update the cost of the breakpoints columns to get the left or the right derivative if the infeasibility function + const X & x = this->m_x[j]; + // set zero cost for each non-basis column + if (this->m_basis_heading[j] < 0) { + this->m_costs[j] = numeric_traits::zero(); + return; + } + // j is a basis column + switch (this->m_column_type[j]) { + case fixed: + case boxed: + if (x > this->m_upper_bound_values[j]) { + this->m_costs[j] = 1; + m_infeasibility += x - this->m_upper_bound_values[j]; + } else if (x < this->m_low_bound_values[j]) { + m_infeasibility += this->m_low_bound_values[j] - x; + this->m_costs[j] = -1; + } else { + this->m_costs[j] = numeric_traits::zero(); + } + break; + case low_bound: + if (x < this->m_low_bound_values[j]) { + this->m_costs[j] = -1; + m_infeasibility += this->m_low_bound_values[j] - x; + } else { + this->m_costs[j] = numeric_traits::zero(); + } + break; + case upper_bound: + if (x > this->m_upper_bound_values[j]) { + this->m_costs[j] = 1; + m_infeasibility += x - this->m_upper_bound_values[j]; + } else { + this->m_costs[j] = numeric_traits::zero(); + } + break; + case free_column: + this->m_costs[j] = numeric_traits::zero(); + break; + default: + lean_assert(false); + break; + } + } + + void init_local() { + this->m_start_time = get_millisecond_count(); + this->m_m = this->m_A.row_count(); + this->m_n = this->m_A.column_count(); + this->m_pivot_row_of_B_1.resize(this->m_m); + this->m_pivot_row.resize(this->m_n); + this->m_b.resize(this->m_m); + this->m_y.resize(this->m_m); + this->m_w.resize(this->m_m); + this->m_d.resize(this->m_n); + this->m_ed.resize(this->m_m); + this->m_costs.resize(this->m_n); + this->m_breakpoint_indices_queue.resize(this->m_n); + this->m_copy_of_xB.resize(this->m_n); + } + + // returns m_sign_of_alpha_r + int column_is_out_of_bounds(unsigned j) { + switch (this->m_column_type[j]) { + case fixed: + case boxed: + if (this->x_below_low_bound(j)) { + return -1; + } + if (this->x_above_upper_bound(j)) { + return 1; + } + return 0; + case low_bound: + if (this->x_below_low_bound(j)) { + return -1; + } + return 0; + case upper_bound: + if (this->x_above_upper_bound(j)) { + return 1; + } + return 0; + default: + return 0; + break; + } + } + + bool can_enter_basis_mpq(unsigned j) { + switch (this->m_column_type[j]) { + case low_bound: + lean_assert(this->x_is_at_low_bound(j)); + return this->m_d[j] < numeric_traits::zero(); + case upper_bound: + lean_assert(this->x_is_at_upper_bound(j)); + return this->m_d[j] > numeric_traits::zero(); + case fixed: + return false; + case boxed: + { + bool low_bound = this->x_is_at_low_bound(j); + lean_assert(low_bound || this->x_is_at_upper_bound(j)); + return (low_bound && this->m_d[j] < numeric_traits::zero()) || ((!low_bound) && this->m_d[j] > numeric_traits::zero()); + } + case free_column: + return !numeric_traits::is_zero(this->m_d[j]); + default: + return false; + } + return false; + } + + + void calculate_pivot_row(unsigned i) { + this->calculate_pivot_row_of_B_1(i); + this->calculate_pivot_row_when_pivot_row_of_B1_is_ready(); + } + + + X get_deb_inf_column(unsigned j) { + const X & x = this->m_x[j]; + switch (this->m_column_type[j]) { + case low_bound: + if (x < this->m_low_bound_values[j]) + return this->m_low_bound_values[j] - x; + return zero_of_type(); + case upper_bound: + if (x > this->m_upper_bound_values[j]) + return x - this->m_upper_bound_values[j]; + return zero_of_type(); + case fixed: + case boxed: + { + if (x < this->m_low_bound_values[j]) + return this->m_low_bound_values[j] - x; + if (x > this->m_upper_bound_values[j]) + return x - this->m_upper_bound_values[j]; + return zero_of_type(); + } + case free_column: + { + return zero_of_type(); + } + default: + lean_assert(false); + return zero_of_type(); + } + } + + X get_deb_inf() { + X ret = zero_of_type(); + for (unsigned j = 0; j < this->m_n; j++) { + X d = get_deb_inf_column(j); + // if (! numeric_traits::is_zero(d)) { + // cout << "column " << j << ", " << this->column_name(j) << " inf is " << d.get_double() << endl; + // } + ret += d; + } + return ret; + } + + bool debug_profit_delta(unsigned j, const T & delta) { + this->update_x(j, delta); + bool ret = m_infeasibility > get_deb_inf(); + if (ret) { + cout << "found profit for " << this->column_name(j) << " and delta = " << delta.get_double() << endl; + cout << "improvement = " << (m_infeasibility - get_deb_inf()).get_double() << endl; + } + return ret; + } + + bool debug_profit(unsigned j) { + if (this->m_column_type[j] == fixed) return false; + T delta = numeric_traits::one() / 10000000; + delta /= 10000000; + return debug_profit_delta(j, -delta) || debug_profit_delta(j, delta); + } + + int choose_column_entering_basis() { + unsigned offset = lrand48() % this->m_non_basic_columns.size(); + unsigned initial_offset_in_non_basis = offset; + do { + unsigned j = this->m_non_basic_columns[offset]; + if (can_enter_basis_mpq(j)) + return j; + offset++; + if (offset == this->m_non_basic_columns.size()) offset = 0; + } while (offset != initial_offset_in_non_basis); + return -1; + } + + void one_iteration() { + this->m_total_iterations++; + lean_assert(this->m_non_basic_columns.size() + this->m_basis.size() == this->m_basis_heading.size()); + if (is_zero(m_infeasibility)) { + this->m_status = OPTIMAL; + return; + } + int entering = choose_column_entering_basis(); + if (entering == -1) { + cout << "cannot choose entering" << endl; + decide_on_status_when_cannot_enter(); + } else { + advance_on_entering(entering); + } + } + + + void decide_on_status_when_cannot_enter() { + if (!is_zero(m_infeasibility)) + this->m_status = INFEASIBLE; + else + this->m_status = FEASIBLE; + cout << "status is " << lp_status_to_string(this->m_status) << endl; + } + template + bool same_sign_with_entering_delta(const L & a) { + return (a > zero_of_type() && m_sign_of_entering_delta > 0) || (a < zero_of_type() && m_sign_of_entering_delta < 0); + } + + // j is the basic column, x is the value at x[j] + // d is the coefficient before m_entering in the row with j as the basis column + void try_add_breakpoint(unsigned j, const X & x, const T & d, breakpoint_type break_type, const X & break_value) { + X diff = x - break_value; + if (is_zero(diff)) { + switch (break_type) { + case low_break: + if (!same_sign_with_entering_delta(d)) + return; // no breakpoint + break; + case upper_break: + if (same_sign_with_entering_delta(d)) + return; // no breakpoint + break; + default: break; + } + add_breakpoint(j, zero_of_type(), break_type); + return; + } + auto delta_j = diff / d; + if (same_sign_with_entering_delta(delta_j)) + add_breakpoint(j, delta_j, break_type); + } + + + void add_breakpoint(unsigned j, X delta, breakpoint_type type) { + m_breakpoints.push_back(breakpoint(j, delta, type)); + m_breakpoint_indices_queue.enqueue(m_breakpoint_indices_queue.size(), abs(delta)); + } + + void try_add_breakpoint_in_row(unsigned i) { + lean_assert(i < this->m_m); + const T & d = this->m_ed[i]; // the coefficient before m_entering in the i-th row + if (d == 0) return; // the change of x[m_entering] will not change the corresponding basis x + unsigned j = this->m_basis[i]; + const X & x = this->m_x[j]; + switch (this->m_column_type[j]) { + case fixed: + try_add_breakpoint(j, x, d, fixed_break, this->m_low_bound_values[j]); + break; + case boxed: + try_add_breakpoint(j, x, d, low_break, this->m_low_bound_values[j]); + try_add_breakpoint(j, x, d, upper_break, this->m_upper_bound_values[j]); + break; + case low_bound: + try_add_breakpoint(j, x, d, low_break, this->m_low_bound_values[j]); + break; + case upper_bound: + try_add_breakpoint(j, x, d, upper_break, this->m_upper_bound_values[j]); + break; + case free_column: + break; + default: + lean_assert(false); + break; + } + } + + string break_type_to_string(breakpoint_type type) { + switch (type){ + case low_break: return "low_break"; + case upper_break: return "upper_break"; + case fixed_break: return "fixed_break"; + default: + lean_assert(false); + break; + } + return "type is not found"; + } + + void print_breakpoint(const breakpoint * b) { + cout << "(" << this->column_name(b->m_j) << "," << break_type_to_string(b->m_type) << "," << T_to_string(b->m_delta) << ")" << endl; + print_bound_info_and_x(b->m_j); + } + + void print_bound_info_and_x(unsigned j) { + cout << "type of " << this->column_name(j) << " is " << column_type_to_string(this->m_column_type[j]) << endl; + cout << "x[" << this->column_name(j) << "] = " << this->m_x[j] << endl; + switch (this->m_column_type[j]) { + case fixed: + case boxed: + cout << "[" << this->m_low_bound_values[j] << "," << this->m_upper_bound_values[j] << "]" << endl; + break; + case low_bound: + cout << "[" << this->m_low_bound_values[j] << ", inf" << endl; + break; + case upper_bound: + cout << "inf ," << this->m_upper_bound_values[j] << "]" << endl; + break; + case free_column: + cout << "inf, inf" << endl; + break; + default: + lean_assert(false); + break; + } + } + + void clear_breakpoints() { + m_breakpoints.clear(); + m_breakpoint_indices_queue.clear(); + } + + void fill_breakpoints_array(unsigned entering) { + clear_breakpoints(); + for (unsigned i = this->m_m; i--;) + try_add_breakpoint_in_row(i); + + if (this->m_column_type[entering] == boxed) { + if (m_sign_of_entering_delta < 0) + add_breakpoint(entering, - this->bound_span(entering), low_break); + else + add_breakpoint(entering, this->bound_span(entering), upper_break); + } + } + + void advance_on_entering(unsigned entering) { + this->solve_Bd(entering); // prepares the entering column to be like the one of the tableau + m_sign_of_entering_delta = this->m_d[entering] < zero_of_type() ? 1 : -1; + + fill_breakpoints_array(entering); + advance_on_sorted_breakpoints(entering); + } + + void print_cost() { + cout << "reduced costs " << endl; + for (unsigned j = 0; j < this->m_n; j++) { + if (numeric_traits::is_zero(this->m_d[j])) continue; + cout << T_to_string(this->m_d[j]) << this->column_name(j) << " "; + } + cout << endl; + } + + void update_basis_and_x_with_comparison(unsigned entering, unsigned leaving, X delta) { + if (entering != leaving) + this->update_basis_and_x(entering, leaving, delta); + else + this->update_x(entering, delta); + } + + void advance_on_sorted_breakpoints(unsigned entering) { + T slope_at_entering = this->m_d[entering]; + breakpoint * last_bp = nullptr; + while (m_breakpoint_indices_queue.is_empty() == false) { + unsigned bi = m_breakpoint_indices_queue.dequeue(); + breakpoint *b = &m_breakpoints[bi]; + change_slope_on_breakpoint(entering, b, slope_at_entering); + last_bp = b; + if (slope_at_entering * m_sign_of_entering_delta > 0) { // the slope started to increase infeasibility + break; + } else { + if (numeric_traits::is_zero(slope_at_entering) && lrand48() % 2 == 0) { + // it is not cost benefitial to advance the delta more, so just break to increas the randomness + break; + } + } + } + update_basis_and_x_with_comparison(entering, last_bp->m_j, last_bp->m_delta); + } + + void change_slope_on_breakpoint(unsigned entering, breakpoint * b, T & slope_at_entering) { + if (b->m_j == entering) { + lean_assert(b->m_type != fixed_break && (!is_zero(b->m_delta))); + slope_at_entering += m_sign_of_entering_delta; + return; + } + + lean_assert(this->m_basis_heading[b->m_j] >= 0); + unsigned i_row = this->m_basis_heading[b->m_j]; + const T & d = - this->m_ed[i_row]; + if (numeric_traits::is_zero(d)) return; + + T delta = m_sign_of_entering_delta * abs(d); + switch (b->m_type) { + case fixed_break: + if (is_zero(b->m_delta)) { + slope_at_entering += delta; + } else { + slope_at_entering += 2 * delta; + } + break; + case low_break: + case upper_break: + slope_at_entering += delta; + break; + default: + throw 1; + lean_assert(false); // such a type does not exist + } + } + + bool row_is_infeasible(unsigned row, int & inf_sign) { + unsigned j = this->m_basis[row]; + inf_sign = get_infeasibility_sign(j); + return inf_sign != 0; + } + + bool row_is_evidence(unsigned row, int & inf_sign) { + if (!row_is_infeasible(row, inf_sign)) return false; + calculate_pivot_row(row); + int entering = choose_entering_column_for_row_inf_strategy(inf_sign); + if (entering == -1) { + return true; + } + return false; + } + + bool find_evidence_row() { + for (unsigned i = this->m_m; --i;) { + int inf_sign; + if (row_is_evidence(i, inf_sign)) { + fill_evidence(i, inf_sign); + return true; + } + } + return false; + } + + + bool done() { + if (this->m_status == OPTIMAL) return true; + if (this->m_status == INFEASIBLE) { + if (this->m_settings.row_feasibility == false) { + if (find_evidence_row()) { + cout << "found evidence" << endl; + } else { + cout << "did not find evidence" << endl; + cout << "started feasibility_loop at iteration " << this->m_total_iterations << endl; + unsigned iters = this->m_total_iterations; + this->m_status = FEASIBLE; + row_feasibility_loop(); + cout << "made another " << this->m_total_iterations - iters << ", percentage is " << 100.0 * (this->m_total_iterations - iters) / this->m_total_iterations << endl; + } + } + return true; + } + + if (this->m_iters_with_no_cost_growing >= this->m_settings.max_number_of_iterations_with_no_improvements) { + cout << "m_iters_with_no_cost_growing = " << this->m_iters_with_no_cost_growing << endl; + this->m_status = ITERATIONS_EXHAUSTED; return true; + } + if (this->m_total_iterations >= this->m_settings.max_total_number_of_iterations) { + cout << "max_total_number_of_iterations " << this->m_total_iterations << " is reached " << endl; + this->m_status = ITERATIONS_EXHAUSTED; return true; + } + return false; + } + + void move_as_many_as_possible_fixed_columns_to_non_basis() { + unsigned i = 0; // points to basis + auto& bs = this->m_basis; + unsigned j = 0; // points to m_column_types + auto & ct = this->m_column_type; + vector heading(this->m_n, -1); + for (int i = 0; i < bs.size(); i ++) heading[bs[j]] = i; + lean_assert(this->m_basis.size() == this->m_m); + while (i < this->m_m && j < ct.size()) { + unsigned basis_j = bs[i]; + if (ct[basis_j] != fixed) {i++; continue;} + do { + if (heading[j] == -numeric_traits::one() && ct[j] != fixed) + break; + j++; + } while (j < ct.size()); + if (j == ct.size()) break; + bs[i++] = j++; + } + } + + bool non_basis_columns_are_set_correctly() { + for (unsigned j : this->m_non_basic_columns) { + if (!this->x_is_at_bound(j)) + return false; + } + return true; + } + + void prefix() { + init_local(); + this->init(); + this->init_basis_heading(); + } + + bool is_tiny() const { + return this->m_m < 10 && this->m_n < 20; + } + + bool is_empty() const { + return this->m_m == 0 || this->m_n == 0; + } + + void feasibility_loop() { + while (true) { + init_costs(); + this->init_reduced_costs_for_one_iteration(); + if (this->print_statistics_with_cost_and_check_that_the_time_is_over(this->m_total_iterations, m_infeasibility)){ + this->m_status = lp_status::TIME_EXHAUSTED; + return; // this->m_total_iterations; + } + one_iteration(); + if (done()) { + break; + } + } + } + + unsigned get_number_of_inf_rows() const { + unsigned r = 0; + for (unsigned k = this->m_m; --k;) { + unsigned j = this->m_basis[k]; + if (get_infeasibility_sign(j)) r++; + } + return r; + } + + + void row_feasibility_loop() { + while (true) { + if (this->print_statistics_with_iterations_and_check_that_the_time_is_over(this->m_total_iterations++)){ + this->m_status = lp_status::TIME_EXHAUSTED; + return; // this->m_total_iterations; + } + int inf_sign; + int i = find_infeasible_row(inf_sign); + if (i == -1) { + this->m_status = OPTIMAL; + break; + } + advance_on_infeasible_row(i, inf_sign); + if (done()) + break; + } + } + + int find_infeasible_row(int & inf_sign) { + unsigned offset = lrand48() % this->m_m; + unsigned initial_offset_in_basis = offset; + do { + unsigned j = this->m_basis[offset]; + inf_sign = get_infeasibility_sign(j); + if (inf_sign) + return offset; + if (++offset == this->m_m) offset = 0; + } while (offset != initial_offset_in_basis); + return -1; + } + + int get_infeasibility_sign(unsigned j) const { + const auto & x = this->m_x[j]; + switch (this->m_column_type[j]) { + case fixed: + case boxed: + if (x < this->m_low_bound_values[j]) return 1; + if (x > this->m_upper_bound_values[j]) return -1; + return 0; + case low_bound: + return x < this->m_low_bound_values[j] ? 1 : 0; + case upper_bound: + return x > this->m_upper_bound_values[j]? -1 :0; + default: + return 0; + } + } + + + template + int get_sign(const L & v) { + return v > zero_of_type() ? 1 : (v < zero_of_type() ? -1 : 0); + } + + bool improves_pivot_row_inf(unsigned j, int inf_sign) { + lean_assert(this->m_basis_heading[j] < 0); + // we have x[basis[i]] = sum (mj*x[j]), where mj = -m_pivot_row[j] + + switch (this->m_column_type[j]) { + case fixed: + return false; + case boxed: + { + lean_assert(this->x_is_at_bound(j)); + int j_sign = - get_sign(this->m_pivot_row[j]) * inf_sign; + if (this->x_is_at_low_bound(j)) + return j_sign > 0; + return j_sign < 0; + } + case low_bound: + { + lean_assert(this->x_is_at_low_bound(j)); + int j_sign = - get_sign(this->m_pivot_row[j]) * inf_sign; + return j_sign > 0; + } + case upper_bound: + { + lean_assert(this->x_is_at_upper_bound(j)); + int j_sign = - get_sign(this->m_pivot_row[j]) * inf_sign; + return j_sign < 0; + } + break; + case free_column: { + return numeric_traits::is_zero(this->m_pivot_row[j]) == false; + } + default: + lean_assert(false); + throw "cannot be here"; + break; + } + } + + int choose_entering_column_for_row_inf_strategy(int inf_sign) { + unsigned offset = lrand48() % this->m_non_basic_columns.size(); + unsigned initial_offset_in_non_basis = offset; + do { + unsigned j = this->m_non_basic_columns[offset]; + if (improves_pivot_row_inf(j, inf_sign)) + return j; + if (++offset == this->m_non_basic_columns.size()) offset = 0; + } while (offset != initial_offset_in_non_basis); + return -1; + } + + void fill_evidence(unsigned row, int inf_sign) { + m_infeasible_row_sign = inf_sign; + m_infeasible_row.push_back(std::make_pair(numeric_traits::one(), this->m_basis[row])); + for (auto j : this->m_non_basic_columns) { + T aj = this->m_pivot_row[j]; + if (!numeric_traits::is_zero(aj)) { + m_infeasible_row.push_back(std::make_pair(aj, j)); + } + } + } + + + void update_delta_of_entering_and_leaving_candidates(X del, X & delta, + vector & leaving_candidates, + unsigned bj) { + if (del < delta) { + leaving_candidates.clear(); + leaving_candidates.push_back(bj); + delta = del; + } else if (del == delta) { + leaving_candidates.push_back(bj); + } + } + + void update_delta_of_entering(int delta_sign, unsigned row, X & delta, + vector & leaving_candidates) { + unsigned bj = this->m_basis[row]; // bj - the basis column for the row + const T & ed = this->m_ed[row]; // this is the coefficent before x[entering] in the sum representing the basis column of this row taken with minus + if (numeric_traits::is_zero(ed)) return; + const X & x = this->m_x[bj]; // the value of the basis column + // adjusted sign + int adj_sign = ed < zero_of_type() ? delta_sign : - delta_sign; + + switch (this->m_column_type[bj]) { + case fixed: + case boxed: + if (adj_sign > 0 && x <= this->m_upper_bound_values[bj]) + update_delta_of_entering_and_leaving_candidates((this->m_upper_bound_values[bj] - x) / abs(ed), delta, leaving_candidates, bj); + else if (adj_sign < 0 && x >= this->m_low_bound_values[bj]) + update_delta_of_entering_and_leaving_candidates((x - this->m_low_bound_values[bj]) / abs(ed), delta, leaving_candidates, bj); + break; + case low_bound: + if (adj_sign < 0 && x >= this->m_low_bound_values[bj]) + update_delta_of_entering_and_leaving_candidates((x - this->m_low_bound_values[bj]) / abs(ed), delta, leaving_candidates, bj); + break; + case upper_bound: + if (adj_sign > 0 && x <= this->m_upper_bound_values[bj]) + update_delta_of_entering_and_leaving_candidates((this->m_upper_bound_values[bj] - x) / abs(ed), delta, leaving_candidates, bj); + break; + default: + break; + } + } + + unsigned find_leaving_for_inf_row_strategy(vector & leaving_candidates) { + lean_assert(leaving_candidates.size()); + return leaving_candidates[lrand48() % leaving_candidates.size()]; // more randomness + } + + X find_initial_delta_and_its_sign(unsigned row, unsigned entering, + int inf_sign, int & entering_delta_sign, + vector & leaving_candidates) { + lean_assert(inf_sign != 0); + unsigned bj = this->m_basis[row]; // this is the infeasible basis column + const X & x = this->m_x[bj]; + entering_delta_sign = - get_sign(this->m_pivot_row[entering]) * inf_sign; + lean_assert(entering_delta_sign != 0); + X delta = (inf_sign > 0? (this->m_low_bound_values[bj] - x) : (x - this->m_upper_bound_values[bj])) / abs(this->m_pivot_row[entering]); + if (this->m_column_type[entering] == boxed) { + X span = this->bound_span(entering); + if (span < delta) { + delta = span; + leaving_candidates.push_back(entering); + } else { + leaving_candidates.push_back(bj); + } + } else { + leaving_candidates.push_back(bj); + } + + return delta; + } + + void advance_on_infeasible_row_and_entering(unsigned inf_row, unsigned entering, int inf_sign) { + this->solve_Bd(entering); // puts the tableau column of entering into this->m_ed + int entering_delta_sign; + vector leaving_candidates; + X delta = find_initial_delta_and_its_sign(inf_row, entering, inf_sign, entering_delta_sign, leaving_candidates); + lean_assert(leaving_candidates.size()); + lean_assert(delta > zero_of_type()); + unsigned row = lrand48() % this->m_m; + unsigned initial_row = row; + do { + if (row != inf_row) + update_delta_of_entering(entering_delta_sign, row, delta, leaving_candidates); + if (++row == this->m_m) row = 0; + } while (row != initial_row); + unsigned leaving = find_leaving_for_inf_row_strategy(leaving_candidates); + update_basis_and_x_with_comparison(entering, leaving, delta * entering_delta_sign); + } + + void advance_on_infeasible_row(unsigned i, int inf_sign) { + calculate_pivot_row(i); + int entering = choose_entering_column_for_row_inf_strategy(inf_sign); + if (entering == -1) { + fill_evidence(i, inf_sign); + this->m_status = INFEASIBLE; + return; + } + advance_on_infeasible_row_and_entering(i, entering, inf_sign); + } + + void solve() { + prefix(); + if (is_empty()) { + this->m_status = OPTIMAL; + return; + } + this->snap_xN_to_bounds(); // we start with non-basic variables at their bounds + lean_assert(non_basis_columns_are_set_correctly()); + + if (this->m_settings.row_feasibility) { + cout << "optimizing by rows " << endl; + row_feasibility_loop(); + } else { + cout << "optimizing total infeasibility" << endl; + feasibility_loop(); + } + } + + bool low_bounds_are_set() const { return true; } + + void print_column_info(unsigned j) { + cout << "type = " << column_type_to_string(this->m_column_type[j]) << endl; + switch (this->m_column_type[j]) { + case fixed: + case boxed: + cout << "(" << this->m_low_bound_values[j] << ", " << this->m_upper_bound_values[j] << ")" << endl; + break; + case low_bound: + cout << this->m_low_bound_values[j] << endl; + break; + case upper_bound: + cout << this->m_upper_bound_values[j] << endl; + break; + default: + lean_assert(false); + break; + } + } + }; +} diff --git a/src/util/lp/lar_solution_signature.h b/src/util/lp/lar_solution_signature.h new file mode 100644 index 0000000000..710892e317 --- /dev/null +++ b/src/util/lp/lar_solution_signature.h @@ -0,0 +1,18 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/debug.h" +#include "util/lp/lp_settings.h" +#include +namespace lean { + struct lar_solution_signature { + std::unordered_map non_basic_column_value_positions; + lp_status status; + }; +} diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h new file mode 100644 index 0000000000..f03252cd7e --- /dev/null +++ b/src/util/lp/lar_solver.h @@ -0,0 +1,884 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/debug.h" +#include "util/buffer.h" +#include "util/numerics/numeric_traits.h" +#include "util/numerics/xnumeral.h" +#include +#include +#include +#include "util/lp/lar_constraints.h" +#include +#include "util/lp/lar_core_solver.h" +#include +#include "util/lp/numeric_pair.h" +#include "util/lp/lar_solution_signature.h" +#include "util/lp/scaler.h" + +namespace std { + template<> + struct hash { + inline size_t operator()(const lean::mpq & v) const { + return v.hash(); + } +}; +} + +namespace lean { + using std::string; + using std::cout; + using std::endl; + using std::vector; + using std::unordered_map; + using std::unordered_set; + + template + struct conversion_helper { + static V get_low_bound(const column_info & ci) { + return V(ci.get_low_bound(), ci.low_bound_is_strict()? 1 : 0); + } + + static V get_upper_bound(const column_info & ci) { + return V(ci.get_upper_bound(), ci.upper_bound_is_strict()? -1 : 0); + } + }; + + template<> + struct conversion_helper { + static double get_low_bound(const column_info & ci) { + if (!ci.low_bound_is_strict()) + return ci.get_low_bound().get_double(); + double eps = 0.00001; + if (!ci.upper_bound_is_set()) + return ci.get_low_bound().get_double() + eps; + eps = std::min((ci.get_upper_bound() - ci.get_low_bound()).get_double()/1000, eps); + return ci.get_low_bound().get_double() + eps; + } + static double get_upper_bound(const column_info & ci) { + if (!ci.upper_bound_is_strict()) + return ci.get_upper_bound().get_double(); + double eps = 0.00001; + if (!ci.low_bound_is_set()) + return ci.get_upper_bound().get_double() - eps; + eps = std::min((ci.get_upper_bound() - ci.get_low_bound()).get_double()/1000, eps); + return ci.get_upper_bound().get_double() - eps; + } + }; + + + +class lar_solver { + unsigned m_available_var_index = 0; + unsigned m_available_constr_index = 0; + lp_status m_status = UNKNOWN; + unordered_map m_var_names_to_var_index; + unordered_map m_map_from_var_index_to_left_side; + unordered_set m_canonic_left_sides; + unordered_map m_column_indices_to_canonic_left_sides; + unordered_map m_normalized_constraints; + static_matrix> m_A; + lar_core_solver> m_mpq_core_solver; + lp_settings m_settings; + vector m_column_types; // this field is passed to the core solver + vector> m_low_bounds; // passed to the core solver + vector> m_upper_bounds; // passed to the core solver + vector m_basis; + vector> m_x; // the solution + unordered_map m_column_names; + vector> m_right_side_vector; // this vector will be all zeroes, it might change when the optimization with fixed variables will used + vector m_costs; + canonic_left_side * m_infeasible_canonic_left_side = nullptr; // such can be found at the initialization step + canonic_left_side * create_or_fetch_existing_left_side(const buffer>& left_side_par) { + auto left_side = new canonic_left_side(left_side_par); + lean_assert(left_side->size() > 0); + auto it = m_canonic_left_sides.find(left_side); + if (it == m_canonic_left_sides.end()) { + m_canonic_left_sides.insert(left_side); + } else { + delete left_side; + left_side = *it; + } + return left_side; + } + + + bool var_is_fixed(unsigned j) { + auto it = m_map_from_var_index_to_left_side.find(j); + lean_assert(it != m_map_from_var_index_to_left_side.end()); + return it->second->m_column_info.is_fixed(); + } + + mpq find_ratio(canonic_left_side * ls, const lar_constraint & constraint) { + lean_assert(ls->m_coeffs.size() > 0); + auto first_pair = ls->m_coeffs[0]; + lean_assert(first_pair.first == numeric_traits::one()); + var_index i = first_pair.second; + auto it = constraint.m_left_side.find(i); + lean_assert(it != constraint.m_left_side.end()); + return it->second; + } + + void add_canonic_left_side_for_var(var_index i, string var_name) { + buffer> b; + b.push_back(std::make_pair(numeric_traits::one(), i)); + auto can_ls = new canonic_left_side(b); + can_ls->set_name(var_name); + + lean_assert(m_canonic_left_sides.find(can_ls) == m_canonic_left_sides.end()); + m_canonic_left_sides.insert(can_ls); + m_map_from_var_index_to_left_side[i] = can_ls; + } + + void map_left_side_to_column_of_A(canonic_left_side* left_side, unsigned & j) { + lean_assert(m_column_indices_to_canonic_left_sides.find(j) == m_column_indices_to_canonic_left_sides.end()); + left_side->m_column_index = j; // assigning this index does not change the hash of canonic_left_side + if (left_side->size() > 1) { // if size is one we will not create a row for this left side + left_side->m_row_index = m_basis.size(); + m_basis.push_back(j); // j will be a basis column, so we put it into the basis as well + } + m_column_indices_to_canonic_left_sides[j++] = left_side; // pointing from the column to the left side + } + + + void map_left_sides_to_columns_of_A() { + unsigned j = 0; + for (auto it : m_canonic_left_sides) + map_left_side_to_column_of_A(it, j); + } + + bool valid_index(unsigned j) { return static_cast(j) >= 0;} + + + // this adds a row to A + template + void add_row_to_A(static_matrix & A, unsigned i, canonic_left_side * ls) { + for (auto & t : ls->m_coeffs) { + var_index vi = t.second; + canonic_left_side *var_left_side = m_map_from_var_index_to_left_side[vi]; + unsigned column = var_left_side->m_column_index; + lean_assert(valid_index(column)); + A.set(i, column, convert_struct::convert(t.first)); + } + A.set(i, ls->m_column_index, - one_of_type()); + } + + template + void create_matrix_A(static_matrix & A) { + unsigned n = m_column_indices_to_canonic_left_sides.size(); + unsigned m = m_basis.size(); + A.init_empty_matrix(m, n); + unsigned i = 0; + for (auto & t : m_column_indices_to_canonic_left_sides) + if (valid_index(t.second->m_row_index)) + add_row_to_A(A, i++, t.second); +#ifndef NDEBUG + // print_matrix(m_A); +#endif + } + + // void fill_column_info_names() { + // for (unsigned j = 0; j < m_A.column_count(); j++) { + // column_info t; + // m_column_infos.push_back(t); + // if (j < m_map_from_var_index_to_name_left_side_pair.size()) { + // m_column_infos.back().set_name(m_map_from_var_index_to_name_left_side_pair[j]); + // } else { + // string pref("_s_"); + // m_column_infos.back().set_name(pref + T_to_string(j)); + // } + // m_column_names + // } + // } + void set_upper_bound_for_column_info(lar_normalized_constraint * norm_constr) { + const mpq & v = norm_constr->m_right_side; + canonic_left_side * ls = norm_constr->m_canonic_left_side; + column_info & ci = ls->m_column_info; + lean_assert(norm_constr->m_kind == LE || norm_constr->m_kind == LT || norm_constr->m_kind == EQ); + bool strict = norm_constr->m_kind == LT; + if (!ci.upper_bound_is_set()) { + ls->m_upper_bound_witness = norm_constr; + ci.set_upper_bound(v); + ci.set_upper_bound_strict(strict); + } else if (ci.get_upper_bound() > v) { + ci.set_upper_bound(v); + ls->m_upper_bound_witness = norm_constr; + ci.set_upper_bound_strict(strict); + } + if (ci.is_infeasible()) { + m_status= INFEASIBLE; + m_infeasible_canonic_left_side = ls; + return; + } + try_to_set_fixed(ci); + } + + bool try_to_set_fixed(column_info & ci) { + if (ci.upper_bound_is_set() && ci.low_bound_is_set() && ci.get_upper_bound() == ci.get_low_bound() && !ci.is_fixed()) { + ci.set_fixed_value(ci.get_upper_bound()); + return true; + } + return false; + } + + void set_low_bound_for_column_info(lar_normalized_constraint * norm_constr) { + const mpq & v = norm_constr->m_right_side; + canonic_left_side * ls = norm_constr->m_canonic_left_side; + column_info & ci = ls->m_column_info; + lean_assert(norm_constr->m_kind == GE || norm_constr->m_kind == GT || norm_constr->m_kind == EQ); + bool strict = norm_constr->m_kind == GT; + if (!ci.low_bound_is_set()) { + ci.set_low_bound(v); + ls->m_low_bound_witness = norm_constr; + ci.set_low_bound_strict(strict); + } else if (ci.get_low_bound() < v) { + ci.set_low_bound(v); + ls->m_low_bound_witness = norm_constr; + ci.set_low_bound_strict(strict); + } + + if (ci.is_infeasible()) { + m_status= INFEASIBLE; + m_infeasible_canonic_left_side = ls; + return; + } + + try_to_set_fixed(ci); + } + + void update_column_info_of_normalized_constraint(lar_normalized_constraint & norm_constr) { + lean_assert(norm_constr.size() > 0); + switch (norm_constr.m_kind) { + case LE: + case LT: + set_upper_bound_for_column_info(&norm_constr); + break; + case GE: + case GT: + set_low_bound_for_column_info(&norm_constr); + break; + + case EQ: + { + set_upper_bound_for_column_info(&norm_constr); + set_low_bound_for_column_info(&norm_constr); + } + break; + default: + throw "unexpected"; + } + } + + column_type get_column_type(column_info & ci) { + auto ret = ci.get_column_type_no_flipping(); + if (ret == boxed) { // changing boxed to fixed because of the no span + if (ci.get_low_bound() == ci.get_upper_bound()) + ret = fixed; + } + return ret; + } + + void fill_column_names() { + m_column_names.clear(); + for (auto t : m_canonic_left_sides) { + auto & ci = t->m_column_info; + unsigned j = t->m_column_index; + lean_assert(valid_index(j)); + string name = ci.get_name(); + if (name.size() == 0) + name = string("_s") + T_to_string(j); + m_column_names[j] = name; + } + } + + void fill_column_types() { + m_column_types.clear(); + m_column_types.resize(m_canonic_left_sides.size(), free_column); + for (auto t : m_canonic_left_sides) { + auto & ci = t->m_column_info; + unsigned j = t->m_column_index; + lean_assert(valid_index(j)); + m_column_types[j] = get_column_type(ci); + } + } + + template + void fill_bounds_for_core_solver(vector & lb, vector & ub) { + unsigned n = m_canonic_left_sides.size(); // this is the number of columns + lb.resize(n); + ub.resize(n); + for (auto t : m_canonic_left_sides) { + auto & ci = t->m_column_info; + unsigned j = t->m_column_index; + lean_assert(valid_index(j)); + if (ci.low_bound_is_set()) + lb[j] = conversion_helper::get_low_bound(ci); + if (ci.upper_bound_is_set()) + ub[j] = conversion_helper::get_upper_bound(ci); + } + } + + + template + void resize_x_and_init_with_zeros(vector & x, unsigned n) { + x.clear(); + x.resize(n, zero_of_type()); // init with zeroes + } + + template + void resize_x_and_init_with_signature(vector & x, vector & low_bound, + vector & upper_bound, const lar_solution_signature & signature) { + x.clear(); + x.resize(low_bound.size()); + for (auto & t : signature.non_basic_column_value_positions) { + x[t.first] = get_column_val(low_bound, upper_bound, t.second, t.first); + } + } + + template V get_column_val(vector & low_bound, vector & upper_bound, non_basic_column_value_position pos_type, unsigned j) { + switch (pos_type) { + case at_low_bound: return low_bound[j]; + case at_fixed: + case at_upper_bound: return upper_bound[j]; + case free_of_bounds: return zero_of_type(); + default: + throw "unexpected type"; + } + } + +public: + ~lar_solver() { + vector to_delete; + for (auto it : m_canonic_left_sides) + to_delete.push_back(it); + for (auto t : to_delete) + delete t; + } + + lp_settings & settings() { return m_settings;} + + void clear() { + lean_assert(false); // not implemented + } + + lar_solver() : m_mpq_core_solver(m_x, + m_column_types, + m_low_bounds, + m_upper_bounds, + m_basis, + m_A, + m_settings, + m_column_names, + m_right_side_vector, + m_costs) { + } + + + var_index add_var(string s) { + auto got = m_var_names_to_var_index.find(s); + if (got != m_var_names_to_var_index.end()) return got->second; + + var_index i = m_available_var_index++; + m_var_names_to_var_index[s] = i; + add_canonic_left_side_for_var(i, s); + return i; + } + + constraint_index add_constraint(const buffer>& left_side, lconstraint_kind kind_par, mpq right_side_par) { + if (left_side.size() == 0) { + cout << "cannot add a constraint without left side" << endl; + return (constraint_index)(-1); + } + constraint_index i = m_available_constr_index++; + lar_constraint original_constr(left_side, kind_par, right_side_par, i); + canonic_left_side * ls = create_or_fetch_existing_left_side(left_side); + mpq ratio = find_ratio(ls, original_constr); + auto kind = ratio.is_neg()? flip_kind(kind_par): kind_par; + mpq right_side = right_side_par / ratio; + lar_normalized_constraint normalized_constraint(ls, ratio, kind, right_side, original_constr); + + m_normalized_constraints[i] = normalized_constraint; + return i; + } + + bool is_infeasible(const column_info & ci) { + return ci.low_bound_is_set() && ci.upper_bound_is_set() && ci.get_low_bound() > ci.get_upper_bound(); + } + + bool all_constraints_hold() { + unordered_map var_map; + get_model(var_map); + for ( auto & it : m_normalized_constraints ) + if (!constraint_holds(it.second.m_origin_constraint, var_map)) { + print_constraint(&it.second.m_origin_constraint); + cout << endl; + return false; + } + return true; + } + + bool constraint_holds(const lar_constraint & constr, unordered_map & var_map) { + mpq left_side_val = get_left_side_val(constr, var_map); + switch (constr.m_kind) { + case LE: return left_side_val <= constr.m_right_side; + case LT: return left_side_val <= constr.m_right_side; + case GE: return left_side_val >= constr.m_right_side; + case GT: return left_side_val >= constr.m_right_side; + case EQ: return left_side_val == constr.m_right_side; + + default: + throw "unexpected"; + return false; + } + } + + lp_status get_status() const { return m_status;} + + void solve_with_core_solver() { + m_mpq_core_solver.solve(); + m_status = m_mpq_core_solver.m_status; + lean_assert(m_status != OPTIMAL || all_constraints_hold()); + lean_assert(!settings().row_feasibility || m_status != INFEASIBLE || the_evidence_is_correct()); + } + + bool the_relations_are_of_same_type(const buffer> & evidence, lconstraint_kind & the_kind_of_sum) { + unsigned n_of_G = 0, n_of_L = 0; + bool strict = false; + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + cout << coeff.get_double() << endl; + lar_constraint & constr = m_normalized_constraints[con_ind].m_origin_constraint; + print_constraint(&constr); cout << endl; + + lconstraint_kind kind = coeff.is_pos()? constr.m_kind: flip_kind(constr.m_kind); + if (kind == GT || kind == LT) + strict = true; + if (kind == GE || kind == GT) n_of_G++; + else if (kind == LE || kind == LT) n_of_L++; + } + the_kind_of_sum = n_of_G? GE : LE; + if (strict) + the_kind_of_sum = static_cast((static_cast(the_kind_of_sum)/2)); + + return n_of_G == 0 || n_of_L == 0; + } + + void register_in_map(unordered_map & coeffs, lar_constraint & cn, const mpq & a) { + for (auto & it : cn.m_left_side) { + unsigned j = it.first; + auto p = coeffs.find(j); + if (p == coeffs.end()) coeffs[j] = it.second * a; + else p->second += it.second * a; + } + } + bool the_left_sides_sum_to_zero(const buffer> & evidence) { + unordered_map coeff_map; + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lar_constraint & constr = m_normalized_constraints[con_ind].m_origin_constraint; + register_in_map(coeff_map, constr, coeff); + } + for (auto & it : coeff_map) { + if (!numeric_traits::is_zero(it.second)) return false; + } + return true; + } + + bool the_righ_sides_do_not_sum_to_zero(const buffer> & evidence) { + mpq ret = numeric_traits::zero(); + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lar_constraint & constr = m_normalized_constraints[con_ind].m_origin_constraint; + ret += constr.m_right_side * coeff; + } + return !numeric_traits::is_zero(ret); + } + + bool the_evidence_is_correct() { + buffer> evidence; + get_infeasibility_evidence(evidence); + lconstraint_kind kind; + lean_assert(the_relations_are_of_same_type(evidence, kind)); + lean_assert(the_left_sides_sum_to_zero(evidence)); + mpq rs = sum_of_right_sides_of_evidence(evidence); + switch (kind) { + case LE: lean_assert(rs < zero_of_type()); + break; + case LT: lean_assert(rs <= zero_of_type()); + break; + case GE: lean_assert(rs > zero_of_type()); + break; + case GT: lean_assert(rs >= zero_of_type()); + break; + case EQ: lean_assert(rs != zero_of_type()); + break; + default: + lean_assert(false); + return false; + } + return true; + } + void update_column_info_of_normalized_constraints() { + for (auto & it : m_normalized_constraints) + update_column_info_of_normalized_constraint(it.second); + } + + template + void init_right_sides_with_zeros(vector & rs) { + rs.clear(); + rs.resize(m_basis.size(), zero_of_type()); + } + + mpq sum_of_right_sides_of_evidence(const buffer> & evidence) { + mpq ret = numeric_traits::zero(); + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lar_constraint & constr = m_normalized_constraints[con_ind].m_origin_constraint; + ret += constr.m_right_side * coeff; + } + return ret; + } + void prepare_independently_of_numeric_type() { + update_column_info_of_normalized_constraints(); + map_left_sides_to_columns_of_A(); + fill_column_names(); + fill_column_types(); + } + + template + void prepare_core_solver_fields(static_matrix & A, vector & x, + vector & right_side_vector, + vector & low_bound, + vector & upper_bound) { + create_matrix_A(A); + fill_bounds_for_core_solver(low_bound, upper_bound); + if (m_status == INFEASIBLE) { + lean_assert(false); // not implemented + } + init_right_sides_with_zeros(right_side_vector); + resize_x_and_init_with_zeros(x, A.column_count()); + lean_assert(m_basis.size() == A.row_count()); + } + + template + void prepare_core_solver_fields_with_signature(static_matrix & A, vector & x, + vector & right_side_vector, + vector & low_bound, + vector & upper_bound, const lar_solution_signature & signature) { + create_matrix_A(A); + fill_bounds_for_core_solver(low_bound, upper_bound); + if (m_status == INFEASIBLE) { + lean_assert(false); // not implemented + } + init_right_sides_with_zeros(right_side_vector); + resize_x_and_init_with_signature(x, low_bound, upper_bound, signature); + } + + void find_solution_signature_with_doubles(lar_solution_signature & signature) { + static_matrix A; + vector x, right_side_vector, low_bounds, upper_bounds; + prepare_core_solver_fields(A, x, right_side_vector, low_bounds, upper_bounds); + vector column_scale_vector; + scaler scaler(right_side_vector, A, m_settings.scaling_minimum, m_settings.scaling_maximum, column_scale_vector, this->m_settings); + if (!scaler.scale()) { + // the scale did not succeed, unscaling + A.clear(); + create_matrix_A(A); + for (auto & s : column_scale_vector) + s = one_of_type(); + } + vector costs(A.column_count()); + auto core_solver = lp_primal_core_solver(A, + right_side_vector, + x, + m_basis, + costs, + m_column_types, + low_bounds, + upper_bounds, + m_settings, + m_column_names); + core_solver.find_feasible_solution(); + extract_signature_from_lp_core_solver(core_solver, signature); + } + + template + void extract_signature_from_lp_core_solver(lp_primal_core_solver & core_solver, lar_solution_signature & signature) { + for (auto j : core_solver.m_non_basic_columns) + signature.non_basic_column_value_positions[j] = core_solver.get_non_basic_column_value_position(j); + } + + void solve_on_signature(const lar_solution_signature & signature) { + prepare_core_solver_fields_with_signature(m_A, m_x, m_right_side_vector, m_low_bounds, m_upper_bounds, signature); + solve_with_core_solver(); + } + + void solve() { + prepare_independently_of_numeric_type(); + if (m_settings.use_double_solver_for_lar) { + lar_solution_signature solution_signature; + find_solution_signature_with_doubles(solution_signature); + // here the basis that is kept in m_basis is the same that was used in the double solver + solve_on_signature(solution_signature); + return; + } + prepare_core_solver_fields(m_A, m_x, m_right_side_vector, m_low_bounds, m_upper_bounds); + solve_with_core_solver(); + } + + lp_status check() { + // for the time being just call solve() + solve(); + return m_status; + } + void get_infeasibility_evidence(buffer> & evidence){ + if (!m_mpq_core_solver.get_infeasible_row_sign()) { + cout << "don't have the infeasibility evidence" << endl; + return; + } + // the infeasibility sign + int inf_sign; + auto inf_row = m_mpq_core_solver.get_infeasibility_info(inf_sign); + lean_assert(inf_sign != 0); + get_infeasibility_evidence_for_inf_sign(evidence, inf_row, inf_sign); + } + + void get_infeasibility_evidence_for_inf_sign(buffer> & evidence, + const vector> & inf_row, + int inf_sign) { + for (auto & it : inf_row) { + mpq coeff = it.first; + unsigned j = it.second; + canonic_left_side * ls = m_column_indices_to_canonic_left_sides[j]; + int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; + + lar_normalized_constraint * bound_constr = adj_sign < 0? ls->m_upper_bound_witness : ls->m_low_bound_witness; + lean_assert(bound_constr != nullptr); + evidence.push_back(std::make_pair(coeff / bound_constr->m_ratio_to_original, bound_constr->m_index)); + } + } + + + mpq find_delta_for_strict_bounds() { + mpq delta = numeric_traits::one(); + for (auto t : m_canonic_left_sides) { + auto & ci = t->m_column_info; + unsigned j = t->m_column_index; + lean_assert (valid_index(j)); + if (ci.low_bound_is_set()) + restrict_delta_on_low_bound_column(delta, j); + if (ci.upper_bound_is_set()) + restrict_delta_on_upper_bound(delta, j); + } + return delta; + } + + void restrict_delta_on_low_bound_column(mpq& delta, unsigned j) { + numeric_pair & x = m_x[j]; + numeric_pair & l = m_low_bounds[j]; + mpq & xx = x.x; + mpq & xy = x.y; + mpq & lx = l.x; + if (xx == lx) { + lean_assert(xy >= numeric_traits::zero()); + } else { + lean_assert(xx >= lx); // we need lx <= xx + delta*xy, or delta*xy >= lx - xx, or - delta*xy <= xx - ls. + // The right part is not negative. The delta is positive. If xy >= 0 we have the ineqality + // otherwise we need to have delta not greater than - (xx - lx)/xy. We use the 2 coefficient to handle the strict case + if (xy >= zero_of_type()) return; + delta = std::min(delta, (lx - xx)/ (2 * xy)); // we need to have delta * xy < xx - lx for the strict case + } + } + void restrict_delta_on_upper_bound(mpq& delta, unsigned j) { + numeric_pair & x = m_x[j]; + numeric_pair & u = m_upper_bounds[j]; + mpq & xx = x.x; + mpq & xy = x.y; + mpq & ux = u.x; + if (xx == ux) { + lean_assert(xy <= numeric_traits::zero()); + } else { + lean_assert(xx < ux); + if (xy <= zero_of_type()) return; + delta = std::min(delta, (ux - xx)/ (2 * xy)); // we need to have delta * xy < ux - xx, for the strict case + } + } + + void get_model(unordered_map & variable_values){ + lean_assert(m_status == OPTIMAL); + mpq delta = find_delta_for_strict_bounds(); + for (auto & it : m_map_from_var_index_to_left_side) { + numeric_pair & rp = m_x[it.second->m_column_index]; + // cout << it.second->m_column_info.get_name() << " = " << rp << endl; + variable_values[it.first] = rp.x + delta * rp.y; + } + } + + string get_variable_name(var_index vi) { + if (m_map_from_var_index_to_left_side.size() <= vi) { + string s="variable " + T_to_string(vi) + " is not found"; + return s; + } + return m_map_from_var_index_to_left_side[vi]->m_column_info.get_name(); + } + + // ********** print region start + void print_constraint(constraint_index ci) { + if (m_normalized_constraints.size() <= ci) { + string s = "constraint " + T_to_string(ci) + " is not found"; + cout << s << endl; + return; + } + + print_constraint(&m_normalized_constraints[ci]); + } + + void print_canonic_left_side(const canonic_left_side & c) { + bool first = true; + for (auto it : c.m_coeffs) { + auto val = it.first; + if (first) { + first = false; + } else { + if (val.is_pos()) { + cout << " + "; + } else { + cout << " - "; + val = -val; + } + } + if (val != numeric_traits::one()) + cout << T_to_string(val); + cout << m_map_from_var_index_to_left_side[it.second]->m_column_info.get_name(); + } + } + + void print_left_side_of_constraint(const lar_base_constraint * c) { + bool first = true; + for (auto it : c->get_left_side_coefficients()) { + auto val = it.first; + if (numeric_traits::is_zero(val)) continue; + if (first) { + first = false; + } else { + if (val.is_pos()) { + cout << " + "; + } else { + cout << " - "; + val = -val; + } + } + + if (val != numeric_traits::one()) + cout << val; + cout << m_map_from_var_index_to_left_side[it.second]->m_column_info.get_name(); + } + } + + + numeric_pair get_infeasibility_from_core_solver(unordered_map & solution) { + prepare_independently_of_numeric_type(); + prepare_core_solver_fields(m_A, m_x, m_right_side_vector, m_low_bounds, m_upper_bounds); + m_mpq_core_solver.prefix(); // just to fill the core solver + + for (auto ls : m_canonic_left_sides) { + lean_assert(valid_index(ls->m_column_index)); + m_x[ls->m_column_index] = numeric_pair(get_canonic_left_side_val(ls, solution), 0); + } + return m_mpq_core_solver.get_deb_inf(); + } + + void print_info_on_column(unsigned j) { + for (auto ls : m_canonic_left_sides) { + if (static_cast(ls->m_column_index) == j) { + auto & ci = ls->m_column_info; + if (ci.low_bound_is_set()) { + cout << "l = " << ci.get_low_bound(); + } + if (ci.upper_bound_is_set()) { + cout << "u = " << ci.get_upper_bound(); + } + cout << endl; + m_mpq_core_solver.print_column_info(j); + } + } + } + + mpq get_infeasibility_of_solution(unordered_map & solution) { + cout << "solution" << endl; + for (auto it : solution) { + cout << it.first << " = " << it.second.get_double() << endl; + } + mpq ret = numeric_traits::zero(); + for (auto it : m_normalized_constraints) { + ret += get_infeasibility_of_constraint(it.second, solution); + } + cout << "ret = " << ret.get_double() << endl; + auto core_inf = get_infeasibility_from_core_solver(solution); + cout << "core inf = " << T_to_string(core_inf) << endl; + lean_assert(numeric_pair(ret, 0) == core_inf); + return ret; + } + + mpq get_infeasibility_of_constraint(const lar_normalized_constraint & norm_constr, unordered_map & solution) { + auto kind = norm_constr.m_kind; + mpq left_side_val = get_canonic_left_side_val(norm_constr.m_canonic_left_side, solution); + + switch (kind) { + case LT: + case LE: return std::max(left_side_val - norm_constr.m_right_side, numeric_traits::zero()); + case GT: + case GE: return std::max(- (left_side_val - norm_constr.m_right_side), numeric_traits::zero()); + + case EQ: + return abs(left_side_val - norm_constr.m_right_side); + + default: + throw "unexpected"; + return numeric_traits::zero(); + } + } + + mpq get_canonic_left_side_val(canonic_left_side * ls, unordered_map & solution) { + mpq ret = numeric_traits::zero(); + for (auto it : ls->m_coeffs) { + var_index j = it.second; + auto vi = m_map_from_var_index_to_left_side.find(j); + lean_assert(vi != m_map_from_var_index_to_left_side.end()); + canonic_left_side * var_ls = vi->second; + string s = var_ls->m_column_info.get_name(); + auto t = solution.find(s); + lean_assert(t != solution.end()); + ret += it.first * (t->second); + } + return ret; + } + + mpq get_left_side_val(const lar_constraint & cns, const unordered_map & var_map) { + mpq ret = numeric_traits::zero(); + for (auto it : cns.m_left_side) { + var_index j = it.first; + auto vi = var_map.find(j); + lean_assert(vi != var_map.end()); + ret += it.second * vi->second; + } + return ret; + } + + void print_constraint(const lar_base_constraint * c) { + print_left_side_of_constraint(c); + cout <<" " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side; + } + unsigned get_total_iterations() const { return m_mpq_core_solver.m_total_iterations; } +}; +} diff --git a/src/util/lp/lp.h b/src/util/lp/lp.h new file mode 100644 index 0000000000..e85aa48cd4 --- /dev/null +++ b/src/util/lp/lp.h @@ -0,0 +1,13 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/debug.h" +#include "util/numerics/numeric_traits.h" +#include "util/numerics/xnumeral.h" +#include "util/lp/lp_primal_core_solver.h" diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h new file mode 100644 index 0000000000..17c365e60f --- /dev/null +++ b/src/util/lp/lp_core_solver_base.h @@ -0,0 +1,757 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/lp/lp.h" +#include "util/lp/core_solver_pretty_printer.h" +#include +#include +#include "util/lp/numeric_pair.h" +namespace lean { + void init_basic_part_of_basis_heading(std::vector & basis, unsigned m, vector & basis_heading) { + for (unsigned i = 0; i < m; i++) { + unsigned column = basis[i]; + basis_heading[column] = i; + } +} + +void init_non_basic_part_of_basis_heading(vector & basis_heading, vector & non_basic_columns, unsigned n) { + for (int j = n; j--;){ + if (basis_heading[j] < 0) { + non_basic_columns.push_back(j); + // the index of column j in m_non_basic_columns is (- basis_heading[j] - 1) + basis_heading[j] = - non_basic_columns.size(); + } + } +} +void init_basis_heading_and_non_basic_columns_vector(std::vector & basis, + unsigned m, + vector & basis_heading, + unsigned n, + vector & non_basic_columns) { + init_basic_part_of_basis_heading(basis, m, basis_heading); + init_non_basic_part_of_basis_heading(basis_heading, non_basic_columns, n); +} + +template // X represents the type of the x variable and the bounds +class lp_core_solver_base { +public: + unsigned m_m; // it is the length of basis. The matrix m_A has m_m rows and the dimension of the matrix A is m_m + unsigned m_n; // the number of columns in the matrix m_A + std::vector m_pivot_row_of_B_1; // the pivot row of the reverse of B + std::vector m_pivot_row; // this is the real pivot row of the simplex tableu + vector m_pivot_row_index; + static_matrix & m_A; // the matrix A + vector & m_b; // the right side + std::vector & m_basis; + std::vector m_basis_heading; + std::vector & m_x; // a feasible solution, the fist time set in the constructor + std::vector & m_costs; + lp_settings & m_settings; + std::vector m_y; // the buffer for yB = cb + lp_status m_status; + // a device that is able to solve Bx=c, xB=d, and change the basis + lu * m_factorization; + const unordered_map & m_column_names; + indexed_vector m_w; // the vector featuring in 24.3 of the Chvatal book + std::vector m_d; // the vector of reduced costs + std::vector m_ed; // the solution of B*m_ed = a + vector m_index_of_ed; + unsigned m_total_iterations = 0; + int m_start_time; + unsigned m_iters_with_no_cost_growing = 0; + vector m_non_basic_columns; + vector & m_column_type; + vector & m_low_bound_values; + vector & m_upper_bound_values; + vector m_column_norms; // the approximate squares of column norms that help choosing a profitable column + vector m_copy_of_xB; + unsigned m_refactor_counter = 200; + lp_core_solver_base(static_matrix & A, + vector & b, // the right side vector + std::vector & basis, + std::vector & x, + std::vector & costs, + lp_settings & settings, + const unordered_map & column_names, + vector & column_types, + vector & low_bound_values, + vector & upper_bound_values): + m_m(A.row_count()), + m_n(A.column_count()), + m_pivot_row_of_B_1(m_m), + m_pivot_row(m_n, zero_of_type()), + m_A(A), + m_b(b), + m_basis(basis), + m_x(x), + m_costs(costs), + m_settings(settings), + m_y(m_m), + m_status(FEASIBLE), + m_factorization(nullptr), + m_column_names(column_names), + m_w(m_m), + m_d(m_n), + m_ed(m_m), + m_column_type(column_types), + m_low_bound_values(low_bound_values), + m_upper_bound_values(upper_bound_values), + m_column_norms(m_n, T(1)), + m_copy_of_xB(m_m) { + if (m_m) { + lean_assert(m_A.col_val_equal_to_row_val()); + init(); + init_basis_heading(); + } + } + + void allocate_basis_heading() { // the rest of initilization will be handled by the factorization class + m_basis_heading.clear(); + m_basis_heading.resize(m_n, -1); + } + void init() { + lean_assert(m_costs.size() == m_n); + lean_assert(m_basis.size() == m_m); + lean_assert(m_b.size() == m_m); + allocate_basis_heading(); + init_factorization(m_factorization, m_A, m_basis, m_basis_heading, m_settings, m_non_basic_columns); + m_refactor_counter = 0; + srand48(1); + } + + virtual ~lp_core_solver_base() { + if (m_factorization != nullptr) + delete m_factorization; + } + + vector & non_basis() { + return m_factorization->m_non_basic_columns; + } + + void set_status(lp_status status) { + m_status = status; + } + lp_status get_status() { + return m_status; + } + + void fill_cb(T * y){ + for (unsigned i = 0; i < m_m; i++) { + y[i] = m_costs[m_basis[i]]; + } + } + + + void fill_cb(std::vector & y){ + for (unsigned i = 0; i < m_m; i++) + y[i] = m_costs[m_basis[i]]; + } + + void solve_yB(std::vector & y) { + fill_cb(y); // now y = cB, that is the projection of costs to basis + m_factorization->solve_yB(y); + } + + void update_index_of_ed() { + m_index_of_ed.clear(); + unsigned i = m_ed.size(); + while (i--) { + if (!is_zero(m_ed[i])) + m_index_of_ed.push_back(i); + } + } + + void solve_Bd(unsigned entering) { + m_factorization->solve_Bd(entering, m_ed, m_w); + update_index_of_ed(); +#ifndef NDEBUG + // auto B = get_B(m_factorization); + // vector a(m_m); + // m_A.copy_column_to_vector(entering, a); + // vector cd(m_ed); + // B.apply_from_left(cd, m_settings); + // lean_assert(vectors_are_equal(cd , a)); +#endif + } + + void pretty_print() { + core_solver_pretty_printer pp(*this); + pp.print(); + } + + void save_state(T * w_buffer, T * d_buffer) { + copy_m_w(w_buffer); + copy_m_ed(d_buffer); + } + + void restore_state(T * w_buffer, T * d_buffer) { + restore_m_w(w_buffer); + restore_m_ed(d_buffer); + } + + X get_cost() { + return dot_product(m_costs, m_x, m_n); + } + + void copy_m_w(T * buffer) { + unsigned i = m_m; + while (i --) { + buffer[i] = m_w[i]; + } + } + + void restore_m_w(T * buffer) { + m_w.m_index.clear(); + unsigned i = m_m; + while (i--) { + if (!is_zero(m_w[i] = buffer[i])) + m_w.m_index.push_back(i); + } + } + + // needed for debugging + void copy_m_ed(T * buffer) { + unsigned i = m_m; + while (i --) { + buffer[i] = m_ed[i]; + } + } + + void restore_m_ed(T * buffer) { + unsigned i = m_m; + while (i --) { + m_ed[i] = buffer[i]; + } + } + + bool A_mult_x_is_off() { + if (precise()) { + return false; + } + + T feps = convert_struct::convert(m_settings.refactor_tolerance); + X one = convert_struct::convert(1.0); + for (unsigned i = 0; i < m_m; i++) { + X delta = abs(m_b[i] - m_A.dot_product_with_row(i, m_x)); + X eps = feps * (one + T(0.1) * abs(m_b[i])); + + if (delta >eps) { + cout << "x is off ("; + cout << "m_b[" << i << "] = " << m_b[i] << " "; + cout << "left side = " << m_A.dot_product_with_row(i, m_x) << ' '; + cout << "delta = " << delta << ' '; + cout << "iters = " << m_total_iterations << ")" << endl; + return true; + } + } + return false; + } + // from page 182 of Istvan Maros's book + void calculate_pivot_row_of_B_1(unsigned pivot_row) { + unsigned i = m_m; + while (i--) { + m_pivot_row_of_B_1[i] = numeric_traits::zero(); + } + m_pivot_row_of_B_1[pivot_row] = numeric_traits::one(); + m_factorization->solve_yB(m_pivot_row_of_B_1); + } + + void zero_pivot_row() { + for (unsigned j : m_pivot_row_index) + m_pivot_row[j] = numeric_traits::zero(); + m_pivot_row_index.clear(); + } + + void calculate_pivot_row_when_pivot_row_of_B1_is_ready() { + zero_pivot_row(); + int i = m_m; + while (i--) { + T pi_1 = m_pivot_row_of_B_1[i]; + if (numeric_traits::is_zero(pi_1)) { + continue; + } + for (auto & c : m_A.m_rows[i]) { + unsigned j = c.m_j; + if (m_factorization->m_basis_heading[j] < 0) { + m_pivot_row[j] += c.get_val() * pi_1; + } + } + } + + unsigned j = m_pivot_row.size(); + while (j--) { + if (!is_zero(m_pivot_row[j])) + m_pivot_row_index.push_back(j); + } + } + + void update_x(unsigned entering, X delta) { + if (is_zero(delta)) { + return; + } + m_x[entering] += delta; + for (unsigned i : m_index_of_ed) { + m_copy_of_xB[i] = m_x[m_basis[i]]; + m_x[m_basis[i]] -= delta * m_ed[i]; + } + } + + T get_var_value(unsigned j) const { + return m_x[j]; + } + + void print_statistics(X cost) { + cout << "cost = " << T_to_string(cost) << + ", nonzeros = " << m_factorization->get_number_of_nonzeroes() << endl; + } + + bool print_statistics_with_iterations_and_check_that_the_time_is_over(unsigned total_iterations) { + if (total_iterations % m_settings.report_frequency == 0) { + cout << "iterations = " << total_iterations << ", nonzeros = " << m_factorization->get_number_of_nonzeroes() << endl; + if (time_is_over()) { + return true; + } + } + return false; + } + + bool print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(string str, unsigned total_iterations) { + if (total_iterations % m_settings.report_frequency == 0) { + cout << str << " iterations = " << total_iterations << " cost = " << T_to_string(get_cost()) <<", nonzeros = " << m_factorization->get_number_of_nonzeroes() << endl; + if (time_is_over()) { + return true; + } + } + return false; + } + + bool print_statistics_with_cost_and_check_that_the_time_is_over(unsigned total_iterations, X cost) { + if (total_iterations % m_settings.report_frequency == 0) { + cout << "iterations = " << total_iterations << ", "; + print_statistics(cost); + if (time_is_over()) { + return true; + } + } + return false; + } + + bool print_statistics_and_check_that_the_time_is_over(unsigned total_iterations) { + if (total_iterations % (numeric_traits::precise()? static_cast(m_settings.report_frequency/10) : m_settings.report_frequency) == 0) { + cout << "iterations = " << total_iterations << ", "; + if (time_is_over()) { + return true; + } + } + return false; + } + + void set_non_basic_x_to_correct_bounds() { + for (unsigned j : non_basis()) { + switch (m_column_type[j]) { + case boxed: + m_x[j] = m_d[j] < 0? m_upper_bound_values[j]: m_low_bound_values[j]; + break; + case low_bound: + m_x[j] = m_low_bound_values[j]; + lean_assert(column_is_dual_feasible(j)); + break; + case upper_bound: + m_x[j] = m_upper_bound_values[j]; + lean_assert(column_is_dual_feasible(j)); + break; + default: + break; + } + } + } + bool at_bound(const X &x, const X & bound) const { + return !below_bound(x, bound) && !above_bound(x, bound); + } + + bool below_bound(const X & x, const X & bound) const { + if (precise()) return x < bound; + return below_bound_numeric(x, bound, m_settings.primal_feasibility_tolerance); + } + + bool above_bound(const X & x, const X & bound) const { + if (precise()) return x > bound; + return above_bound_numeric(x, bound, m_settings.primal_feasibility_tolerance); + } + + bool x_below_low_bound(unsigned p) { + return below_bound(m_x[p], m_low_bound_values[p]); + } + + bool x_above_upper_bound(unsigned p) { + return above_bound(m_x[p], m_upper_bound_values[p]); + } + + + bool x_is_at_low_bound(unsigned j) const { + return at_bound(m_x[j], m_low_bound_values[j]); + } + bool x_is_at_upper_bound(unsigned j) const { + return at_bound(m_x[j], m_upper_bound_values[j]); + } + + bool x_is_at_bound(unsigned j) const { + return x_is_at_low_bound(j) || x_is_at_upper_bound(j); + } + + bool column_is_dual_feasible(unsigned j) { + switch (m_column_type[j]) { + case fixed: + case boxed: + return (x_is_at_low_bound(j) && d_is_not_negative(j)) || + (x_is_at_upper_bound(j) && d_is_not_positive(j)); + case low_bound: + return x_is_at_low_bound(j) && d_is_not_negative(j); + case upper_bound: + cout << "upper_bound type should be switched to low_bound" << endl; + lean_assert(false); // impossible case + case free_column: + return numeric_traits::is_zero(m_d[j]); + default: + cout << "column = " << j << endl; + cout << "unexpected column type = " << column_type_to_string(m_column_type[j]) << endl; + lean_assert(false); + throw "unexpected column type"; + break; + } + } + bool d_is_not_negative(unsigned j) { + if (numeric_traits::precise()) { + return m_d[j] >= numeric_traits::zero(); + } + return m_d[j] > -T(0.00001); + } + + bool d_is_not_positive(unsigned j) { + if (numeric_traits::precise()) { + return m_d[j] <= numeric_traits::zero(); + } + return m_d[j] < T(0.00001); + } + + + bool time_is_over() { + int span_in_mills = get_millisecond_span(m_start_time); + if (span_in_mills / 1000.0 > m_settings.time_limit) { + cout << "time is over" << endl; + return true; + } + return false; + } + + void rs_minus_Anx(vector & rs) { + unsigned row = m_m; + while (row--) { + auto &rsv = rs[row] = m_b[row]; + for (auto & it : m_A.m_rows[row]) { + unsigned j = it.m_j; + if (m_basis_heading[j] < 0) { + rsv -= m_x[j] * it.get_val(); + } + } + } + } + + bool find_x_by_solving() { + solve_Ax_eq_b(); + bool ret= !A_mult_x_is_off(); + if (ret) + cout << "find_x_by_solving succeeded" << endl; + else + cout << "find_x_by_solving did not succeed" << endl; + return ret; + } + + bool update_basis_and_x(int entering, int leaving, X const & tt) { + if (!is_zero(tt)) { + update_x(entering, tt); + if (A_mult_x_is_off() && !find_x_by_solving()) { + init_factorization(m_factorization, m_A, m_basis, m_basis_heading, m_settings, m_non_basic_columns); + m_refactor_counter = 0; + + if (!find_x_by_solving()) { + restore_x(entering, tt); + lean_assert(!A_mult_x_is_off()); + init_factorization(m_factorization, m_A, m_basis, m_basis_heading, m_settings, m_non_basic_columns); + m_refactor_counter = 0; + m_iters_with_no_cost_growing++; + if (m_factorization->get_status() != LU_status::OK) { + cout << "failing refactor on off_result for entering = " << entering << ", leaving = " << leaving << " total_iterations = " << m_total_iterations << endl; + throw ""; + } + return false; + } + } + } + + bool refactor = m_refactor_counter++ >= 200; + if (!refactor) { + const T & pivot = this->m_pivot_row[entering]; // m_ed[m_factorization->basis_heading(leaving)] is the same but the one that we are using is more precise + m_factorization->replace_column(leaving, pivot, m_w); + if (m_factorization->get_status() == LU_status::OK) { + m_factorization->change_basis(entering, leaving); + return true; + } + } + // need to refactor + m_refactor_counter = 0; + m_factorization->change_basis(entering, leaving); + init_factorization(m_factorization, m_A, m_basis, m_basis_heading, m_settings, m_non_basic_columns); + if (m_factorization->get_status() != LU_status::OK || A_mult_x_is_off()) { + cout << "failing refactor for entering = " << entering << ", leaving = " << leaving << " total_iterations = " << m_total_iterations << endl; + restore_x_and_refactor(entering, leaving, tt); + lean_assert(!A_mult_x_is_off()); + m_iters_with_no_cost_growing++; + cout << "rolled back after failing of init_factorization()" << endl; + m_status = UNSTABLE; + return false; + } + return true; + } + + + void init_basis_heading() { + init_basis_heading_and_non_basic_columns_vector(m_basis, m_m, m_basis_heading, m_n, m_non_basic_columns); + lean_assert(basis_heading_is_correct()); + } + + bool basis_has_no_doubles() { + std::set bm; + for (unsigned i = 0; i < m_m; i++) { + bm.insert(m_basis[i]); + } + return bm.size() == m_m; + } + + bool non_basis_has_no_doubles() { + std::set bm; + for (auto j : m_non_basic_columns) { + bm.insert(j); + } + return bm.size() == m_non_basic_columns.size(); + } + + bool basis_is_correctly_represented_in_heading() { + for (unsigned i = 0; i < m_m; i++) { + if (m_basis_heading[m_basis[i]] != i) + return false; + } + return true; + } + bool non_basis_is_correctly_represented_in_heading() { + for (int i = 0; i < m_non_basic_columns.size(); i++) { + if (m_basis_heading[m_non_basic_columns[i]] != - i - 1) + return false; + } + for (int j = 0; j < m_A.column_count(); j++) { + if (m_basis_heading[j] >= 0) { + lean_assert(m_basis_heading[j] < m_A.row_count() && m_basis[m_basis_heading[j]] == j); + } + } + return true; + } + + bool basis_heading_is_correct() { + return basis_has_no_doubles() && non_basis_has_no_doubles() && basis_is_correctly_represented_in_heading() && non_basis_is_correctly_represented_in_heading(); + } + + void restore_x_and_refactor(int entering, int leaving, X const & t) { + m_factorization->restore_basis_change(entering, leaving); + restore_x(entering, t); + init_factorization(m_factorization, m_A, m_basis, m_basis_heading, m_settings, m_non_basic_columns); + if (m_factorization->get_status() == LU_status::Degenerated) { + cout << "cannot refactor" << endl; + m_status = lp_status::FLOATING_POINT_ERROR; + } + // solve_Ax_eq_b(); + if (A_mult_x_is_off()) { + cout << "cannot restore solution" << endl; + m_status = lp_status::FLOATING_POINT_ERROR; + return; + } + } + + void restore_x(unsigned entering, X const & t) { + if (is_zero(t)) return; + cout << "calling restore for entering " << entering << endl; + m_x[entering] -= t; + for (unsigned i : m_index_of_ed) { + m_x[m_basis[i]] = m_copy_of_xB[i]; + } + } + + void fill_reduced_costs_from_m_y_by_rows() { + unsigned j = m_n; + while (j--) { + if (m_factorization->m_basis_heading[j] < 0) + m_d[j] = m_costs[j]; + else + m_d[j] = numeric_traits::zero(); + } + + unsigned i = m_m; + while (i--) { + const T & y = m_y[i]; + if (is_zero(y)) continue; + for (auto & it : m_A.m_rows[i]) { + j = it.m_j; + if (m_factorization->m_basis_heading[j] < 0) + m_d[j] -= y * it.get_val(); + } + } + } + + void copy_rs_to_xB(vector & rs) { + unsigned j = m_m; + while (j--) { + m_x[m_basis[j]] = rs[j]; + } + } + virtual bool low_bounds_are_set() const { return false; } + X low_bound_value(unsigned j) const { return m_low_bound_values[j]; } + X upper_bound_value(unsigned j) const { return m_upper_bound_values[j]; } + + column_type get_column_type(unsigned j) const {return m_column_type[j]; } + + bool pivot_row_element_is_too_small_for_ratio_test(unsigned j) { + return m_settings.abs_val_is_smaller_than_pivot_tolerance(m_pivot_row[j]); + } + + X bound_span(unsigned j) { + return m_upper_bound_values[j] - m_low_bound_values[j]; + } + + std::string column_name(unsigned column) const { + auto it = m_column_names.find(column); + if (it == m_column_names.end()) { + std::string name = T_to_string(column); + return std::string(string("u") + name); + } + return it->second; + } + + void copy_right_side(vector & rs) { + unsigned i = m_m; + while (i --) { + rs[i] = m_b[i]; + } + } + + void add_delta_to_xB(vector & del) { + unsigned i = m_m; + while (i--) { + this->m_x[this->m_basis[i]] -= del[i]; + } + } + + void find_error_in_BxB(vector& rs){ + unsigned row = m_m; + while (row--) { + auto &rsv = rs[row]; + for (auto & it : m_A.m_rows[row]) { + unsigned j = it.m_j; + if (m_basis_heading[j] >= 0) { + rsv -= m_x[j] * it.get_val(); + } + } + } + } + + // recalculates the projection of x to B, such that Ax = b, whereab is the right side + void solve_Ax_eq_b() { + vector rs(m_m); + rs_minus_Anx(rs); + vector rrs = rs; // another copy of rs + m_factorization->solve_By(rs); + copy_rs_to_xB(rs); + find_error_in_BxB(rrs); + m_factorization->solve_By(rrs); + add_delta_to_xB(rrs); + } + + void snap_non_basic_x_to_bound() { + for (unsigned j : non_basis()) { + switch (m_column_type[j]) { + case fixed: + case boxed: + if (x_is_at_bound(j)) + break; // we should preserve x if possible + m_x[j] = m_low_bound_values[j]; + break; + case low_bound: + if (x_is_at_low_bound(j)) + break; + m_x[j] = m_low_bound_values[j]; + break; + case upper_bound: + if (x_is_at_upper_bound(j)) + break; + m_x[j] = m_upper_bound_values[j]; + break; + default: + break; + } + } + } + void snap_non_basic_x_to_bound_and_free_to_zeroes() { + for (unsigned j : non_basis()) { + lean_assert(j < m_x.size()); + switch (m_column_type[j]) { + case fixed: + case boxed: + case low_bound: + m_x[j] = m_low_bound_values[j]; + break; + case upper_bound: + m_x[j] = m_upper_bound_values[j]; + break; + default: + m_x[j] = zero_of_type(); + break; + } + } + } + void snap_xN_to_bounds() { + snap_non_basic_x_to_bound(); + solve_Ax_eq_b(); + } + + void snap_xN_to_bounds_and_free_columns_to_zeroes() { + snap_non_basic_x_to_bound_and_free_to_zeroes(); + solve_Ax_eq_b(); + } + + void init_reduced_costs_for_one_iteration() { + solve_yB(m_y); + fill_reduced_costs_from_m_y_by_rows(); + } + + non_basic_column_value_position get_non_basic_column_value_position(unsigned j) { + switch (m_column_type[j]) { + case fixed: + return at_fixed; + case free_column: + return free_of_bounds; + case boxed: + return x_is_at_low_bound(j)? at_low_bound : at_upper_bound; + case low_bound: + return at_low_bound; + case upper_bound: + return at_upper_bound; + default: + throw "unexpected column type"; + } + } +}; +} diff --git a/src/util/lp/lp_dual_core_solver.h b/src/util/lp/lp_dual_core_solver.h new file mode 100644 index 0000000000..87185710e7 --- /dev/null +++ b/src/util/lp/lp_dual_core_solver.h @@ -0,0 +1,833 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ +#pragma once +#include "util/lp/static_matrix.h" +#include "util/lp/lp_core_solver_base.h" +#include +#include +#include +#include +#include + +namespace lean { +template +class lp_dual_core_solver:public lp_core_solver_base { +public: + vector & m_can_enter_basis; + int m_r; // the row of the leaving column + int m_p; // leaving column; that is m_p = m_basis[m_r] + T m_delta; // the offset of the leaving basis variable + int m_sign_of_alpha_r; // see page 27 + T m_theta_D; + T m_theta_P; + int m_q; + // todo : replace by a vector later + std::set m_breakpoint_set; // it is F in "Progress in the dual simplex method ..." + std::set m_flipped_boxed; + std::set m_tight_set; // it is the set of all breakpoints that become tight when m_q becomes tight + vector m_a_wave; + vector m_betas; // m_betas[i] is approximately a square of the norm of the i-th row of the reverse of B + T m_harris_tolerance; + + lp_dual_core_solver(static_matrix & A, + vector & can_enter_basis, + vector & b, // the right side vector + vector & x, // the number of elements in x needs to be at least as large as the number of columns in A + vector & basis, + vector & costs, + vector & column_type_array, + vector & low_bound_values, + vector & upper_bound_values, + lp_settings & settings, + unordered_map const & column_names): + lp_core_solver_base(A, + b, + basis, + x, + costs, + settings, + column_names, + column_type_array, + low_bound_values, + upper_bound_values), + m_can_enter_basis(can_enter_basis), + m_a_wave(this->m_m), + m_betas(this->m_m) { + m_harris_tolerance = numeric_traits::precise()? numeric_traits::zero() : T(this->m_settings.harris_feasibility_tolerance); + this->solve_yB(this->m_y); + init_basic_part_of_basis_heading(this->m_basis, this->m_m, this->m_basis_heading); + fill_non_basis_with_only_able_to_enter_columns(); + } + + void init_a_wave_by_zeros() { + unsigned j = this->m_m; + while (j--) { + m_a_wave[j] = numeric_traits::zero(); + } + } + + void fill_non_basis_with_only_able_to_enter_columns() { + auto & nb = this->m_factorization->m_non_basic_columns; + nb.clear(); + unsigned j = this->m_n; + while (j--) { + if (this->m_basis_heading[j] >= 0 || !m_can_enter_basis[j]) continue; + nb.push_back(j); + this->m_basis_heading[j] = - nb.size(); + } + } + + void print_nb() { + cout << "this is nb " << endl; + for (auto l : this->m_factorization->m_non_basic_columns) { + cout << l << " "; + } + cout << endl; + } + + void restore_non_basis() { + auto & nb = this->m_factorization->m_non_basic_columns; + nb.clear(); + unsigned j = this->m_n; + while (j--) { + if (this->m_basis_heading[j] >= 0 ) continue; + if (m_can_enter_basis[j]) { + lean_assert(std::find(nb.begin(), nb.end(), j) == nb.end()); + nb.push_back(j); + this->m_basis_heading[j] = - nb.size(); + } + } + } + + bool update_basis(int entering, int leaving) { + // the second argument is the element of the entering column from the pivot row - its value should be equal to the low diagonal element of the bump after all pivoting is done + if (!(this->m_refactor_counter++ >= 200)) { + this->m_factorization->replace_column(leaving, this->m_ed[this->m_factorization->basis_heading(leaving)], this->m_w); + if (this->m_factorization->get_status() != LU_status::OK) { + cout << "failed on replace_column( " << leaving << ", " << this->m_ed[this->m_factorization->basis_heading(leaving)] << ") total_iterations = " << this->m_total_iterations << endl; + init_factorization(this->m_factorization, this->m_A, this->m_basis, this->m_basis_heading, this->m_settings, this->m_non_basic_columns); + this->m_iters_with_no_cost_growing++; + this->m_status = UNSTABLE; + return false; + } + this->m_factorization->change_basis(entering, leaving); + } else { // need to refactor + this->m_factorization->change_basis(entering, leaving); + init_factorization(this->m_factorization, this->m_A, this->m_basis, this->m_basis_heading, this->m_settings, this->m_non_basic_columns); + if (this->m_factorization->get_status() != LU_status::OK) { + cout << "failing refactor for entering = " << entering << ", leaving = " << leaving << " total_iterations = " << this->m_total_iterations << endl; + this->m_iters_with_no_cost_growing++; + return false; + } + } + return true; + } + + void recalculate_xB_and_d() { + this->solve_Ax_eq_b(); + recalculate_d(); + } + + void recalculate_d() { + this->solve_yB(this->m_y); + this->fill_reduced_costs_from_m_y_by_rows(); + } + + vector & non_basis() { return this->m_factorization->m_non_basic_columns; } + + void init_betas() { + // todo : look at page 194 of Progress in the dual simplex algorithm for solving large scale LP problems : techniques for a fast and stable implementation + // the current implementation is not good enough: todo + unsigned i = this->m_m; + while (i--) { + m_betas[i] = 1; + } + } + + void adjust_xb_for_changed_xn_and_init_betas() { + this->solve_Ax_eq_b(); + init_betas(); + } + + void start_with_initial_basis_and_make_it_dual_feasible() { + this->set_non_basic_x_to_correct_bounds(); // It is not an efficient version, see 3.29, + // however this version does not require that m_x is the solution of Ax = 0 beforehand + adjust_xb_for_changed_xn_and_init_betas(); + } + + bool done() { + if (this->m_status == OPTIMAL) { + return true; + } + if (this->m_total_iterations > this->m_settings.max_total_number_of_iterations) { // debug !!!! + this->m_status = ITERATIONS_EXHAUSTED; + return true; + } + return false; // todo, need to be more cases + } + + T get_edge_steepness_for_low_bound(unsigned p) { + lean_assert(this->m_basis_heading[p] >= 0 && this->m_basis_heading[p] < this->m_m); + T del = this->m_x[p] - this->m_low_bound_values[p]; + del *= del; + return del / this->m_betas[this->m_basis_heading[p]]; + } + + T get_edge_steepness_for_upper_bound(unsigned p) { + lean_assert(this->m_basis_heading[p] >= 0 && this->m_basis_heading[p] < this->m_m); + T del = this->m_x[p] - this->m_upper_bound_values[p]; + del *= del; + return del / this->m_betas[this->m_basis_heading[p]]; + } + + // void print_x_and_low_bound(unsigned p) { + // cout << "x l[" << p << "] = " << this->m_x[p] << " " << this->m_low_bound_values[p] << endl; + // } + // void print_x_and_upper_bound(unsigned p) { + // cout << "x u[" << p << "] = " << this->m_x[p] << " " << this->m_upper_bound_values[p] << endl; + // } + + // returns the + T pricing_for_row(unsigned i) { + unsigned p = this->m_basis[i]; + switch (this->m_column_type[p]) { + case fixed: + case boxed: + if (this->x_below_low_bound(p)) { + T del = get_edge_steepness_for_low_bound(p); + // cout << "case boxed low_bound in pricing" << endl; + // print_x_and_low_bound(p); + return del; + } + if (this->x_above_upper_bound(p)) { + T del = get_edge_steepness_for_upper_bound(p); + // cout << "case boxed at upper_bound in pricing" << endl; + // print_x_and_upper_bound(p); + return del; + } + return numeric_traits::zero(); + case low_bound: + if (this->x_below_low_bound(p)) { + T del = get_edge_steepness_for_low_bound(p); + // cout << "case low_bound in pricing" << endl; + // print_x_and_low_bound(p); + return del; + } + return numeric_traits::zero(); + break; + case upper_bound: + if (this->x_above_upper_bound(p)) { + T del = get_edge_steepness_for_upper_bound(p); + // cout << "case upper_bound in pricing" << endl; + // print_x_and_upper_bound(p); + return del; + } + return numeric_traits::zero(); + break; + case free_column: + lean_assert(numeric_traits::is_zero(this->m_d[p])); + return numeric_traits::zero(); + default: + cout << "row = " << i << " p = " << p << endl; + cout << "unexpected column type = " << column_type_to_string(this->m_column_type[p]) << endl; + lean_assert(false); + throw "unexpected column type"; + break; + } + } + + void pricing_loop(unsigned number_of_rows_to_try, unsigned offset_in_rows) { + m_r = -1; + T steepest_edge_max = numeric_traits::zero(); + unsigned initial_offset_in_rows = offset_in_rows; + unsigned i = offset_in_rows; + unsigned rows_left = number_of_rows_to_try; + do { + loop_start: + T se = pricing_for_row(i); + if (se > steepest_edge_max) { + steepest_edge_max = se; + m_r = i; + } + if (++i == this->m_m) { + i = 0; + } + if (rows_left > 0) { + rows_left--; + } + } while (rows_left || (steepest_edge_max < T(1e-5) && i != initial_offset_in_rows)); + if (m_r == -1) { + if (this->m_status != UNSTABLE) { + this->m_status = OPTIMAL; + } + } else { + m_p = this->m_basis[m_r]; + m_delta = get_delta(); + if (advance_on_known_p()){ + return; + } + if (this->m_status == FLOATING_POINT_ERROR) { + return; + } + this->m_status = UNSTABLE; + if (i == initial_offset_in_rows) { + return; // made a full loop + } + m_p = m_r = -1; + steepest_edge_max = numeric_traits::zero(); + rows_left = number_of_rows_to_try; + goto loop_start; + // if (this->m_total_iterations % 80 == 0) { + // cout << "m_delta = " << m_delta << endl; + // } + } + } + + bool advance_on_known_p() { + if (done()) { + return true; + } + this->calculate_pivot_row_of_B_1(m_r); + this->calculate_pivot_row_when_pivot_row_of_B1_is_ready(); + if (!ratio_test()) { + return true; + } + calculate_beta_r_precisely(); + FTran(); + DSE_FTran(); + return basis_change_and_update(); + } + + int define_sign_of_alpha_r() { + switch (this->m_column_type[m_p]) { + case boxed: + case fixed: + if (this->x_below_low_bound(m_p)) { + return -1; + } + if (this->x_above_upper_bound(m_p)) { + return 1; + } + lean_assert(false); // wrong choice of leaving row + throw "wrong choice of leaving row"; + case low_bound: + if (this->x_below_low_bound(m_p)) { + return -1; + } + lean_assert(false); // wrong choice of leaving row + throw "wrong choice of leaving row"; + case upper_bound: + if (this->x_above_upper_bound(m_p)) { + return 1; + } + lean_assert(false); // wrong choice of leaving row + throw "wrong choice of leaving row"; + default: + cout << column_type_to_string(this->m_column_type[m_p]) << endl; + lean_assert(false); // wrong choice of leaving row + throw "wrong choice of leaving row"; + break; + } + } + + + // void try_update_theta_D_and_q_for_boxed(unsigned j) { + // if (this->m_settings.abs_val_is_smaller_than_zero_tolerance(this->m_pivot_row[j])) { + // return; + // } + + // T ratio = abs(this->m_d[j] / this->m_pivot_row[j]); + // if (ratio < m_theta_D) { + // m_theta_D = ratio; + // m_q = j; + // m_delta -= abs(bound_span(j) * this->m_pivot_row[j]); + // } + // } + + + // void try_update_theta_D_and_q(unsigned j) { + // if (this->m_settings.abs_val_is_smaller_than_zero_tolerance(this->m_pivot_row[j])) { + // return; + // cout << " investigate " << endl; + // throw "try_update_theta_D_and_q"; + // } + + // T ratio = this->m_d[j] / (m_sign_of_alpha_r * this->m_pivot_row[j]); + // if (ratio < m_theta_D) { + // m_theta_D = ratio; + // m_q = j; + // } + // } + + + bool can_be_breakpoint(unsigned j) { + if (this->pivot_row_element_is_too_small_for_ratio_test(j)) return false; + switch (this->m_column_type[j]) { + case low_bound: + lean_assert(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_low_bound_values[j])); + return m_sign_of_alpha_r * this->m_pivot_row[j] > 0; + case upper_bound: + lean_assert(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_upper_bound_values[j])); + return m_sign_of_alpha_r * this->m_pivot_row[j] < 0; + case boxed: + { + bool low_bound = this->x_is_at_low_bound(j); + bool grawing = m_sign_of_alpha_r * this->m_pivot_row[j] > 0; + return low_bound == grawing; + } + case fixed: // is always dual feasible so we ingore it + return false; + case free_column: + return true; + default: + return false; + } + } + + void fill_breakpoint_set() { + m_breakpoint_set.clear(); + for (unsigned j : non_basis()) { + if (can_be_breakpoint(j)) { + m_breakpoint_set.insert(j); + } + } + } + + void FTran() { + this->solve_Bd(m_q); + } + + // this calculation is needed for the steepest edge update, + // it hijackes m_pivot_row_of_B_1 for this purpose since we will need it anymore to the end of the cycle + void DSE_FTran() { // todo, see algorithm 7 from page 35 + this->m_factorization->solve_By(this->m_pivot_row_of_B_1); + } + + T get_delta() { + switch (this->m_column_type[m_p]) { + case boxed: + if (this->x_below_low_bound(m_p)) { + return this->m_x[m_p] - this->m_low_bound_values[m_p]; + } + if (this->x_above_upper_bound(m_p)) { + return this->m_x[m_p] - this->m_upper_bound_values[m_p];; + } + cout << "incorrect m_p = " << m_p << endl; + lean_assert(false); + throw "incorrect m_p"; + case low_bound: + if (this->x_below_low_bound(m_p)) { + return this->m_x[m_p] - this->m_low_bound_values[m_p]; + } + cout << "incorrect m_p = " << m_p << endl; + lean_assert(false); + throw "incorrect m_p"; + + case upper_bound: + if (this->x_above_upper_bound(m_p)) { + return get_edge_steepness_for_upper_bound(m_p); + } + cout << "incorrect m_p = " << m_p << endl; + lean_assert(false); + throw "incorrect m_p"; + case fixed: + return this->m_x[m_p] - this->m_upper_bound_values[m_p];; + default: + cout << "unsigned column type " << this->m_column_type[m_p] << endl; + throw "unhandled column type"; + break; + } + } + + void restore_d() { + cout << "restore_d" << endl; + this->m_d[m_p] = numeric_traits::zero(); + for (auto j : non_basis()) { + this->m_d[j] += m_theta_D * this->m_pivot_row[j]; + } + } + + bool d_is_correct() { + this->solve_yB(this->m_y); + for (auto j : non_basis()) { + T d = this->m_costs[j] - this->m_A.dot_product_with_column(this->m_y, j); + if (numeric_traits::get_double(abs(d - this->m_d[j])) >= 0.001) { + cout << "m_total_iterations = " << this->m_total_iterations << endl; + cout << "d[" << j << "] = " << this->m_d[j] << " but should be " << d << endl; + return false; + } + } + return true; + } + + void xb_minus_delta_p_pivot_column() { + unsigned i = this->m_m; + while (i--) { + this->m_x[this->m_basis[i]] -= m_theta_P * this->m_ed[i]; + } + } + + void update_betas() { // page 194 of Progress ... todo - once in a while betas have to be reinitialized + T one_over_arq = numeric_traits::one() / this->m_pivot_row[m_q]; + T beta_r = this->m_betas[m_r] = std::max(T(0.0001), (m_betas[m_r] * one_over_arq) * one_over_arq); + T k = -2 * one_over_arq; + unsigned i = this->m_m; + while (i--) { + if (i == m_r) continue; + T a = this->m_ed[i]; + m_betas[i] += a * (a * beta_r + k * this->m_pivot_row_of_B_1[i]); + if (m_betas[i] < T(0.0001)) + m_betas[i] = T(0.0001); + } + } + + void apply_flips() { + for (unsigned j : m_flipped_boxed) { + lean_assert(this->x_is_at_bound(j)); + if (this->x_is_at_low_bound(j)) { + this->m_x[j] = this->m_upper_bound_values[j]; + } else { + this->m_x[j] = this->m_low_bound_values[j]; + } + } + } + + void snap_xN_column_to_bounds(unsigned j) { + switch (this->m_column_type[j]) { + case fixed: + this->m_x[j] = this->m_low_bound_values[j]; + break; + case boxed: + if (this->x_is_at_low_bound(j)) { + this->m_x[j] = this->m_low_bound_values[j]; + } else { + this->m_x[j] = this->m_upper_bound_values[j]; + } + break; + case low_bound: + this->m_x[j] = this->m_low_bound_values[j]; + break; + case upper_bound: + this->m_x[j] = this->m_upper_bound_values[j]; + break; + case free_column: + break; + default: + cout << "column = " << j << endl; + cout << "unexpected column type = " << column_type_to_string(this->m_column_type[j]) << endl; + lean_assert(false); + throw "unexpected column type"; + break; + } + } + + void snap_xN_to_bounds() { + for (auto j : this->non_basis()) { + snap_xN_column_to_bounds(j); + } + } + + void init_beta_precisely(unsigned i) { + vector vec(this->m_m, numeric_traits::zero()); + vec[i] = numeric_traits::one(); + this->m_factorization->solve_yB(vec); + T beta = numeric_traits::zero(); + for (T & v : vec) { + beta += v * v; + } + this->m_betas[i] =beta; + } + + void init_betas_precisely() { + cout << "init beta precisely..." << endl; + unsigned i = this->m_m; + while (i--) { + init_beta_precisely(i); + } + cout << "done" << endl; + } + + // step 7 of the algorithm from Progress + bool basis_change_and_update() { + update_betas(); + update_d_and_xB(); + m_theta_P = m_delta / this->m_ed[m_r]; + xb_minus_delta_p_pivot_column(); + apply_flips(); + this->m_x[m_q] += m_theta_P; + if (!update_basis(m_q, m_p) || this->A_mult_x_is_off() || !problem_is_dual_feasible()) { + revert_to_previous_basis(); + this->m_iters_with_no_cost_growing++; + return false; + } + lean_assert(d_is_correct()); + return true; + } + + void revert_to_previous_basis() { + cout << "recovering basis p = " << m_p << " q = " << m_q << endl; + this->m_factorization->change_basis(m_p, m_q); + init_factorization(this->m_factorization, this->m_A, this->m_basis, this->m_basis_heading, this->m_settings, this->m_non_basic_columns); + if (this->m_factorization->get_status() != LU_status::OK) { + this->m_status = FLOATING_POINT_ERROR; + return; + } + this->m_x[m_q] -= m_theta_P; + snap_xN_to_bounds(); + recalculate_xB_and_d(); + if (this->A_mult_x_is_off()) { + this->m_status = FLOATING_POINT_ERROR; + return; + } + init_betas_precisely(); + } + + + bool problem_is_dual_feasible() { + for (unsigned j : non_basis()){ + if (!this->column_is_dual_feasible(j)) { + cout << "column " << j << " is not dual feasible" << endl; + cout << "m_d[" << j << "] = " << this->m_d[j] << endl; + cout << "x[" << j << "] = " << this->m_x[j] << endl; + cout << "type = " << column_type_to_string(this->m_column_type[j]) << endl; + cout << "bounds = " << this->m_low_bound_values[j] << "," << this->m_upper_bound_values[j] << endl; + cout << "m_total_iterations = " << this->m_total_iterations << endl; + // cout << "m_betas "; + // print_vector(m_betas); + // column_is_dual_feasible(j); // debug + return false; + } + } + return true; + } + + unsigned get_number_of_rows_to_try_for_leaving() { + unsigned s = this->m_m; + if (this->m_m > 300) { + s = (unsigned)(s / this->m_settings.percent_of_entering_to_check * 100); + } + return lrand48() % s + 1; + } + + void update_a_wave(const T & del, unsigned j) { + this->m_A.add_column_to_vector(del, j, & m_a_wave[0]); + } + + bool delta_keeps_the_sign(int initial_delta_sign, const T & delta) { + if (numeric_traits::precise()) + return ((delta > numeric_traits::zero()) && (initial_delta_sign == 1)) || + ((delta < numeric_traits::zero()) && (initial_delta_sign == -1)); + + double del = numeric_traits::get_double(delta); + return ( (del > this->m_settings.zero_tolerance) && (initial_delta_sign == 1)) || + ((del < - this->m_settings.zero_tolerance) && (initial_delta_sign == -1)); + } + + void set_status_to_tentative_dual_unbounded_or_dual_unbounded() { + cout << "cost = " << this->get_cost() << endl; + if (this->m_status == TENTATIVE_DUAL_UNBOUNDED) { + cout << "setting status to DUAL_UNBOUNDED" << endl; + this->m_status = DUAL_UNBOUNDED; + } else { + cout << "setting to TENTATIVE_DUAL_UNBOUNDED" << endl; + this->m_status = TENTATIVE_DUAL_UNBOUNDED; + } + } + + // it is positive if going from low bound to upper bound and negative if going from upper bound to low bound + T signed_span_of_boxed(unsigned j) { + return this->x_is_at_low_bound(j)? this->bound_span(j): - this->bound_span(j); + } + + void add_tight_breakpoints_and_q_to_flipped_set() { + m_flipped_boxed.insert(m_q); + for (auto j : m_tight_set) { + m_flipped_boxed.insert(j); + } + } + + T delta_lost_on_flips_of_tight_breakpoints() { + T ret = abs(this->bound_span(m_q) * this->m_pivot_row[m_q]); + for (auto j : m_tight_set) { + ret += abs(this->bound_span(j) * this->m_pivot_row[j]); + } + return ret; + } + + bool tight_breakpoinst_are_all_boxed() { + if (this->m_column_type[m_q] != boxed) return false; + for (auto j : m_tight_set) { + if (this->m_column_type[j] != boxed) return false; + } + return true; + } + + T calculate_harris_delta_on_breakpoint_set() { + bool first_time = true; + T ret = zero_of_type(); + lean_assert(m_breakpoint_set.size() > 0); + for (auto j : m_breakpoint_set) { + T t; + if (this->x_is_at_low_bound(j)) { + t = abs((std::max(this->m_d[j], numeric_traits::zero()) + m_harris_tolerance) / this->m_pivot_row[j]); + } else { + t = abs((std::min(this->m_d[j], numeric_traits::zero()) - m_harris_tolerance) / this->m_pivot_row[j]); + } + if (first_time) { + ret = t; + first_time = false; + } else if (t < ret) { + ret = t; + } + } + return ret; + } + + void fill_tight_set_on_harris_delta(const T & harris_delta ){ + m_tight_set.clear(); + for (auto j : m_breakpoint_set) { + if (this->x_is_at_low_bound(j)) { + if (abs(std::max(this->m_d[j], numeric_traits::zero()) / this->m_pivot_row[j]) <= harris_delta){ + m_tight_set.insert(j); + } + } else { + if (abs(std::min(this->m_d[j], numeric_traits::zero() ) / this->m_pivot_row[j]) <= harris_delta){ + m_tight_set.insert(j); + } + } + } + } + + void find_q_on_tight_set() { + m_q = -1; + T max_pivot; + for (auto j : m_tight_set) { + T r = abs(this->m_pivot_row[j]); + if (m_q != -1) { + if (r > max_pivot) { + max_pivot = r; + m_q = j; + } + } else { + max_pivot = r; + m_q = j; + } + } + m_tight_set.erase(m_q); + } + + void find_q_and_tight_set() { + T harris_del = calculate_harris_delta_on_breakpoint_set(); + fill_tight_set_on_harris_delta(harris_del); + find_q_on_tight_set(); + lean_assert(m_q != -1); + } + + void erase_tight_breakpoints_and_q_from_breakpoint_set() { + m_breakpoint_set.erase(m_q); + for (auto j : m_tight_set) { + m_breakpoint_set.erase(j); + } + } + + bool ratio_test() { + m_sign_of_alpha_r = define_sign_of_alpha_r(); + fill_breakpoint_set(); + m_flipped_boxed.clear(); + int initial_delta_sign = m_delta >= numeric_traits::zero()? 1: -1; + do { + if (m_breakpoint_set.size() == 0) { + set_status_to_tentative_dual_unbounded_or_dual_unbounded(); + return false; + } + this->m_status = FEASIBLE; + find_q_and_tight_set(); + if (!tight_breakpoinst_are_all_boxed()) break; + T del = m_delta - delta_lost_on_flips_of_tight_breakpoints() * initial_delta_sign; + if (!delta_keeps_the_sign(initial_delta_sign, del)) break; + if (m_tight_set.size() + 1 == m_breakpoint_set.size()) { + break; // deciding not to flip since we might get stuck without finding m_q, the column entering the basis + } + // we can flip m_q together with the tight set and look for another breakpoint candidate for m_q and another tight set + add_tight_breakpoints_and_q_to_flipped_set(); + m_delta = del; + erase_tight_breakpoints_and_q_from_breakpoint_set(); + } while (true); + m_theta_D = this->m_d[m_q] / this->m_pivot_row[m_q]; + return true; + } + + void process_flipped() { + init_a_wave_by_zeros(); + for (auto j : m_flipped_boxed) { + update_a_wave(signed_span_of_boxed(j), j); + } + } + void update_d_and_xB() { + for (auto j : non_basis()) { + this->m_d[j] -= m_theta_D * this->m_pivot_row[j]; + } + this->m_d[m_p] = - m_theta_D; + if (m_flipped_boxed.size() > 0) { + process_flipped(); + update_xb_after_bound_flips(); + } + } + + void calculate_beta_r_precisely() { + T t = numeric_traits::zero(); + unsigned i = this->m_m; + while (i--) { + T b = this->m_pivot_row_of_B_1[i]; + t += b * b; + } + m_betas[m_r] = t; + } + // see "Progress in the dual simplex method for large scale LP problems: practical dual phase 1 algorithms" + + void update_xb_after_bound_flips() { + this->m_factorization->solve_By(m_a_wave); + unsigned i = this->m_m; + while (i--) { + this->m_x[this->m_basis[i]] -= m_a_wave[i]; + } + } + + void one_iteration() { + unsigned number_of_rows_to_try = get_number_of_rows_to_try_for_leaving(); + unsigned offset_in_rows = lrand48() % this->m_m; + if (this->m_status == TENTATIVE_DUAL_UNBOUNDED) { + number_of_rows_to_try = this->m_m; + } else { + this->m_status = FEASIBLE; + } + pricing_loop(number_of_rows_to_try, offset_in_rows); + lean_assert(problem_is_dual_feasible()); + } + + void solve() { // see the page 35 + lean_assert(d_is_correct()); + lean_assert(problem_is_dual_feasible()); + this->m_start_time = get_millisecond_count(); + lean_assert(this->basis_heading_is_correct()); + this->m_total_iterations = 0; + this->m_iters_with_no_cost_growing = 0; + do { + if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(string(), this->m_total_iterations)){ + this->m_status = lp_status::TIME_EXHAUSTED; + return; + } + one_iteration(); + this->m_total_iterations++; + } while (this->m_status != FLOATING_POINT_ERROR && this->m_status != DUAL_UNBOUNDED && this->m_status != OPTIMAL && + this->m_iters_with_no_cost_growing <= this->m_settings.max_number_of_iterations_with_no_improvements + && this->m_total_iterations <= this->m_settings.max_total_number_of_iterations); + } + + bool low_bounds_are_set() const { return true; } +}; +} diff --git a/src/util/lp/lp_dual_simplex.h b/src/util/lp/lp_dual_simplex.h new file mode 100644 index 0000000000..871b2eb282 --- /dev/null +++ b/src/util/lp/lp_dual_simplex.h @@ -0,0 +1,411 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include "util/lp/lp_solver.h" +#include "util/lp/lp_dual_core_solver.h" +#include +namespace lean { + +template +class lp_dual_simplex: public lp_solver { + lp_dual_core_solver * m_core_solver = nullptr; + vector m_b_copy; + std::vector m_low_bounds; // We don't have a convention here that all low bounds are zeros. At least it does not hold for the first stage solver + std::vector m_column_types_of_core_solver; + std::vector m_column_types_of_logicals; + std::vector m_can_enter_basis; +public: + ~lp_dual_simplex() { + if (m_core_solver != nullptr) { + delete m_core_solver; + } + } + + void decide_on_status_after_stage1() { + switch (m_core_solver->get_status()) { + case OPTIMAL: + if (this->m_settings.abs_val_is_smaller_than_artificial_tolerance(m_core_solver->get_cost())) { + this->m_status = FEASIBLE; + cout << "status is FEASIBLE" << endl; + } else { + cout << "status is UNBOUNDED" << endl; + this->m_status = UNBOUNDED; + } + break; + case DUAL_UNBOUNDED: + cout << "the status cannot be DUAL_UNBOUNDED since the price is not positive!" << endl; + lean_assert(false); + throw "unexpected status DUAL_UNBOUNDED"; + break; + case ITERATIONS_EXHAUSTED: + cout << "status is ITERATIONS_EXHAUSTED" << endl; + this->m_status = ITERATIONS_EXHAUSTED; + break; + case TIME_EXHAUSTED: + cout << "status is TIME_EXHAUSTED" << endl; + this->m_status = TIME_EXHAUSTED; + break; + case FLOATING_POINT_ERROR: + cout << "status is FLOATING_POINT_ERROR" << endl; + this->m_status = FLOATING_POINT_ERROR; + break; + default: + cout << "the status is not expected: " << lp_status_to_string(m_core_solver->get_status()) << endl; + lean_assert(false); + throw "unexpected status"; + } + } + + void fix_logical_for_stage2(unsigned j) { + lean_assert(j >= this->number_of_core_structurals()); + switch (m_column_types_of_logicals[j - this->number_of_core_structurals()]) { + case low_bound: + m_low_bounds[j] = numeric_traits::zero(); + m_column_types_of_core_solver[j] = low_bound; + m_can_enter_basis[j] = true; + break; + case fixed: + this->m_upper_bounds[j] = m_low_bounds[j] = numeric_traits::zero(); + m_column_types_of_core_solver[j] = fixed; + m_can_enter_basis[j] = false; + break; + default: + throw 1; + lean_assert(false); + } + } + + void fix_structural_for_stage2(unsigned j) { + column_info * ci = this->m_columns[this->m_core_solver_columns_to_external_columns[j]]; + switch (ci->get_column_type()) { + case low_bound: + m_low_bounds[j] = numeric_traits::zero(); + m_column_types_of_core_solver[j] = low_bound; + m_can_enter_basis[j] = true; + break; + case fixed: + case upper_bound: + lean_assert(false); + throw "unexpected bound type"; + break; + case boxed: + this->m_upper_bounds[j] = ci->get_adjusted_upper_bound() / this->m_column_scale[j]; + m_low_bounds[j] = numeric_traits::zero(); + m_column_types_of_core_solver[j] = boxed; + m_can_enter_basis[j] = true; + break; + case free_column: + m_can_enter_basis[j] = true; + m_column_types_of_core_solver[j] = free_column; + break; + default: + lean_assert(false); + throw "unexpected bound type"; + } + T cost_was = this->m_costs[j]; + this->set_scaled_cost(j); + bool in_basis = m_core_solver->m_factorization->m_basis_heading[j] >= 0; + if (in_basis && cost_was != this->m_costs[j]) { + cout << "cost change in basis" << endl; + } + } + + void unmark_boxed_and_fixed_columns_and_fix_structural_costs() { + unsigned j = this->m_A->column_count(); + while (j-- > this->number_of_core_structurals()) { + fix_logical_for_stage2(j); + } + j = this->number_of_core_structurals(); + while (j--) { + fix_structural_for_stage2(j); + } + } + + void restore_right_sides() { + unsigned i = this->m_A->row_count(); + while (i--) { + this->m_b[i] = m_b_copy[i]; + } + } + + void solve_for_stage2() { + m_core_solver->restore_non_basis(); + m_core_solver->solve_yB(m_core_solver->m_y); + m_core_solver->fill_reduced_costs_from_m_y_by_rows(); + m_core_solver->start_with_initial_basis_and_make_it_dual_feasible(); + m_core_solver->set_status(FEASIBLE); + m_core_solver->solve(); + switch (m_core_solver->get_status()) { + case OPTIMAL: + this->m_status = OPTIMAL; + break; + case DUAL_UNBOUNDED: + this->m_status = INFEASIBLE; + break; + case TIME_EXHAUSTED: + this->m_status = TIME_EXHAUSTED; + break; + case FLOATING_POINT_ERROR: + this->m_status = FLOATING_POINT_ERROR; + break; + default: + cout << "status of core solver is " << lp_status_to_string(m_core_solver->get_status()) << endl; + lean_assert(false); + throw "unexpected status"; + } + this->m_second_stage_iterations = m_core_solver->m_total_iterations; + } + + void fill_x_with_zeros() { + unsigned j = this->m_A->column_count(); + while (j--) { + this->m_x[j] = numeric_traits::zero(); + } + } + + void stage1() { + lean_assert(m_core_solver == nullptr); + this->m_x.resize(this->m_A->column_count(), numeric_traits::zero()); + this->print_statistics_on_A(); + m_core_solver = new lp_dual_core_solver( + *this->m_A, + m_can_enter_basis, + this->m_b, // the right side vector + this->m_x, + this->m_basis, + this->m_costs, + this->m_column_types_of_core_solver, + this->m_low_bounds, + this->m_upper_bounds, + this->m_settings, + this->m_name_map); + m_core_solver->fill_reduced_costs_from_m_y_by_rows(); + m_core_solver->start_with_initial_basis_and_make_it_dual_feasible(); + if (this->m_settings.abs_val_is_smaller_than_artificial_tolerance(m_core_solver->get_cost())) { + cout << "skipping stage 1" << endl; + m_core_solver->set_status(OPTIMAL); + m_core_solver->m_total_iterations = 0; + } else { + cout << "stage 1" << endl; + m_core_solver->solve(); + } + decide_on_status_after_stage1(); + this->m_first_stage_iterations = m_core_solver->m_total_iterations; + } + + void stage2() { + cout << "starting stage2" << endl; + unmark_boxed_and_fixed_columns_and_fix_structural_costs(); + restore_right_sides(); + solve_for_stage2(); + } + + void fill_first_stage_solver_fields() { + unsigned slack_var = this->number_of_core_structurals(); + unsigned artificial = this->number_of_core_structurals() + this->m_slacks; + + for (unsigned row = 0; row < this->row_count(); row++) { + fill_first_stage_solver_fields_for_row_slack_and_artificial(row, slack_var, artificial); + } + fill_costs_and_bounds_and_column_types_for_the_first_stage_solver(); + } + + column_type get_column_type(unsigned j) { + lean_assert(j < this->m_A->column_count()); + if (j >= this->number_of_core_structurals()) { + return m_column_types_of_logicals[j - this->number_of_core_structurals()]; + } + return this->m_columns[this->m_core_solver_columns_to_external_columns[j]]->get_column_type(); + } + + void fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_structural_column(unsigned j) { + // see 4.7 in the dissertation of Achim Koberstein + lean_assert(this->m_core_solver_columns_to_external_columns.find(j) != + this->m_core_solver_columns_to_external_columns.end()); + + T free_bound = T(1e4); // see 4.8 + unsigned jj = this->m_core_solver_columns_to_external_columns[j]; + lean_assert(this->m_columns.find(jj) != this->m_columns.end()); + column_info * ci = this->m_columns[jj]; + switch (ci->get_column_type()) { + case upper_bound: + cout << j << endl; + cout << column_type_to_string(get_column_type(j)) << endl; + cout << "throwing upper_bound case " << endl; + throw "unexpected bound type"; // we flip columns so this case is impossible + break; + case low_bound: { + m_can_enter_basis[j] = true; + this->set_scaled_cost(j); + this->m_low_bounds[j] = numeric_traits::zero(); + this->m_upper_bounds[j] =numeric_traits::one(); + break; + } + case free_column: { + m_can_enter_basis[j] = true; + this->set_scaled_cost(j); + this->m_upper_bounds[j] = free_bound; + this->m_low_bounds[j] = -free_bound; + break; + } + case boxed: + m_can_enter_basis[j] = false; + this->m_costs[j] = numeric_traits::zero(); + this->m_upper_bounds[j] = this->m_low_bounds[j] = numeric_traits::zero(); // is it needed? + break; + default: + lean_assert(false); + throw "unexpected column type"; + break; + } + m_column_types_of_core_solver[j] = boxed; + } + + void fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_logical_column(unsigned j) { + this->m_costs[j] = 0; + lean_assert(get_column_type(j) != upper_bound); + if ((m_can_enter_basis[j] = (get_column_type(j) == low_bound))) { + m_column_types_of_core_solver[j] = boxed; + this->m_low_bounds[j] = numeric_traits::zero(); + this->m_upper_bounds[j] = numeric_traits::one(); + } else { + m_column_types_of_core_solver[j] = fixed; + this->m_low_bounds[j] = numeric_traits::zero(); + this->m_upper_bounds[j] = numeric_traits::zero(); + } + } + + void fill_costs_and_bounds_and_column_types_for_the_first_stage_solver() { + unsigned j = this->m_A->column_count(); + while (j-- > this->number_of_core_structurals()) { // go over logicals here + fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_logical_column(j); + } + j = this->number_of_core_structurals(); + while (j--) { + fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_structural_column(j); + } + } + + void set_type_for_logical(unsigned j, column_type col_type) { + this->m_column_types_of_logicals[j - this->number_of_core_structurals()] = col_type; + } + + void fill_first_stage_solver_fields_for_row_slack_and_artificial(unsigned row, + unsigned & slack_var, + unsigned & artificial) { + lean_assert(row < this->row_count()); + auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[row]]; + // we need to bring the program to the form Ax = b + T rs = this->m_b[row]; + switch (constraint.m_relation) { + case Equal: // no slack variable here + set_type_for_logical(artificial, fixed); + this->m_basis[row] = artificial; + this->m_costs[artificial] = numeric_traits::zero(); + (*this->m_A)(row, artificial) = numeric_traits::one(); + artificial++; + break; + + case Greater_or_equal: + set_type_for_logical(slack_var, low_bound); + (*this->m_A)(row, slack_var) = - numeric_traits::one(); + if (rs > 0) { + // adding one artificial + set_type_for_logical(artificial, fixed); + (*this->m_A)(row, artificial) = numeric_traits::one(); + this->m_basis[row] = artificial; + this->m_costs[artificial] = numeric_traits::zero(); + artificial++; + } else { + // we can put a slack_var into the basis, and avoid adding an artificial variable + this->m_basis[row] = slack_var; + this->m_costs[slack_var] = numeric_traits::zero(); + } + slack_var++; + break; + case Less_or_equal: + // introduce a non-negative slack variable + set_type_for_logical(slack_var, low_bound); + (*this->m_A)(row, slack_var) = numeric_traits::one(); + if (rs < 0) { + // adding one artificial + set_type_for_logical(artificial, fixed); + (*this->m_A)(row, artificial) = - numeric_traits::one(); + this->m_basis[row] = artificial; + this->m_costs[artificial] = numeric_traits::zero(); + artificial++; + } else { + // we can put slack_var into the basis, and avoid adding an artificial variable + this->m_basis[row] = slack_var; + this->m_costs[slack_var] = numeric_traits::zero(); + } + slack_var++; + break; + } + } + + void augment_matrix_A_and_fill_x_and_allocate_some_fields() { + this->count_slacks_and_artificials(); + this->m_A->add_columns_at_the_end(this->m_slacks + this->m_artificials); + unsigned n = this->m_A->column_count(); + this->m_column_types_of_core_solver.resize(n); + m_column_types_of_logicals.resize(this->m_slacks + this->m_artificials); + this->m_costs.resize(n); + this->m_upper_bounds.resize(n); + this->m_low_bounds.resize(n); + m_can_enter_basis.resize(n); + this->m_basis.resize(this->m_A->row_count()); + } + + + + void copy_m_b_aside_and_set_it_to_zeros() { + for (int i = 0; i < this->m_b.size(); i++) { + m_b_copy.push_back(this->m_b[i]); + this->m_b[i] = numeric_traits::zero(); // preparing for the first stage + } + } + + void find_maximal_solution(){ + if (this->problem_is_empty()) { + this->m_status = lp_status::EMPTY; + return; + } + + this->flip_costs(); // do it for now, todo ( remove the flipping) + + this->cleanup(); + if (this->m_status == INFEASIBLE) { + return; + } + this->fill_matrix_A_and_init_right_side(); + this->fill_m_b(); + this->scale(); + augment_matrix_A_and_fill_x_and_allocate_some_fields(); + fill_first_stage_solver_fields(); + this->fill_column_names_for_core_solver(); + copy_m_b_aside_and_set_it_to_zeros(); + stage1(); + if (this->m_status == FEASIBLE) { + stage2(); + } + } + + virtual T get_column_value(unsigned column) const { + return this->get_column_value_with_core_solver(column, m_core_solver); + } + + T get_current_cost() const { + T ret = numeric_traits::zero(); + for (auto it : this->m_columns) { + ret += this->get_column_cost_value(it.first, it.second); + } + return -ret; // we flip costs for now + } +}; +} diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h new file mode 100644 index 0000000000..6be72be658 --- /dev/null +++ b/src/util/lp/lp_primal_core_solver.h @@ -0,0 +1,1424 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once + +#include "util/numerics/double.h" +#include "util/lp/lu.h" +#include "util/lp/lp_solver.h" +#include + +#include +#include "util/lp/static_matrix.h" +#include "util/lp/core_solver_pretty_printer.h" +#include +#include +#include +#include +#include +#include "util/lp/lp_core_solver_base.h" +#include +#include "util/lp/breakpoint.h" +#include "util/lp/binary_heap_priority_queue.h" +namespace lean { + +// This core solver solves (Ax=b, low_bound_values \leq x \leq upper_bound_values, maximize costs*x ) +// The right side b is given implicitly by x and the basis +template +class lp_primal_core_solver:public lp_core_solver_base { +public: // todo : move public lower ; it is for debug only + // m_sign_of_entering is set to 1 if the entering variable needs + // to grow and is set to -1 otherwise + unsigned m_column_norm_update_counter; + T m_enter_price_eps; + X m_infeasibility = zero_of_type(); + int m_sign_of_entering_delta; + vector> m_breakpoints; + binary_heap_priority_queue m_breakpoint_indices_queue; + bool m_using_inf_costs = false; + bool m_recalc_reduced_costs = false; + std::set m_forbidden_enterings; + vector m_beta; // see Swietanowski working vector beta for column norms + T m_epsilon_of_reduced_cost = T(1e-7); + bool m_exit_on_feasible_solution = false; + vector m_costs_backup; + bool m_current_x_is_feasible; + + int choose_entering_column(unsigned number_of_benefitial_columns_to_go_over) { // at this moment m_y = cB * B(-1) + lean_assert(number_of_benefitial_columns_to_go_over); + unsigned offset_in_nb = lrand48() % this->m_non_basic_columns.size(); + unsigned initial_offset_in_non_basis = offset_in_nb; + T steepest_edge = zero_of_type(); + int entering = -1; + do { + unsigned j = this->m_factorization->m_non_basic_columns[offset_in_nb]; + push_forward_offset_in_non_basis(offset_in_nb); + if (m_forbidden_enterings.find(j) != m_forbidden_enterings.end()) { + continue; + } + T dj = this->m_d[j]; + switch (this->m_column_type[j]) { + case fixed: continue; + case free_column: + if (dj > m_epsilon_of_reduced_cost || dj < -m_epsilon_of_reduced_cost) break; + continue; + case low_bound: + if (dj > m_epsilon_of_reduced_cost) break; + continue; + case upper_bound: + if (dj < -m_epsilon_of_reduced_cost) break; + continue; + case boxed: + if (dj > m_epsilon_of_reduced_cost) { + if (this->m_x[j] < this->m_upper_bound_values[j] - this->bound_span(j)/2) + break; + continue; + } else if (dj < - m_epsilon_of_reduced_cost) { + if (this->m_x[j] > this->m_low_bound_values[j] + this->bound_span(j)/2) break; + } + continue; + default: + cout << "unexpected column type " << column_type_to_string(this->m_column_type[j]) << endl; + throw "unexpected column_type"; + break; + } + + // if we are here then j is a candidate to enter the basis + T t = dj * dj / this->m_column_norms[j]; + if (t > steepest_edge) { + steepest_edge = t; + entering = j; + if (number_of_benefitial_columns_to_go_over) + number_of_benefitial_columns_to_go_over--; + } + } while (number_of_benefitial_columns_to_go_over && initial_offset_in_non_basis != offset_in_nb); + if (entering != -1) + m_sign_of_entering_delta = this->m_d[entering] > 0? 1 : -1; + return entering; +} + + + + int find_leaving_and_t_precisely(unsigned entering, X & t){ + int leaving = -1; + T abs_of_d_of_leaving = numeric_traits::zero(); + for (unsigned i = 0; i < this->m_m; i++) { + if (is_zero(this->m_ed[i])) continue; + unsigned j = this->m_basis[i]; + get_bound_on_variable_and_update_leaving_precisely(j, leaving, - this->m_ed[i] * m_sign_of_entering_delta, t, abs_of_d_of_leaving); + if (leaving != -1 && is_zero(t)) { + return leaving; + } + } + + get_bound_on_variable_and_update_leaving_precisely(entering, leaving, T(m_sign_of_entering_delta), t, abs_of_d_of_leaving); + return leaving; + } + + static X positive_infinity() { + return convert_struct::convert(UINT_MAX); + } + + X get_harris_theta() { + X theta = positive_infinity(); + unsigned i = this->m_m; + while (i--) { + if (this->m_settings.abs_val_is_smaller_than_pivot_tolerance(this->m_ed[i])) continue; + limit_theta_on_basis_column(this->m_basis[i], - this->m_ed[i] * m_sign_of_entering_delta, theta); + if (is_zero(theta)) break; + } + return theta; + } + + void restore_harris_eps() { + m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); + } + + void zero_harris_eps() { m_converted_harris_eps = zero_of_type(); } + + bool get_current_x_is_feasible() const { + return m_current_x_is_feasible; + } + + bool get_current_x_is_infeasible() const { + return !m_current_x_is_feasible; + } + + int find_leaving_on_harris_theta(X const & harris_theta, X & t) { + int leaving = -1; + int leaving_fixed = -1; // we would like to get rid of fixed columns in the basis first because they might bring t to zero + T pivot_abs_max; + T pivot_abs_max_fixed; + // we know already that there is no bound flip on entering + // we also know that harris_theta is limited, so we will find a leaving + zero_harris_eps(); + unsigned i = lrand48() % this->m_m; + unsigned initial_i = i; + int column_with_non_zero_cost = -1; + do { + if (this->m_settings.abs_val_is_smaller_than_pivot_tolerance(this->m_ed[i])) { + if (++i == this->m_m) + i = 0; + continue; + } + X ratio = positive_infinity(); + unsigned j = this->m_basis[i]; + limit_theta_on_basis_column(j, - this->m_ed[i] * m_sign_of_entering_delta, ratio); + if (ratio <= harris_theta) { + if (get_current_x_is_infeasible() && !m_recalc_reduced_costs) { // when we have made several basic variables feasible then we need to recalculate the costs and the reduced costs: here we are catching this case + if (!is_zero(this->m_costs[j])) { + if (column_with_non_zero_cost != -1) + m_recalc_reduced_costs = true; + else + column_with_non_zero_cost = j; + } + } + if (leaving == -1 || abs(this->m_ed[i]) > pivot_abs_max) { + t = ratio; + leaving = j; + pivot_abs_max = abs(this->m_ed[i]); + if (this->m_column_type[j] == fixed) { + leaving_fixed = j; + pivot_abs_max_fixed = pivot_abs_max; + } + } else if (this->m_column_type[j] == fixed) { + if (leaving_fixed == -1 || abs(this->m_ed[i]) > pivot_abs_max_fixed) { + pivot_abs_max_fixed = abs(this->m_ed[i]); + leaving_fixed = j; + } + } + } + if (++i == this->m_m) i = 0; + } while ( i != initial_i); + restore_harris_eps(); + // if (m_j_uht.size() > 1) { + // cout << "under set " << endl; + // for(auto j : m_j_uht) + // print_column(j); + // // } + // cout << "done with under set" << endl; + return leaving; // debug + // return leaving_fixed != -1 ? leaving_fixed : leaving; + } + + + bool try_jump_to_another_bound_on_entering(unsigned entering, const X & theta, X & t) { + if (this->m_column_type[entering] != boxed) + return false; + + if (m_sign_of_entering_delta > 0) { + t = this->m_upper_bound_values[entering] - this->m_x[entering]; + if (t <= theta){ + lean_assert(t >= zero_of_type()); + return true; + } + } else { // m_sign_of_entering_delta == -1 + t = this->m_x[entering] - this->m_low_bound_values[entering]; + if (t <= theta) { + lean_assert(t >= zero_of_type()); + return true; + } + } + + return false; + } + + int find_leaving_and_t(unsigned entering, X & t){ + if (numeric_traits::precise()) return find_leaving_and_t_precisely(entering, t); + X theta = get_harris_theta(); + lean_assert(theta >= zero_of_type()); + if (try_jump_to_another_bound_on_entering(entering, theta, t)) return entering; + if (theta == positive_infinity()) return -1; // unlimited + return find_leaving_on_harris_theta(theta, t); + } + + void limit_theta_on_basis_column_for_inf_case_m_neg_upper_bound(unsigned j, const T & m, X & theta) { + lean_assert(m < 0 && this->m_column_type[j] == upper_bound); + limit_inf_on_upper_bound_m_neg(m, this->m_x[j], this->m_upper_bound_values[j], theta); + } + + void limit_theta_on_basis_column_for_feas_case_m_neg(unsigned j, const T & m, X & theta) { + lean_assert(m < 0); + lean_assert(this->m_column_type[j] == low_bound || this->m_column_type[j] == boxed); + const X & eps = harris_eps_for_bound(this->m_low_bound_values[j]); + if (this->above_bound(this->m_x[j], this->m_low_bound_values[j])) { + theta = std::min((this->m_low_bound_values[j] -this->m_x[j] - eps) / m, theta); + if (theta < zero_of_type()) theta = zero_of_type(); + } + } + + void limit_theta_on_basis_column_for_feas_case_m_neg_no_check(unsigned j, const T & m, X & theta) { + lean_assert(m < 0); + // lean_assert(this->m_column_type[j] == low_bound || this->m_column_type[j] == boxed); + const X& eps = harris_eps_for_bound(this->m_low_bound_values[j]); + theta = std::min((this->m_low_bound_values[j] - this->m_x[j] - eps) / m, theta); + if (theta < zero_of_type()) theta = zero_of_type(); + } + + void limit_theta_on_basis_column_for_inf_case_m_neg_low_bound(unsigned j, const T & m, X & theta) { + lean_assert(m < 0 && this->m_column_type[j] == low_bound); + limit_inf_on_bound_m_neg(m, this->m_x[j], this->m_low_bound_values[j], theta); + } + + void limit_theta_on_basis_column_for_inf_case_m_pos_low_bound(unsigned j, const T & m, X & theta) { + lean_assert(m > 0 && this->m_column_type[j] == low_bound); + limit_inf_on_low_bound_m_pos(m, this->m_x[j], this->m_low_bound_values[j], theta); + } + + void limit_theta_on_basis_column_for_inf_case_m_pos_upper_bound(unsigned j, const T & m, X & theta) { + lean_assert(m > 0 && this->m_column_type[j] == upper_bound); + limit_inf_on_bound_m_pos(m, this->m_x[j], this->m_upper_bound_values[j], theta); + } + + + bool limit_inf_on_bound_m_neg(const T & m, const X & x, const X & bound, X & theta) { + // x gets smaller + lean_assert(m < 0); + const X& eps = harris_eps_for_bound(bound); + if (this->below_bound(x, bound)) return false; + if (this->above_bound(x, bound)) { + theta = std::min((bound - x - eps) / m, theta); + } else { + theta = zero_of_type(); + } + return true; + } + + bool limit_inf_on_bound_m_pos(const T & m, const X & x, const X & bound, X & theta) { + // x gets larger + lean_assert(m > 0); + const X& eps = harris_eps_for_bound(bound); + if (this->above_bound(x, bound)) return false; + if (this->below_bound(x, bound)) { + theta = std::min((bound - x + eps) / m, theta); + } else { + theta = zero_of_type(); + } + return true; + } + + void limit_inf_on_low_bound_m_pos(const T & m, const X & x, const X & bound, X & theta) { + // x gets larger + lean_assert(m > 0); + const X& eps = harris_eps_for_bound(bound); + if (this->below_bound(x, bound)) + theta = std::min((bound - x + eps) / m, theta); + } + + void limit_inf_on_upper_bound_m_neg(const T & m, const X & x, const X & bound, X & theta) { + // x gets smaller + lean_assert(m < 0); + const X& eps = harris_eps_for_bound(bound); + if (this->above_bound(x, bound)) + theta = std::min((bound - x - eps) / m, theta); + } + + + + void limit_theta_on_basis_column_for_inf_case_m_neg_fixed(unsigned j, const T & m, X & theta) { + lean_assert(m < 0 && this->m_column_type[j] == fixed); + limit_inf_on_bound_m_neg(m, this->m_x[j], this->m_upper_bound_values[j], theta); + } + + void limit_theta_on_basis_column_for_inf_case_m_pos_fixed(unsigned j, const T & m, X & theta) { + lean_assert(m > 0 && this->m_column_type[j] == fixed); + limit_inf_on_bound_m_pos(m, this->m_x[j], this->m_upper_bound_values[j], theta); + } + + void limit_theta_on_basis_column_for_inf_case_m_pos_boxed(unsigned j, const T & m, X & theta) { + // lean_assert(m > 0 && this->m_column_type[j] == boxed); + const X & x = this->m_x[j]; + const X & lbound = this->m_low_bound_values[j]; + + if (this->below_bound(x, lbound)) { + const X& eps = harris_eps_for_bound(this->m_upper_bound_values[j]); + theta = std::min((lbound - x + eps) / m, theta); + } else { + const X & ubound = this->m_upper_bound_values[j]; + if (this->below_bound(x, ubound)){ + const X& eps = harris_eps_for_bound(ubound); + theta = std::min((ubound - x + eps) / m, theta); + } else if (!this->above_bound(x, ubound)) { + theta = zero_of_type(); + } + } + } + + void limit_theta_on_basis_column_for_inf_case_m_neg_boxed(unsigned j, const T & m, X & theta) { + // lean_assert(m < 0 && this->m_column_type[j] == boxed); + const X & x = this->m_x[j]; + const X & ubound = this->m_upper_bound_values[j]; + if (this->above_bound(x, ubound)) { + const X& eps = harris_eps_for_bound(ubound); + theta = std::min((ubound - x - eps) / m, theta); + } else { + const X & lbound = this->m_low_bound_values[j]; + if (this->above_bound(x, lbound)){ + const X& eps = harris_eps_for_bound(lbound); + theta = std::min((lbound - x - eps) / m, theta); + } else if (!this->below_bound(x, lbound)) { + theta = zero_of_type(); + } + } + } + void limit_theta_on_basis_column_for_feas_case_m_pos(unsigned j, const T & m, X & theta) { + lean_assert(m > 0); + const T& eps = harris_eps_for_bound(this->m_upper_bound_values[j]); + if (this->below_bound(this->m_x[j], this->m_upper_bound_values[j])) { + theta = std::min((this->m_upper_bound_values[j] - this->m_x[j] + eps) / m, theta); + if (theta < zero_of_type()) theta = zero_of_type(); + } + } + + void limit_theta_on_basis_column_for_feas_case_m_pos_no_check(unsigned j, const T & m, X & theta) { + lean_assert(m > 0); + const X& eps = harris_eps_for_bound(this->m_upper_bound_values[j]); + theta = std::min((this->m_upper_bound_values[j] - this->m_x[j] + eps) / m, theta); + if (theta < zero_of_type()) theta = zero_of_type(); + } + + T m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); + X harris_eps_for_bound(const X & bound) const { + return ( convert_struct::convert(1) + abs(bound)/10) * m_converted_harris_eps/3; + } + // j is a basic column or the entering, in any case x[j] has to stay feasible. + // m is the multiplier. updating t in a way that holds the following + // x[j] + t * m >= - harris_feasibility_tolerance ( if m < 0 ) + // or + // x[j] + t * m <= this->m_upper_bound_values[j] + harris_feasibility_tolerance ( if m > 0) + void limit_theta_on_basis_column(unsigned j, T m, X & theta) { + switch (this->m_column_type[j]) { + case free_column: break; + case upper_bound: + if (get_current_x_is_feasible()) { + if (m > 0) + limit_theta_on_basis_column_for_feas_case_m_pos_no_check(j, m, theta); + } else { // inside of feasibility_loop + if (m > 0) + limit_theta_on_basis_column_for_inf_case_m_pos_upper_bound(j, m, theta); + else + limit_theta_on_basis_column_for_inf_case_m_neg_upper_bound(j, m, theta); + } + break; + case low_bound: + if (get_current_x_is_feasible()) { + if (m < 0) + limit_theta_on_basis_column_for_feas_case_m_neg_no_check(j, m, theta); + } else { + if (m < 0) + limit_theta_on_basis_column_for_inf_case_m_neg_low_bound(j, m, theta); + else + limit_theta_on_basis_column_for_inf_case_m_pos_low_bound(j, m, theta); + } + break; + // case fixed: + // if (get_current_x_is_feasible()) { + // theta = zero_of_type(); + // break; + // } + // if (m < 0) + // limit_theta_on_basis_column_for_inf_case_m_neg_fixed(j, m, theta); + // else + // limit_theta_on_basis_column_for_inf_case_m_pos_fixed(j, m, theta); + // break; + case fixed: + case boxed: + if (get_current_x_is_feasible()) { + if (m > 0) { + limit_theta_on_basis_column_for_feas_case_m_pos_no_check(j, m, theta); + } else { + limit_theta_on_basis_column_for_feas_case_m_neg_no_check(j, m, theta); + } + } else { + if (m > 0) { + limit_theta_on_basis_column_for_inf_case_m_pos_boxed(j, m, theta); + } else { + limit_theta_on_basis_column_for_inf_case_m_neg_boxed(j, m, theta); + } + } + + break; + default: + cout << column_type_to_string(this->m_column_type[j]) << endl; + throw "unexpected type"; + } + if (theta < zero_of_type()) + theta = zero_of_type(); + } + + // m is the multiplier. updating t in a way that holds the following + // x[j] + t * m >= m_low_bound_values[j] ( if m < 0 ) + // or + // x[j] + t * m <= this->m_upper_bound_values[j] ( if m > 0) + void get_bound_on_variable_and_update_leaving_precisely(unsigned j, int & leaving, T m, X & t, T & abs_of_d_of_leaving) { + lean_assert(leaving == -1 || t > zero_of_type()); + if (m > 0) { + if (this->m_column_type[j] != boxed) { + return; + } + X tt = (this->m_upper_bound_values[j] - this->m_x[j]) / m; + if (leaving == -1 || tt < t || (tt == t && m > abs_of_d_of_leaving)) { + t = tt; + leaving = j; + abs_of_d_of_leaving = m; + if (t < zero_of_type()) + t = zero_of_type(); + } + } else if (m < 0){ + if (this->m_column_type[j] == free_column) { + return; + } + X tt = (- this->m_x[j]) / m; + if (leaving == -1 || tt < t || (tt == t && - m > abs_of_d_of_leaving)) { + t = tt; + leaving = j; + abs_of_d_of_leaving = - m; + if (t < zero_of_type()) + t = zero_of_type(); + } + } + } + + bool column_is_free(unsigned j) { + return this->m_column_type[j] == free; + } + + bool column_has_upper_bound(unsigned j) { + return ((unsigned)this->m_column_type[j]) < 2; + } + + bool column_has_low_bound(unsigned j) { + return this->m_column_type[j] != free_column; + } + + bool bound_holds(unsigned entering) { + if (numeric_traits::precise()) return true; + T v = this->m_x[entering]; + T eps = T(this->m_settings.harris_feasibility_tolerance); + + switch (this->m_column_type[entering]) { + case low_bound: + lean_assert(v >= -eps); + break; + case boxed: + lean_assert(v >= -eps); + lean_assert(v <= this->m_upper_bound_values[entering] + eps); + break; + default: + break; + } + return true; + } + + + vector m_low_bound_values_dummy; // needed for the base class only + + X get_max_bound(vector & b) { + X ret = zero_of_type(); + for (auto & v : b) { + X a = abs(v); + if (a > ret) ret = a; + } + return ret; + } + + // stage1 constructor + lp_primal_core_solver(static_matrix & A, + vector & b, // the right side vector + std::vector & x, // the number of elements in x needs to be at least as large as the number of columns in A + std::vector & basis, + std::vector & costs, + std::vector & column_type_array, + std::vector & low_bound_values, + std::vector & upper_bound_values, + lp_settings & settings, + unordered_map const & column_names): + lp_core_solver_base(A, b, + basis, + x, + costs, + settings, + column_names, + column_type_array, + low_bound_values, + upper_bound_values), + m_beta(A.row_count()) { + this->m_status = UNKNOWN; + this->m_column_norm_update_counter = settings.column_norms_update_frequency; + } + + // constructor + lp_primal_core_solver(static_matrix & A, + vector & b, // the right side vector + std::vector & x, // the number of elements in x needs to be at least as large as the number of columns in A + std::vector & basis, + std::vector & costs, + std::vector & column_type_array, + std::vector & upper_bound_values, + lp_settings & settings, + unordered_map const & column_names): + lp_core_solver_base(A, b, + basis, + x, + costs, + settings, + column_names, + column_type_array, + m_low_bound_values_dummy, + upper_bound_values), + m_beta(A.row_count()) { + m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); + lean_assert(initial_x_is_correct()); + m_low_bound_values_dummy.resize(A.column_count(), zero_of_type()); + m_enter_price_eps = numeric_traits::precise() ? numeric_traits::zero() : T(1e-5); + this->m_column_norm_update_counter = settings.column_norms_update_frequency; +#ifndef NDEBUG + // check_correctness(); +#endif + } + + void init_lu() { + init_factorization(this->m_factorization, this->m_A, this->m_basis, this->m_basis_heading, this->m_settings, this->m_non_basic_columns); + this->m_refactor_counter = 0; + } + + bool initial_x_is_correct() { + std::set basis_set; + for (int i = 0; i < this->m_A.row_count(); i++) { + basis_set.insert(this->m_basis[i]); + } + for (int j = 0; j < this->m_n; j++) { + if (column_has_low_bound(j) && this->m_x[j] < numeric_traits::zero()) { + cout << "low bound for variable " << j << " does not hold: this->m_x[" << j << "] = " << this->m_x[j] << " is negative " << endl; + return false; + } + + if (column_has_upper_bound(j) && this->m_x[j] > this->m_upper_bound_values[j]) { + cout << "upper bound for " << j << " does not hold: " << this->m_upper_bound_values[j] << ">" << this->m_x[j] << endl; + return false; + } + + if (basis_set.find(j) != basis_set.end()) continue; + if (this->m_column_type[j] == low_bound) { + if (numeric_traits::zero() != this->m_x[j]) { + cout << "only low bound is set for " << j << " but low bound value " << numeric_traits::zero() << " is not equal to " << this->m_x[j] << endl; + return false; + } + } + if (this->m_column_type[j] == boxed) { + if (this->m_upper_bound_values[j] != this->m_x[j] && !numeric_traits::is_zero(this->m_x[j])) { + return false; + } + } + } + return true; + } + +#ifndef NDEBUG + void check_Ax_equal_b() { + dense_matrix d(this->m_A); + T * ls = d.apply_from_left_with_different_dims(this->m_x); + lean_assert(vectors_are_equal(ls, this->m_b, this->m_m)); + delete [] ls; + } + void check_the_bounds() { + for (unsigned i = 0; i < this->m_n; i++) { + check_bound(i); + } + } + + void check_bound(unsigned i) { + lean_assert (!(column_has_low_bound(i) && (numeric_traits::zero() > this->m_x[i]))); + lean_assert (!(column_has_upper_bound(i) && (this->m_upper_bound_values[i] < this->m_x[i]))); + } + + void check_correctness() { + check_the_bounds(); + check_Ax_equal_b(); + } +#endif + + // from page 183 of Istvan Maros's book + // the basis structures have not changed yet + void update_reduced_costs_from_pivot_row(unsigned entering, int leaving) { + // the basis heading has changed already +#ifndef NDEBUG + auto & basis_heading = this->m_factorization->m_basis_heading; + lean_assert(basis_heading[entering] >= 0 && basis_heading[entering] < this->m_ed.size()); + lean_assert(basis_heading[leaving] < 0); +#endif + T pivot = this->m_pivot_row[entering]; + T dq = this->m_d[entering]/pivot; + for (auto j : this->m_pivot_row_index) { + // for (auto j : this->m_non_basic_columns) + if (this->m_basis_heading[j] >= 0) continue; + if (j != leaving) + this->m_d[j] -= dq * this->m_pivot_row[j]; + } + this->m_d[leaving] = -dq; + if (get_current_x_is_infeasible()) { + this->m_d[leaving] -= this->m_costs[leaving]; + this->m_costs[leaving] = zero_of_type(); + } + this->m_d[entering] = numeric_traits::zero(); + } + + // return 0 if the reduced cost at entering is close enough to the refreshed + // 1 if it is way off, and 2 if it is unprofitable + int refresh_reduced_cost_at_entering_and_check_that_it_is_off(unsigned entering) { + T reduced_at_entering_was = this->m_d[entering]; // can benefit from going over non-zeros of m_ed + lean_assert(abs(reduced_at_entering_was) > m_epsilon_of_reduced_cost); + T refreshed_cost = this->m_costs[entering]; + unsigned i = this->m_m; + while (i--) refreshed_cost -= this->m_costs[this->m_basis[i]] * this->m_ed[i]; + this->m_d[entering] = refreshed_cost; + T delta = abs(reduced_at_entering_was - refreshed_cost); + if (delta * 2 > abs(reduced_at_entering_was)) { + this->m_status = UNSTABLE; + if (reduced_at_entering_was > m_epsilon_of_reduced_cost) { + if (refreshed_cost <= zero_of_type()) + return 2; // abort entering + } else { + if (refreshed_cost > -m_epsilon_of_reduced_cost) + return 2; // abort entiring + } + return 1; // go on with this entering + } else { + if (reduced_at_entering_was > m_epsilon_of_reduced_cost) { + if (refreshed_cost <= zero_of_type()) + return 2; // abort entering + } else { + if (refreshed_cost > -m_epsilon_of_reduced_cost) + return 2; // abort entiring + } + } + return 0; + } + + void normalize_costs_and_backup_costs() { + T cost_max = std::max(max_abs_in_vector(this->m_costs), T(1)); + lean_assert(m_costs_backup.size() == 0); + for (unsigned j = 0; j < this->m_costs.size(); j++) + m_costs_backup.push_back(this->m_costs[j] /= cost_max); + m_using_inf_costs = false; + } + + void init_run() { + this->m_start_time = get_millisecond_count(); + this->m_total_iterations = 0; + this->m_iters_with_no_cost_growing = 0; + normalize_costs_and_backup_costs(); + set_current_x_is_feasible(); + init_reduced_costs(); + } + + int pivots_in_column_and_row_are_different(int entering, int leaving) const { + const T & column_p = this->m_ed[this->m_basis_heading[leaving]]; + const T & row_p = this->m_pivot_row[entering]; + if (is_zero(column_p) || is_zero(row_p)) return true; // pivots cannot be zero + // the pivots have to have the same sign + if (column_p < 0) { + if (row_p > 0) + return 2; + } else { // column_p > 0 + if (row_p < 0) + return 2; + } + T diff_normalized = abs((column_p - row_p) / (numeric_traits::one() + abs(row_p))); + if ( !this->m_settings.abs_val_is_smaller_than_harris_tolerance(diff_normalized / T(10))) + return 1; + return 0; + } + + void calc_working_vector_beta_for_column_norms(){ + unsigned i = this->m_m; + while (i--) + m_beta[i] = this->m_ed[i]; + this->m_factorization->solve_yB(m_beta); + } + + void advance_on_entering_and_leaving(int entering, int leaving, X & t) { + lean_assert(t >= zero_of_type()); + lean_assert(leaving >= 0 && entering >= 0); + lean_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes + if (entering == leaving) { + lean_assert(!this->A_mult_x_is_off() ); + this->update_x(entering, t * m_sign_of_entering_delta); + if (this->A_mult_x_is_off() && !this->find_x_by_solving()) { + init_lu(); + if (!this->find_x_by_solving()) { + this->restore_x(entering, t * m_sign_of_entering_delta); + m_forbidden_enterings.insert(entering); + this->m_iters_with_no_cost_growing++; + cout << "failing in advance_on_entering_and_leaving for entering == leaving = " << leaving << endl; + return; + } + } + set_current_x_is_feasible(); + if (need_to_switch_costs()) + init_reduced_costs(); + this->m_iters_with_no_cost_growing = 0; + return; + } + unsigned pivot_row = this->m_factorization->basis_heading(leaving); + this->calculate_pivot_row_of_B_1(pivot_row); + this->calculate_pivot_row_when_pivot_row_of_B1_is_ready(); + int pivot_compare_result = pivots_in_column_and_row_are_different(entering, leaving); + if (!pivot_compare_result){;} + else if (pivot_compare_result == 2) { // the sign is changed, cannot continue + m_forbidden_enterings.insert(entering); + this->m_status = UNSTABLE; + this->m_iters_with_no_cost_growing++; + return; + } else { + lean_assert(pivot_compare_result == 1); + init_lu(); + } + calc_working_vector_beta_for_column_norms(); + if (!this->update_basis_and_x(entering, leaving, t * m_sign_of_entering_delta)) { + if (this->m_status == FLOATING_POINT_ERROR) + return; + set_current_x_is_feasible(); + init_reduced_costs(); + m_forbidden_enterings.insert(entering); + return; + } + if (!is_zero(t)) { + this->m_iters_with_no_cost_growing = 0; + set_current_x_is_feasible(); + } + update_or_init_column_norms(entering, leaving); + if (need_to_switch_costs() || m_recalc_reduced_costs) + init_reduced_costs(); + else + update_reduced_costs_from_pivot_row(entering, leaving); + lean_assert(!need_to_switch_costs()); + m_forbidden_enterings.clear(); + } + + bool need_to_switch_costs() { + lean_assert(calc_current_x_is_feasible() == m_current_x_is_feasible); + return get_current_x_is_feasible() == m_using_inf_costs; + } + // void recalc_reduced_costs() { + // if (current_x_is_feasible()) + // init_infeasibility_costs(); + // this->init_reduced_costs_for_one_iteration(); + // } + + void advance_on_entering(int entering) { + lean_assert(entering > -1); + this->solve_Bd(entering); + int refresh_result = refresh_reduced_cost_at_entering_and_check_that_it_is_off(entering); + if (refresh_result) { + init_lu(); + init_reduced_costs(); + if (refresh_result == 2) { + this->m_iters_with_no_cost_growing++; + return; + } + } + X t; + int leaving = find_leaving_and_t(entering, t); + if (leaving == -1){ + if (get_current_x_is_infeasible()) { + if (this->m_status == UNSTABLE) { + cout << "setting status to FLOATING_POINT_ERROR" << endl; + this->m_status = FLOATING_POINT_ERROR; + return; + } + init_reduced_costs(); + this->m_status = UNSTABLE; + return; + } + if (this->m_status == TENTATIVE_UNBOUNDED) { + this->m_status = UNBOUNDED; + } else { + this->m_status = TENTATIVE_UNBOUNDED; + } + return; + } + advance_on_entering_and_leaving(entering, leaving, t); + } + + void push_forward_offset_in_non_basis(unsigned & offset_in_nb) { + if (++offset_in_nb == this->m_non_basic_columns.size()) + offset_in_nb = 0; + } + + unsigned get_number_of_non_basic_column_to_try_for_enter() { + unsigned ret = this->m_factorization->m_non_basic_columns.size(); + if (this->m_status == TENTATIVE_UNBOUNDED) + return ret; // we really need to find entering with a large reduced cost + if (ret > 300) { + ret = (unsigned)(ret * this->m_settings.percent_of_entering_to_check / 100); + } + return std::max(static_cast(lrand48() % ret), 1u); + } + + void print_column_norms() { + cout << " column norms " << endl; + for (unsigned j = 0; j < this->m_n; j++) { + cout << this->m_column_norms[j] << " "; + } + cout << endl; + cout << endl; + } + + void set_current_x_is_feasible() { + m_current_x_is_feasible = calc_current_x_is_feasible(); + } + // returns the number of iterations + unsigned solve() { + init_run(); + lean_assert(!this->A_mult_x_is_off()); + do { + if (this->m_total_iterations % this->m_settings.report_frequency == 0) { + std::ostringstream string_stream; + string_stream << (m_using_inf_costs? "stage 1" : "stage 2"); + std::string stream_string = string_stream.str(); + if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(stream_string, this->m_total_iterations)) { + this->m_status = lp_status::TIME_EXHAUSTED; + return this->m_total_iterations; + } + } + lean_assert(m_current_x_is_feasible == calc_current_x_is_feasible()); + one_iteration(); + switch (this->m_status) { + case OPTIMAL: // double check that we are at optimum + case INFEASIBLE: + m_forbidden_enterings.clear(); + init_lu(); + lean_assert(this->m_factorization->get_status() == LU_status::OK); + set_current_x_is_feasible(); + init_reduced_costs(); + if (choose_entering_column(1) == -1) { + decide_on_status_when_cannot_find_entering(); + break; + } + this->m_status = UNKNOWN; + break; + case TENTATIVE_UNBOUNDED: + m_forbidden_enterings.clear(); + init_lu(); + lean_assert(this->m_factorization->get_status() == LU_status::OK); + init_reduced_costs(); + break; + case UNBOUNDED: + break; + + case UNSTABLE: + // m_forbidden_enterings.clear(); + init_lu(); + init_reduced_costs(); + this->m_status = UNKNOWN; + break; + + default: + break; // do nothing + } + } while (this->m_status != FLOATING_POINT_ERROR && this->m_status != UNBOUNDED + && + this->m_status != OPTIMAL + && + this->m_status != INFEASIBLE + && + this->m_iters_with_no_cost_growing <= this->m_settings.max_number_of_iterations_with_no_improvements + && + this->m_total_iterations <= this->m_settings.max_total_number_of_iterations + && + !(m_current_x_is_feasible && m_exit_on_feasible_solution)); + return this->m_total_iterations; + } + + lu * factorization() { + return this->m_factorization; + } + + + void forget_last_columns(unsigned how_many_to_forget) { + lean_assert(this->m_n > how_many_to_forget); +#ifndef NDEBUG + for (unsigned i = 0; i < this->m_A.row_count(); i++) { + lean_assert(this->m_basis[i] < this->m_n - how_many_to_forget); + } +#endif + this->m_A.forget_last_columns(how_many_to_forget); + this->m_n -= how_many_to_forget; + this->m_non_basic_columns.clear(); + this->init_basis_heading(); + } + + void reduce_basis_by_one(unsigned col) { + // at this moment this->m_basis has one column too many + for (unsigned i = this->m_basis_heading[col]; i < this->m_m; i++) { + unsigned t = this->m_basis[i] = this->m_basis[i + 1]; + this->m_basis_heading[t] = i; + } + this->m_basis_heading[col] = -1; + } + + // k is the redundant row index + void cross_out_redundant_row_and_remove_basis_column(unsigned k, unsigned col) { + this->m_A.cross_out_row(k); + this->m_m--; + reduce_basis_by_one(col); + } + + void delete_factorization() { + if (this->m_factorization != nullptr) { + delete this->m_factorization; + this->m_factorization = nullptr; + } + } + + // according to Swietanowski, " A new steepest edge approximation for the simplex method for linear programming" + void init_column_norms() { + m_column_norm_update_counter = 0; + for (unsigned j : this->m_non_basic_columns) + this->m_column_norms[j] = 1; + } + + // debug only + T calculate_column_norm_exactly(unsigned j) { + indexed_vector w(this->m_m); + this->m_A.copy_column_to_vector(j, w); + vector d(this->m_m); + this->m_factorization->solve_Bd_when_w_is_ready(d, w); + T ret = zero_of_type(); + for (auto v : d) + ret += v*v; + return ret+1; + } + + void update_or_init_column_norms(unsigned entering, unsigned leaving) { + if (++m_column_norm_update_counter == this->m_settings.column_norms_update_frequency) { + init_column_norms(); + } else { + update_column_norms(entering, leaving); + } + } + + // following Swietanowski - A new steepest ... + void update_column_norms(unsigned entering, unsigned leaving) { + T pivot = this->m_pivot_row[entering]; + T g_ent = std::max(calculate_norm_of_entering_exactly() / pivot /pivot, T(0.000001)); + this->m_column_norms[leaving] = g_ent; + + for (unsigned j : this->m_pivot_row_index) { + if (j == leaving) + continue; + const T & t = this->m_pivot_row[j]; + T s = this->m_A.dot_product_with_column(m_beta, j); + T k = -2 / pivot; + T tp = t/pivot; + if (this->m_column_type[j] == fixed) { + this->m_column_norms[j] = T(1); // We would like to kick out fixed vars from the basis, so making the norm small increases this chance since the steepest edge expression will be large + } else { + this->m_column_norms[j] = std::max(this->m_column_norms[j] + t * (t * g_ent + k * s), // see Achim Koberstein dissertation (8.1) + 1 + tp * tp); + } + } + } + + T calculate_norm_of_entering_exactly() { + T r = numeric_traits::one(); + unsigned i = this->m_m; + while (i--) { + T t = this->m_ed[i]; + r += t * t; + } + return r; + } + + // calling it stage1 is too cryptic + void find_feasible_solution() { + m_exit_on_feasible_solution = true; + this->snap_xN_to_bounds_and_free_columns_to_zeroes(); + solve(); + } + + bool is_tiny() const { + return this->m_m < 10 && this->m_n < 20; + } + + void calculate_infeasibility() { + m_infeasibility = zero_of_type(); + unsigned i = this->m_m; + while (i--) { + add_column_infeasibility(this->m_basis[i]); + } + } + + void add_column_infeasibility(unsigned j){ + const X & x = this->m_x[j]; + switch (this->m_column_type[j]) { + case fixed: + case boxed: + if (this->above_bound(x, this->m_upper_bound_values[j])) { + m_infeasibility -= x - this->m_upper_bound_values[j]; + } else if (this->below_bound(x, this->m_low_bound_values[j])) { + m_infeasibility -= this->m_low_bound_values[j] - x; + } + break; + case low_bound: + if (this->below_bound(x, this->m_low_bound_values[j])) { + m_infeasibility -= this->m_low_bound_values[j] - x; + } + break; + case upper_bound: + if (this->above_bound(x, this->m_upper_bound_values[j])) { + m_infeasibility -= x - this->m_upper_bound_values[j]; + } + break; + case free_column: + break; + } + } + + void one_iteration() { + this->m_total_iterations++; + unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter(); + int entering = choose_entering_column(number_of_benefitial_columns_to_go_over); + if (entering == -1) + decide_on_status_when_cannot_find_entering(); + else + advance_on_entering(entering); + } + + void fill_breakpoints_array(unsigned entering) { + clear_breakpoints(); + for (unsigned i = this->m_m; i--;) + try_add_breakpoint_in_row(i); + + if (this->m_column_type[entering] == boxed) { + if (m_sign_of_entering_delta < 0) + add_breakpoint(entering, - this->bound_span(entering), low_break); + else + add_breakpoint(entering, this->bound_span(entering), upper_break); + } + } + + void try_add_breakpoint_in_row(unsigned i) { + lean_assert(i < this->m_m); + const T & d = this->m_ed[i]; // the coefficient before m_entering in the i-th row + if (d == 0) return; // the change of x[m_entering] will not change the corresponding basis x + unsigned j = this->m_basis[i]; + const X & x = this->m_x[j]; + switch (this->m_column_type[j]) { + case fixed: + try_add_breakpoint(j, x, d, fixed_break, this->m_low_bound_values[j]); + break; + case boxed: + try_add_breakpoint(j, x, d, low_break, this->m_low_bound_values[j]); + try_add_breakpoint(j, x, d, upper_break, this->m_upper_bound_values[j]); + break; + case low_bound: + try_add_breakpoint(j, x, d, low_break, this->m_low_bound_values[j]); + break; + case upper_bound: + try_add_breakpoint(j, x, d, upper_break, this->m_upper_bound_values[j]); + break; + case free_column: + break; + default: + lean_assert(false); + break; + } + } + + void clear_breakpoints() { + m_breakpoints.clear(); + m_breakpoint_indices_queue.clear();// m_breakpoints.clear(); + } + + void change_slope_on_breakpoint(unsigned entering, breakpoint * b, T & slope_at_entering) { + if (b->m_j == entering) { + lean_assert(b->m_type != fixed_break && (!is_zero(b->m_delta))); + slope_at_entering += m_sign_of_entering_delta; + return; + } + + lean_assert(this->m_basis_heading[b->m_j] >= 0); + unsigned i_row = this->m_basis_heading[b->m_j]; + const T & d = - this->m_ed[i_row]; + if (numeric_traits::is_zero(d)) return; + + T delta = m_sign_of_entering_delta * abs(d); + switch (b->m_type) { + case fixed_break: + if (is_zero(b->m_delta)) { + slope_at_entering += delta; + } else { + slope_at_entering += 2 * delta; + } + break; + case low_break: + case upper_break: + slope_at_entering += delta; + break; + default: + throw 1; + lean_assert(false); // such a type does not exist + } + } + + + void advance_on_sorted_breakpoints(unsigned entering) { + T slope_at_entering = this->m_d[entering]; + breakpoint * last_bp = nullptr; + while (m_breakpoint_indices_queue.is_empty() == false) { + unsigned bi = m_breakpoint_indices_queue.dequeue(); + breakpoint *b = &m_breakpoints[bi]; + change_slope_on_breakpoint(entering, b, slope_at_entering); + last_bp = b; + if (slope_at_entering * m_sign_of_entering_delta > 0) { // the slope started to increase infeasibility + break; + } else { + if (numeric_traits::is_zero(slope_at_entering) && lrand48() % 2 == 0) { + // it is not cost benefitial to advance the delta more, so just break to increas the randomness + break; + } + } + } + update_basis_and_x_with_comparison(entering, last_bp->m_j, last_bp->m_delta); + } + + void update_basis_and_x_with_comparison(unsigned entering, unsigned leaving, X delta) { + if (entering != leaving) + this->update_basis_and_x(entering, leaving, delta); + else + this->update_x(entering, delta); + } + bool column_is_feasible(unsigned j){ + const X& x = this->m_x[j]; + switch (this->m_column_type[j]) { + case fixed: + case boxed: + if (this->above_bound(x, this->m_upper_bound_values[j])) { + return false; + } else if (this->below_bound(x, this->m_low_bound_values[j])) { + return false; + } else { + return true; + } + break; + case low_bound: + if (this->below_bound(x, this->m_low_bound_values[j])) { + return false; + } else { + return true; + } + break; + case upper_bound: + if (this->above_bound(x, this->m_upper_bound_values[j])) { + return false; + } else { + return true; + } + break; + case free_column: + return true; + break; + default: + lean_assert(false); + throw "cannot be here"; + break; + } + } + + bool calc_current_x_is_feasible() { + unsigned i = this->m_m; + while (i--) { + if (!column_is_feasible(this->m_basis[i])) + return false; + } + return true; + } + + void decide_on_status_when_cannot_find_entering() { + lean_assert(!need_to_switch_costs()); + this->m_status = get_current_x_is_feasible()? OPTIMAL: INFEASIBLE; + } + + bool can_enter_basis(unsigned j) { + switch (this->m_column_type[j]) { + case low_bound: + lean_assert(this->x_is_at_low_bound(j)); + return this->m_d[j] > numeric_traits::zero(); + case upper_bound: + lean_assert(this->x_is_at_upper_bound(j)); + return this->m_d[j] < numeric_traits::zero(); + case fixed: + return false; + case boxed: + { + bool at_low_bound = this->x_is_at_low_bound(j); + lean_assert(at_low_bound || this->x_is_at_upper_bound(j)); + return at_low_bound ? this->m_d[j] > numeric_traits::zero() : this->m_d[j] < numeric_traits::zero(); + } + case free_column: + return !numeric_traits::is_zero(this->m_d[j]); + default: + return false; + } + return false; + } + + + + bool done() { + if (this->m_status == OPTIMAL ||this->m_status == FLOATING_POINT_ERROR) return true; + if (this->m_status == INFEASIBLE) { + return true; + } + if (this->m_iters_with_no_cost_growing >= this->m_settings.max_number_of_iterations_with_no_improvements) { + cout << "m_iters_with_no_cost_growing = " << this->m_iters_with_no_cost_growing << endl; + this->m_status = ITERATIONS_EXHAUSTED; return true; + } + if (this->m_total_iterations >= this->m_settings.max_total_number_of_iterations) { + cout << "max_total_number_of_iterations " << this->m_total_iterations << " is reached " << endl; + this->m_status = ITERATIONS_EXHAUSTED; return true; + } + return false; + } + + void init_infeasibility_costs() { + lean_assert(this->m_x.size() >= this->m_n); + lean_assert(this->m_column_type.size() >= this->m_n); + // X inf = m_infeasibility; + m_infeasibility = zero_of_type(); + for (unsigned j = this->m_n; j--;) + init_infeasibility_cost_for_column(j); + // lean_assert(this->m_total_iterations == 0 || (inf <= m_infeasibility + convert_struct::convert(this->m_settings.tolerance_for_artificials))); + // if (inf == m_infeasibility) + // this->m_iters_with_no_cost_growing++; + m_using_inf_costs = true; + } + + void print_column(unsigned j) { + cout << this->column_name(j) << " " << j << " " << column_type_to_string(this->m_column_type[j]) << " x = " << this->m_x[j] << " " << "c = " << this->m_costs[j];; + switch (this->m_column_type[j]) { + case fixed: + case boxed: + cout << "( " << this->m_low_bound_values[j] << " " << this->m_x[j] << " " << this->m_upper_bound_values[j] << ")" << endl; + break; + case upper_bound: + cout << "( _" << this->m_x[j] << " " << this->m_upper_bound_values[j] << ")" << endl; + break; + case low_bound: + cout << "( " << this->m_low_bound_values[j] << " " << this->m_x[j] << " " << "_ )" << endl; + break; + case free_column: + cout << "( _" << this->m_x[j] << "_)" << endl; + default: + throw "unexpected type"; + } + } + + void init_infeasibility_cost_for_column(unsigned j) { + // we are going to maximize the cost + // When j is feasible, even at the boundary, then we set the cost of the column to zero. + const X & x = this->m_x[j]; + // set zero cost for each non-basis column + if (this->m_basis_heading[j] < 0) { + this->m_costs[j] = zero_of_type(); + return; + } + + // j is a basis column + switch (this->m_column_type[j]) { + case fixed: + case boxed: + if (this->above_bound(x, this->m_upper_bound_values[j])) { + this->m_costs[j] = -1; + m_infeasibility -= x - this->m_upper_bound_values[j]; + } else if (this->below_bound(x, this->m_low_bound_values[j])) { + m_infeasibility -= this->m_low_bound_values[j] - x; + this->m_costs[j] = 1; + } else { + this->m_costs[j] = zero_of_type(); + } + break; + case low_bound: + if (this->below_bound(x, this->m_low_bound_values[j])) { + this->m_costs[j] = 1; + m_infeasibility -= this->m_low_bound_values[j] - x; + } else { + this->m_costs[j] = zero_of_type(); + } + break; + case upper_bound: + if (this->above_bound(x, this->m_upper_bound_values[j])) { + this->m_costs[j] = -1; + m_infeasibility -= x - this->m_upper_bound_values[j]; + } else { + this->m_costs[j] = zero_of_type(); + } + break; + case free_column: + this->m_costs[j] = zero_of_type(); + break; + default: + lean_assert(false); + break; + } + } + + void add_breakpoint(unsigned j, X delta, breakpoint_type type) { + m_breakpoints.push_back(breakpoint(j, delta, type)); + m_breakpoint_indices_queue.enqueue(m_breakpoint_indices_queue.size(), abs(delta)); + } + + // j is the basic column, x is the value at x[j] + // d is the coefficient before m_entering in the row with j as the basis column + void try_add_breakpoint(unsigned j, const X & x, const T & d, breakpoint_type break_type, const X & break_value) { + X diff = x - break_value; + if (is_zero(diff)) { + switch (break_type) { + case low_break: + if (!same_sign_with_entering_delta(d)) + return; // no breakpoint + break; + case upper_break: + if (same_sign_with_entering_delta(d)) + return; // no breakpoint + break; + default: break; + } + add_breakpoint(j, zero_of_type(), break_type); + return; + } + auto delta_j = diff / d; + if (same_sign_with_entering_delta(delta_j)) + add_breakpoint(j, delta_j, break_type); + } + template + bool same_sign_with_entering_delta(const L & a) { + return (a > zero_of_type() && m_sign_of_entering_delta > 0) || (a < zero_of_type() && m_sign_of_entering_delta < 0); + } // todo: check that it works correctly + + void init_costs_from_backup() { + this->m_costs = m_costs_backup; + m_using_inf_costs = false; + } + + void init_reduced_costs() { + lean_assert(m_current_x_is_feasible == calc_current_x_is_feasible()); + if (get_current_x_is_infeasible()) { + init_infeasibility_costs(); + } else if (m_using_inf_costs) { + init_costs_from_backup(); + lean_assert(m_using_inf_costs == false); + } + this->init_reduced_costs_for_one_iteration(); + } + + bool low_bounds_are_set() const { return true; } + friend core_solver_pretty_printer; +}; +} diff --git a/src/util/lp/lp_primal_simplex.h b/src/util/lp/lp_primal_simplex.h new file mode 100644 index 0000000000..2ca60cc6d4 --- /dev/null +++ b/src/util/lp/lp_primal_simplex.h @@ -0,0 +1,465 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include "util/lp/lp_primal_core_solver.h" +#include "util/lp/lp_solver.h" +#include +#include +#include +#include +#include "util/lp/column_info.h" + +namespace lean { +using std::vector; +using std::tuple; + +template +class lp_primal_simplex: public lp_solver { + lp_primal_core_solver * m_core_solver = nullptr; + vector m_low_bounds; +private: + unsigned original_rows() { return this->m_external_rows_to_core_solver_rows.size(); } + + void fill_costs_and_x_for_first_stage_solver(unsigned original_number_of_columns) { + unsigned slack_var = original_number_of_columns; + unsigned artificial = original_number_of_columns + this->m_slacks; + + for (unsigned row = 0; row < this->row_count(); row++) { + fill_costs_and_x_for_first_stage_solver_for_row(row, slack_var, artificial); + } + } + + void init_buffer(unsigned k, vector & r) { + for (unsigned i = 0; i < k; i++) { + r[i] = 0; + } + r[k] = 1; + for (unsigned i = this->row_count() -1; i > k; i--) { + r[i] = 0; + } + } + + void refactor() { + m_core_solver->init_lu(); + if (m_core_solver->factorization()->get_status() != LU_status::OK) { + cout << "cannot refactor \n"; + throw "cannot refactor"; + } + } + + void set_scaled_costs() { + unsigned j = this->number_of_core_structurals(); + while (j-- > 0) { + this->set_scaled_cost(j); + } + } + + void stage_two() { + cout << "starting stage 2" << endl; + lean_assert(!m_core_solver->A_mult_x_is_off()); + int j = this->m_A->column_count() - 1; + unsigned core_solver_cols = this->number_of_core_structurals(); + + while (j >= core_solver_cols) { + this->m_costs[j--] = numeric_traits::zero(); + } + + set_scaled_costs(); + m_core_solver->set_status(lp_status::FEASIBLE); + this->m_second_stage_iterations = m_core_solver->solve(); + this->m_status = m_core_solver->get_status(); + // cout << "status is " << lp_status_to_string(this->m_status) << endl; + } +public: + lp_primal_simplex() {} + + + + column_info * get_or_create_column_info(unsigned column) { + auto it = this->m_columns.find(column); + return (it == this->m_columns.end())? ( this->m_columns[column] = new column_info) : it->second; + } + + void set_status(lp_status status) { + this->m_status = status; + } + + lp_status get_status() { + return this->m_status; + } + + void fill_acceptable_values_for_x() { + for (auto t : this->m_core_solver_columns_to_external_columns) { + this->m_x[t.first] = numeric_traits::zero(); + lean_assert(this->m_x[t.first] >= 0); + } + } + + + void set_zero_bound(bool * bound_is_set, T * bounds, unsigned i) { + bound_is_set[i] = true; + bounds[i] = numeric_traits::zero(); + } + + void fill_costs_and_x_for_first_stage_solver_for_row( + int row, + unsigned & slack_var, + unsigned & artificial) { + lean_assert(row >= 0 && row < this->row_count()); + auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[row]]; + // we need to bring the program to the form Ax = b + T rs = this->m_b[row]; + T artificial_cost = - numeric_traits::one(); + switch (constraint.m_relation) { + case Equal: // no slack variable here + this->m_column_types[artificial] = low_bound; + this->m_costs[artificial] = artificial_cost; // we are maximizing, so the artificial, which is non-negatiive, will be pushed to zero + this->m_basis[row] = artificial; + if (rs >= 0) { + (*this->m_A)(row, artificial) = numeric_traits::one(); + this->m_x[artificial] = rs; + } else { + (*this->m_A)(row, artificial) = - numeric_traits::one(); + this->m_x[artificial] = - rs; + } + artificial++; + break; + + case Greater_or_equal: + this->m_column_types[slack_var] = low_bound; + (*this->m_A)(row, slack_var) = - numeric_traits::one(); + + if (rs > 0) { + lean_assert(numeric_traits::is_zero(this->m_x[slack_var])); + // adding one artificial + this->m_column_types[artificial] = low_bound; + (*this->m_A)(row, artificial) = numeric_traits::one(); + this->m_costs[artificial] = artificial_cost; + this->m_basis[row] = artificial; + this->m_x[artificial] = rs; + artificial++; + } else { + // we can put a slack_var into the basis, and avoid adding an artificial variable + this->m_basis[row] = slack_var; + this->m_x[slack_var] = - rs; + } + slack_var++; + break; + case Less_or_equal: + // introduce a non-negative slack variable + this->m_column_types[slack_var] = low_bound; + (*this->m_A)(row, slack_var) = numeric_traits::one(); + + if (rs < 0) { + // adding one artificial + lean_assert(numeric_traits::is_zero(this->m_x[slack_var])); + this->m_column_types[artificial] = low_bound; + (*this->m_A)(row, artificial) = - numeric_traits::one(); + this->m_costs[artificial] = artificial_cost; + this->m_x[artificial] = - rs; + this->m_basis[row] = artificial++; + } else { + // we can put slack_var into the basis, and avoid adding an artificial variable + this->m_basis[row] = slack_var; + this->m_x[slack_var] = rs; + } + slack_var++; + break; + } + } + + + + string name_of_core_solver_column(unsigned j) { // j here is the core solver index + unsigned external_j = this->m_core_solver_columns_to_external_columns[j]; + auto t = this->m_columns.find(external_j); + if (t == this->m_columns.end()) { + return string("name_not_found"); + } + return t->m_name; + } + + + void set_core_solver_bounds() { + unsigned total_vars = this->m_A->column_count() + this->m_slacks + this->m_artificials; + this->m_column_types.resize(total_vars); + this->m_upper_bounds.resize(total_vars); + for (auto cit : this->m_columns) { + column_info * ci = cit.second; + auto p = this->m_external_columns_to_core_solver_columns.find(cit.first); + if (p == this->m_external_columns_to_core_solver_columns.end()) continue; + unsigned j = p->second; + switch (this->m_column_types[j] = ci->get_column_type()){ + case fixed: + this->m_upper_bounds[j] = numeric_traits::zero(); + break; + case boxed: + this->m_upper_bounds[j] = ci->get_adjusted_upper_bound() / this->m_column_scale[j]; + break; + + default: break; // do nothing + } + } + } + + void update_time_limit_from_starting_time(int start_time) { + this->m_settings.time_limit -= (get_millisecond_span(start_time) / 1000.); + } + + void find_maximal_solution() { + int preprocessing_start_time = get_millisecond_count(); + if (this->problem_is_empty()) { + this->m_status = lp_status::EMPTY; + return; + } + + this->cleanup(); + this->fill_matrix_A_and_init_right_side(); + if (this->m_status == lp_status::INFEASIBLE) { + return; + } + this->m_x.resize(this->m_A->column_count()); + this->fill_m_b(); + this->scale(); + fill_acceptable_values_for_x(); + this->count_slacks_and_artificials(); + set_core_solver_bounds(); + update_time_limit_from_starting_time(preprocessing_start_time); + solve_with_total_inf(); + } + + void fill_A_x_and_basis_for_stage_on_total_inf() { + for (unsigned row = 0; row < this->row_count(); row++) + fill_A_x_and_basis_for_stage_on_total_inf_for_row(row); + } + + void fill_A_x_and_basis_for_stage_on_total_inf_for_row(unsigned row) { + lean_assert(row < this->row_count()); + auto ext_row_it = this->m_core_solver_rows_to_external_rows.find(row); + lean_assert(ext_row_it != this->m_core_solver_rows_to_external_rows.end()); + unsigned ext_row = ext_row_it->second; + auto constr_it = this->m_constraints.find(ext_row); + lean_assert(constr_it != this->m_constraints.end()); + auto & constraint = constr_it->second; + unsigned j = this->m_A->column_count(); // j is a slack variable + this->m_A->add_column(); + // we need to bring the program to the form Ax = b + this->m_basis[row] = j; + switch (constraint.m_relation) { + case Equal: + this->m_x[j] = this->m_b[row]; + (*this->m_A)(row, j) = numeric_traits::one(); + this->m_column_types[j] = fixed; + this->m_upper_bounds[j] = m_low_bounds[j] = zero_of_type(); + break; + + case Greater_or_equal: + this->m_x[j] = - this->m_b[row]; + (*this->m_A)(row, j) = - numeric_traits::one(); + this->m_column_types[j] = low_bound; + this->m_upper_bounds[j] = zero_of_type(); + break; + case Less_or_equal: + this->m_x[j] = this->m_b[row]; + (*this->m_A)(row, j) = numeric_traits::one(); + this->m_column_types[j] = low_bound; + this->m_upper_bounds[j] = m_low_bounds[j] = zero_of_type(); + break; + } + } + + void solve_with_total_inf() { + cout << "starting solve_with_total_inf()" << endl; + int total_vars = this->m_A->column_count() + this->row_count(); + m_low_bounds.clear(); + m_low_bounds.resize(total_vars, zero_of_type()); // low bounds are shifted ot zero + this->m_x.resize(total_vars, numeric_traits::zero()); + this->m_basis.resize(this->row_count()); + this->m_costs.clear(); + this->m_costs.resize(total_vars, zero_of_type()); + fill_A_x_and_basis_for_stage_on_total_inf(); + this->print_statistics_on_A(); + this->fill_column_names_for_core_solver(); + int j = this->m_A->column_count() - 1; + unsigned core_solver_cols = this->number_of_core_structurals(); + + while (j >= core_solver_cols) + this->m_costs[j--] = numeric_traits::zero(); + + set_scaled_costs(); + m_core_solver = new lp_primal_core_solver(*this->m_A, + this->m_b, + this->m_x, + this->m_basis, + this->m_costs, + this->m_column_types, + m_low_bounds, + this->m_upper_bounds, + this->m_settings, this->m_name_map); + m_core_solver->solve(); + this->m_status = m_core_solver->m_status; + this->m_total_iterations = m_core_solver->m_total_iterations; + } + + + // void stage_one_of_total_inf() { + // cout << "starting stage_one_of_total_inf()" << endl; + // int total_vars = this->m_A->column_count() + this->row_count(); + // m_low_bounds.clear(); + // m_low_bounds.resize(total_vars, zero_of_type()); // low bounds are shifted ot zero + // this->m_x.resize(total_vars, numeric_traits::zero()); + // this->m_basis.resize(this->row_count()); + // this->m_costs.clear(); + // this->m_costs.resize(total_vars, zero_of_type()); + // fill_A_x_and_basis_for_stage_on_total_inf(); + // this->print_statistics_on_A(); + // this->fill_column_names_for_core_solver(); + // m_core_solver = new lp_primal_core_solver(*this->m_A, + // this->m_b, + // this->m_x, + // this->m_basis, + // this->m_costs, + // this->m_column_types, + // m_low_bounds, + // this->m_upper_bounds, + // this->m_settings, this->m_name_map); + // m_core_solver->find_feasible_solution(); + // this->m_first_stage_iterations = m_core_solver->m_total_iterations; + // this->m_status = m_core_solver->m_status == lp_status::OPTIMAL? lp_status::FEASIBLE: m_core_solver->m_status; // just map FEASIBLE to OPTIMAL and do not change the rest + // } + + ~lp_primal_simplex() { + if (m_core_solver != nullptr) { + delete m_core_solver; + } + } + + bool bounds_hold(unordered_map const & solution) { + for (auto it : this->m_columns) { + auto sol_it = solution.find(it.second->get_name()); + if (sol_it == solution.end()) { + cout << "cannot find column " << it.first << " in solution " << endl; + throw; + } + + if (!it.second->bounds_hold(sol_it->second)) { + cout << "bounds do not hold for " << it.second->get_name() << endl; + it.second->bounds_hold(sol_it->second); + return false; + } + } + return true; + } + + T get_row_value(unsigned i, unordered_map const & solution, bool print) { + auto it = this->m_A_values.find(i); + if (it == this->m_A_values.end()) { + cout << "cannot find row " << i << endl; + throw "get_row_value"; + } + T ret = numeric_traits::zero(); + for (auto & pair : it->second) { + auto cit = this->m_columns.find(pair.first); + if (cit == this->m_columns.end()){ + cout << "cannot find column " << pair.first << endl; + } + + column_info * ci = cit->second; + auto sol_it = solution.find(ci->get_name()); + if (sol_it == solution.end()) { + cout << "cannot find in the solution column " << ci->get_name() << endl; + } + T column_val = sol_it->second; + if (print) { + cout << pair.second << "(" << ci->get_name() << "=" << column_val << ") "; + } + ret += pair.second * column_val; + } + if (print) { + cout << " = " << ret << endl; + } + return ret; + } + + bool row_constraint_holds(unsigned i, unordered_map const & solution, bool print) { + T row_val = get_row_value(i, solution, print); + auto & constraint = this->m_constraints[i]; + T rs = constraint.m_rs; + switch (constraint.m_relation) { + case Equal: + if (fabs(numeric_traits::get_double(row_val - rs)) > 0.00001) { + if (print) { + cout << "should be = " << rs << endl; + } + return false; + } + return true; + case Greater_or_equal: + if (numeric_traits::get_double(row_val - rs) < -0.00001) { + if (print) { + cout << "should be >= " << rs << endl; + } + return false; + } + return true;; + + case Less_or_equal: + if (numeric_traits::get_double(row_val - rs) > 0.00001) { + if (print) { + cout << "should be <= " << rs << endl; + } + return false; + } + return true;; + } + cout << "throw in row_constraint_holds " << endl; + throw "wrong case"; + } + + bool row_constraints_hold(unordered_map const & solution) { + for (auto it : this->m_A_values) { + if (!row_constraint_holds(it.first, solution, false)) { + row_constraint_holds(it.first, solution, true); + return false; + } + } + return true; + } + + + T * get_array_from_map(unordered_map const & solution) { + T * t = new T[solution.size()]; + for (auto it : solution) { + auto g = this->m_names_to_columns.find(it.first); + if (g == this->m_names_to_columns.end()) { + string s = string("cannot find name ") + " "+ it.first; + cout << "throw in get_array_from_map" << endl; + throw s; + } + t[g->second] = it.second; + } + return t; + } + + bool solution_is_feasible(unordered_map const & solution) { + return bounds_hold(solution) && row_constraints_hold(solution); + } + + virtual T get_column_value(unsigned column) const { + return this->get_column_value_with_core_solver(column, m_core_solver); + } + + T get_current_cost() const { + T ret = numeric_traits::zero(); + for (auto it : this->m_columns) { + ret += this->get_column_cost_value(it.first, it.second); + } + return ret; + } +}; +} diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h new file mode 100644 index 0000000000..cbae166893 --- /dev/null +++ b/src/util/lp/lp_settings.h @@ -0,0 +1,216 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include +#include +#include + + +namespace lean { + +enum column_type { + fixed, + boxed, + low_bound, + upper_bound, + free_column +}; + +inline std::string column_type_to_string(column_type t) { + switch (t) { + case fixed: + return std::string("fixed"); + case boxed: + return std::string("boxed"); + case low_bound: + return std::string("low_bound"); + case upper_bound: + return std::string("upper_bound"); + case free_column: + return std::string("free_column"); + default: + throw "unexpected"; + } +} + +enum lp_status { + UNKNOWN, + INFEASIBLE, + TENTATIVE_UNBOUNDED, + UNBOUNDED, + TENTATIVE_DUAL_UNBOUNDED, + DUAL_UNBOUNDED, + OPTIMAL, + FEASIBLE, + FLOATING_POINT_ERROR, + TIME_EXHAUSTED, + ITERATIONS_EXHAUSTED, + EMPTY, + UNSTABLE +}; + +inline const char* lp_status_to_string(lp_status status) { + switch (status) { + case UNKNOWN: return "UNKNOWN"; + case INFEASIBLE: return "INFEASIBLE"; + case UNBOUNDED: return "UNBOUNDED"; + case TENTATIVE_DUAL_UNBOUNDED: return "TENTATIVE_DUAL_UNBOUNDED"; + case DUAL_UNBOUNDED: return "DUAL_UNBOUNDED"; + case OPTIMAL: return "OPTIMAL"; + case FEASIBLE: return "FEASIBLE"; + case FLOATING_POINT_ERROR: return "FLOATING_POINT_ERROR"; + case TIME_EXHAUSTED: return "TIME_EXHAUSTED"; + case ITERATIONS_EXHAUSTED: return "ITERATIONS_EXHAUSTED"; + case EMPTY: return "EMPTY"; + case UNSTABLE: return "UNSTABLE"; + default: + std::cout << "throwing in lp_status_to_string " << std::endl; + throw "lp_status_to_string"; + } +} + +inline lp_status lp_status_from_string(std::string status) { + if (status == "UNKNOWN") return lp_status::UNKNOWN; + if (status == "INFEASIBLE") return lp_status::INFEASIBLE; + if (status == "UNBOUNDED") return lp_status::UNBOUNDED; + if (status == "OPTIMAL") return lp_status::OPTIMAL; + if (status == "FEASIBLE") return lp_status::FEASIBLE; + if (status == "FLOATING_POINT_ERROR") return lp_status::FLOATING_POINT_ERROR; + if (status == "TIME_EXHAUSTED") return lp_status::TIME_EXHAUSTED; + if (status == "ITERATIONS_EXHAUSTED") return lp_status::ITERATIONS_EXHAUSTED; + if (status == "EMPTY") return lp_status::EMPTY; + std::cout << "unexpected status " << status << std::endl; + throw "wrong status in a test file"; +} + +enum non_basic_column_value_position { at_low_bound, at_upper_bound, at_fixed, free_of_bounds }; + +template bool is_epsilon_small(const X & v, const double& eps); // forward definition +template bool precise() { return numeric_traits::precise();} +template X zero_of_type() { return numeric_traits::zero(); } +template X one_of_type() { return numeric_traits::one(); } +template bool is_zero(const X & v) { return numeric_traits::is_zero(v); } +template double get_double(const X & v) { return numeric_traits::get_double(v); } + +struct lp_settings { + // when the absolute value of an element is less than pivot_epsilon + // in pivoting, we treat it as a zero + double pivot_epsilon = 0.00000001; + // see Chatal, page 115 + double positive_price_epsilon = 1e-7; + // a quatation "if some choice of the entering vairable leads to an eta matrix + // whose diagonal element in the eta column is less than e2 (entering_diag_epsilon) in magnitude, the this choice is rejected ... + double entering_diag_epsilon = 1e-8; + double c_partial_pivoting = 10; // this is the constant c from page 410 + unsigned depth_of_rook_search = 4; + bool using_partial_pivoting = true; + // dissertation of Achim Koberstein + // if Bx - b is different at any component more that refactor_epsilon then we refactor + double refactor_tolerance = 1e-4; + double pivot_tolerance = 1e-6; + double zero_tolerance = 1e-12; + double drop_tolerance = 1e-14; + double tolerance_for_artificials = 1e-4; + double can_be_taken_to_basis_tolerance = 0.00001; + + unsigned percent_of_entering_to_check = 5; // we try to find a profitable column in a percentage of the columns + bool use_scaling = true; + double scaling_maximum = 1; + double scaling_minimum = 0.5; + double harris_feasibility_tolerance = 1e-7; // page 179 of Istvan Maros + double ignore_epsilon_of_harris = 10e-5; + unsigned max_number_of_iterations_with_no_improvements = 2000000; + unsigned max_total_number_of_iterations = 20000000; + double time_limit = std::numeric_limits::max(); // the maximum time limit of the total run time in seconds + // dual section + double dual_feasibility_tolerance = 1e-7; // // page 71 of the PhD thesis of Achim Koberstein + double primal_feasibility_tolerance = 1e-7; // page 71 of the PhD thesis of Achim Koberstein + double relative_primal_feasibility_tolerance = 1e-9; // page 71 of the PhD thesis of Achim Koberstein + + + template static bool is_eps_small_general(const T & t, const double & eps) { + return (!numeric_traits::precise())? is_epsilon_small(t, eps) : numeric_traits::is_zero(t); + } + + template + bool abs_val_is_smaller_than_dual_feasibility_tolerance(T const & t) { + return is_eps_small_general(t, dual_feasibility_tolerance); + } + + template + bool abs_val_is_smaller_than_primal_feasibility_tolerance(T const & t) { + return is_eps_small_general(t, dual_feasibility_tolerance); + } + + template + bool abs_val_is_smaller_than_can_be_taken_to_basis_tolerance(T const & t) { + return is_eps_small_general(t, can_be_taken_to_basis_tolerance); + } + + template + bool abs_val_is_smaller_than_drop_tolerance(T const & t) { + return is_eps_small_general(t, drop_tolerance); + } + + + template + bool abs_val_is_smaller_than_zero_tolerance(T const & t) { + return is_eps_small_general(t, zero_tolerance); + } + + template + bool abs_val_is_smaller_than_refactor_tolerance(T const & t) { + return is_eps_small_general(t, refactor_tolerance); + } + + + template + bool abs_val_is_smaller_than_pivot_tolerance(T const & t) { + return is_eps_small_general(t, pivot_tolerance); + } + + template + bool abs_val_is_smaller_than_harris_tolerance(T const & t) { + return is_eps_small_general(t, harris_feasibility_tolerance); + } + + template + bool abs_val_is_smaller_than_ignore_epslilon_for_harris(T const & t) { + return is_eps_small_general(t, ignore_epsilon_of_harris); + } + + template + bool abs_val_is_smaller_than_artificial_tolerance(T const & t) { + return is_eps_small_general(t, tolerance_for_artificials); + } + // the method of lar solver to use + bool row_feasibility = true; + bool use_double_solver_for_lar = true; + int report_frequency = 1000; + unsigned column_norms_update_frequency = 1000; + bool scale_with_ratio = true; + double density_threshold = 0.7; // need to tune it up, todo +#ifndef NDEBUG + bool dense_deb; + static unsigned ddd; // used for debugging +#endif +}; +int get_millisecond_count() { + timeb tb; + ftime(&tb); + return tb.millitm + (tb.time & 0xfffff) * 1000; +} + +int get_millisecond_span(int start_time) { + int span = get_millisecond_count() - start_time; + if (span < 0) + span += 0x100000 * 1000; + return span; +} +} diff --git a/src/util/lp/lp_solver.h b/src/util/lp/lp_solver.h new file mode 100644 index 0000000000..831aa60249 --- /dev/null +++ b/src/util/lp/lp_solver.h @@ -0,0 +1,688 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once + +#include "util/lp/lp_settings.h" +#include +#include +#include "util/lp/column_info.h" +#include "util/lp/static_matrix.h" +#include +#include "util/lp/lp_core_solver_base.h" +#include +#include "util/lp/scaler.h" +namespace lean { +enum lp_relation { + Less_or_equal, + Equal, + Greater_or_equal +}; + + + +template +struct lp_constraint { + X m_rs; // right side of the constraint + lp_relation m_relation; + lp_constraint() {} // empty constructor + lp_constraint(T rs, lp_relation relation): m_rs(rs), m_relation(relation) {} +}; + +template +class lp_solver { + column_info * get_or_create_column_info(unsigned column) { + auto it = m_columns.find(column); + return (it == m_columns.end())? ( m_columns[column] = new column_info) : it->second; + } + +protected: + T get_column_cost_value(unsigned j, column_info * ci) const { + if (ci->is_fixed()) { + return ci->get_cost() * ci->get_fixed_value(); + } + return ci->get_cost() * get_column_value(j); + } +public: + unsigned m_total_iterations; + static_matrix* m_A = nullptr; // this is the matrix of constraints + vector m_b; // the right side vector + unsigned m_first_stage_iterations = 0; + unsigned m_second_stage_iterations = 0; + unordered_map> m_constraints; + unordered_map*> m_columns; + unordered_map > m_A_values; + unordered_map m_names_to_columns; // don't have to use it + unordered_map m_external_rows_to_core_solver_rows; + unordered_map m_core_solver_rows_to_external_rows; + unordered_map m_external_columns_to_core_solver_columns; + unordered_map m_core_solver_columns_to_external_columns; + vector m_column_scale; + unordered_map m_name_map; + unsigned m_artificials = 0; + unsigned m_slacks = 0; + vector m_column_types; + vector m_costs; + vector m_x; + vector m_upper_bounds; + vector m_basis; + + lp_status m_status = lp_status::UNKNOWN; + + lp_settings m_settings; + lp_solver() {} + + unsigned row_count() const { return this->m_A->row_count(); } + + void add_constraint(lp_relation relation, T right_side, unsigned row_index) { + lean_assert(m_constraints.find(row_index) == m_constraints.end()); + lp_constraint cs(right_side, relation); + m_constraints[row_index] = cs; + } + + void set_cost_for_column(unsigned column, T column_cost) { + get_or_create_column_info(column)->set_cost(column_cost); + } + + void set_row_column_coefficient(unsigned row, unsigned column, T const & val) { + m_A_values[row][column] = val; + } + // returns the current cost + virtual T get_current_cost() const = 0; + // do not have to call it + void give_symbolic_name_to_column(string name, unsigned column) { + auto it = m_columns.find(column); + column_info *ci; + if (it == m_columns.end()){ + m_columns[column] = ci = new column_info; + } else { + ci = it->second; + } + ci->set_name(name); + m_names_to_columns[name] = column; + } + + virtual T get_column_value(unsigned column) const = 0; + + T get_column_value_by_name(std::string name) const { + auto it = m_names_to_columns.find(name); + if (it == m_names_to_columns.end()) { + cout << "throwing in get_column_value_by_name" << endl; + throw "get_column_value_by_name"; + } + return get_column_value(it -> second); + } + + // returns -1 if not found + virtual int get_column_index_by_name(std::string name) const { + auto t = m_names_to_columns.find(name); + if (t == m_names_to_columns.end()) { + return -1; + } + return t->second; + } + + void set_low_bound(unsigned i, T bound) { + column_info *ci = get_or_create_column_info(i); + ci->set_low_bound(bound); + } + + void set_upper_bound(unsigned i, T bound) { + column_info *ci = get_or_create_column_info(i); + ci->set_upper_bound(bound); + } + + void unset_low_bound(unsigned i) { + get_or_create_column_info(i)->unset_low_bound(); + } + + void unset_upper_bound(unsigned i) { + get_or_create_column_info(i)->unset_upper_bound(); + } + + void set_fixed_value(unsigned i, T val) { + column_info *ci = get_or_create_column_info(i); + ci->set_fixed_value(val); + } + + void unset_fixed_value(unsigned i) { + get_or_create_column_info(i)->unset_fixed(); + } + + lp_status get_status() const { + return m_status; + } + + virtual ~lp_solver(){ + if (m_A != nullptr) { + delete m_A; + } + for (auto t : m_columns) { + delete t.second; + } + } + + void flip_costs() { + for (auto t : m_columns) { + column_info *ci = t.second; + ci->set_cost(-ci->get_cost()); + } + } + + virtual void find_maximal_solution() = 0; + void set_time_limit(unsigned time_limit_in_seconds) { + m_settings.time_limit = time_limit_in_seconds; + } + + void set_max_iterations_per_stage(unsigned max_iterations) { + m_settings.max_total_number_of_iterations = max_iterations; + } + + void get_max_iterations_per_stage() const { + return m_settings.max_total_number_of_iterations; + } +protected: + bool problem_is_empty() { + for (auto & c : m_A_values) + if (c.second.size()) + return false; + return true; + } + + void scale() { + if (numeric_traits::precise() || m_settings.use_scaling == false) { + m_column_scale.clear(); + m_column_scale.resize(m_A->column_count(), one_of_type()); + return; + } + + T smin = T(m_settings.scaling_minimum); + T smax = T(m_settings.scaling_maximum); + + scaler scaler(m_b, *m_A, smin, smax, m_column_scale, this->m_settings); + if (!scaler.scale()) { + unscale(); + } + } + + + void print_rows_scale_stats() { + cout << "rows max" << endl; + for (unsigned i = 0; i < m_A->row_count(); i++) { + print_row_scale_stats(i); + } + cout << endl; + } + + void print_columns_scale_stats() { + cout << "columns max" << endl; + for (unsigned i = 0; i < m_A->column_count(); i++) { + print_column_scale_stats(i); + } + cout << endl; + } + + void print_row_scale_stats(unsigned i) { + cout << "(" << std::min(m_A->get_min_abs_in_row(i), abs(m_b[i])) << " "; + cout << std::max(m_A->get_max_abs_in_row(i), abs(m_b[i])) << ")"; + } + + void print_column_scale_stats(unsigned j) { + cout << "(" << m_A->get_min_abs_in_row(j) << " "; + cout << m_A->get_max_abs_in_column(j) << ")"; + } + + void print_scale_stats() { + print_rows_scale_stats(); + print_columns_scale_stats(); + } + + void get_max_abs_in_row(unordered_map & row_map) { + T ret = numeric_traits::zero(); + for (auto jp : row_map) { + T ac = numeric_traits::abs(jp->second); + if (ac > ret) { + ret = ac; + } + } + return ret; + } + + void pin_vars_down_on_row(unordered_map & row) { + pin_vars_on_row_with_sign(row, - numeric_traits::one()); + } + + void pin_vars_up_on_row(unordered_map & row) { + pin_vars_on_row_with_sign(row, numeric_traits::one()); + } + + void pin_vars_on_row_with_sign(unordered_map & row, T sign ) { + unordered_map pinned; + for (auto t : row) { + unsigned j = t.first; + column_info * ci = m_columns[j]; + T a = t.second; + if (a * sign > numeric_traits::zero()) { + lean_assert(ci->upper_bound_is_set()); + ci->set_fixed_value(ci->get_upper_bound()); + } else { + lean_assert(ci->low_bound_is_set()); + ci->set_fixed_value(ci->get_low_bound()); + } + } + } + + bool get_minimal_row_value(unordered_map & row, T & low_bound) { + low_bound = numeric_traits::zero(); + for (auto & t : row) { + T a = t.second; + column_info * ci = m_columns[t.first]; + if (a > numeric_traits::zero()) { + if (ci->low_bound_is_set()) { + low_bound += ci->get_low_bound() * a; + } else { + return false; + } + } else { + if (ci->upper_bound_is_set()) { + low_bound += ci->get_upper_bound() * a; + } else { + return false; + } + } + } + return true; + } + + bool get_maximal_row_value(unordered_map & row, T & low_bound) { + low_bound = numeric_traits::zero(); + for (auto & t : row) { + T a = t.second; + column_info * ci = m_columns[t.first]; + if (a < numeric_traits::zero()) { + if (ci->low_bound_is_set()) { + low_bound += ci->get_low_bound() * a; + } else { + return false; + } + } else { + if (ci->upper_bound_is_set()) { + low_bound += ci->get_upper_bound() * a; + } else { + return false; + } + } + } + return true; + } + + bool row_is_zero(unordered_map & row) { + for (auto & t : row) { + if (!is_zero(t.second)) + return false; + } + return true; + } + + bool row_e_is_obsolete(unordered_map & row, unsigned row_index) { + T rs = m_constraints[row_index].m_rs; + if (row_is_zero(row)) { + if (!is_zero(rs)) + m_status = INFEASIBLE; + return true; + } + + T low_bound; + bool lb = get_minimal_row_value(row, low_bound); + if (lb) { + T diff = low_bound - rs; + if (!val_is_smaller_than_eps(diff, m_settings.refactor_tolerance)){ + // low_bound > rs + m_settings.refactor_epsilon + m_status = INFEASIBLE; + return true; + } + if (val_is_smaller_than_eps(-diff, m_settings.refactor_tolerance)){ + pin_vars_down_on_row(row); + return true; + } + } + + T upper_bound; + bool ub = get_maximal_row_value(row, upper_bound); + if (ub) { + T diff = rs - upper_bound; + if (!val_is_smaller_than_eps(diff, m_settings.refactor_tolerance)) { + // upper_bound < rs - m_settings.refactor_tolerance + m_status = INFEASIBLE; + return true; + } + if (val_is_smaller_than_eps(-diff, m_settings.refactor_tolerance)){ + pin_vars_up_on_row(row); + return true; + } + } + + return false; + } + + int row_ge_is_obsolete(unordered_map & row, unsigned row_index) { + T rs = m_constraints[row_index].m_rs; + if (row_is_zero(row)) { + if (rs > zero_of_type()) + m_status = INFEASIBLE; + return true; + } + + T upper_bound; + if (get_maximal_row_value(row, upper_bound)) { + T diff = rs - upper_bound; + if (!val_is_smaller_than_eps(diff, m_settings.refactor_tolerance)) { + // upper_bound < rs - m_settings.refactor_tolerance + m_status = INFEASIBLE; + return true; + } + if (val_is_smaller_than_eps(-diff, m_settings.refactor_tolerance)){ + pin_vars_up_on_row(row); + return true; + } + } + + return false; + } + + bool row_le_is_obsolete(unordered_map & row, unsigned row_index) { + T low_bound; + T rs = m_constraints[row_index].m_rs; + if (row_is_zero(row)) { + if (rs < zero_of_type()) + m_status = INFEASIBLE; + return true; + } + + if (get_minimal_row_value(row, low_bound)) { + T diff = low_bound - rs; + if (!val_is_smaller_than_eps(diff, m_settings.refactor_tolerance)){ + // low_bound > rs + m_settings.refactor_tolerance + m_status = lp_status::INFEASIBLE; + return true; + } + if (val_is_smaller_than_eps(-diff, m_settings.refactor_tolerance)){ + pin_vars_down_on_row(row); + return true; + } + } + + return false; + } + + // analyse possible max and min values that are derived from var boundaries + // Let us say that the we have a "ge" constraint, and the min value is equal to the rs. + // Then we know what values of the variables are. For each positive coeff of the row it has to be + // the low boundary of the var and for a negative - the upper. + + // this routing also pins the variables to the boundaries + bool row_is_obsolete(unordered_map & row, unsigned row_index ) { + auto & constraint = m_constraints[row_index]; + switch (constraint.m_relation) { + case lp_relation::Equal: + return row_e_is_obsolete(row, row_index); + + case lp_relation::Greater_or_equal: + return row_ge_is_obsolete(row, row_index); + + case lp_relation::Less_or_equal: + return row_le_is_obsolete(row, row_index); + } + + throw "unexpected relation"; + } + + + void remove_fixed_or_zero_columns() { + for (auto & i_row : m_A_values) { + remove_fixed_or_zero_columns_from_row(i_row.first, i_row.second); + } + } + + void remove_fixed_or_zero_columns_from_row(unsigned i, unordered_map & row) { + auto & constraint = m_constraints[i]; + vector removed; + for (auto & col : row) { + unsigned j = col.first; + lean_assert(m_columns.find(j) != m_columns.end()); + column_info * ci = m_columns[j]; + if (ci->is_fixed()) { + removed.push_back(j); + T aj = col.second; + constraint.m_rs -= aj * ci->get_fixed_value(); + } else { + if (numeric_traits::is_zero(col.second)){ + removed.push_back(j); + } + } + } + + for (auto j : removed) { + row.erase(j); + } + } + + unsigned try_to_remove_some_rows() { + vector rows_to_delete; + for (auto & t : m_A_values) { + if (row_is_obsolete(t.second, t.first)) { + rows_to_delete.push_back(t.first); + } + + if (m_status == lp_status::INFEASIBLE) { + return 0; + } + } + if (rows_to_delete.size() > 0) { + for (unsigned k : rows_to_delete) { + m_A_values.erase(k); + } + } + remove_fixed_or_zero_columns(); + return rows_to_delete.size(); + } + + void cleanup() { + int n = 0; // number of deleted rows + int d; + while ((d = try_to_remove_some_rows())) + n += d; + + if (n == 1) + cout << "deleted one row" << endl; + else if (n) + cout << "deleted " << n << " rows" << endl; + } + + void map_external_rows_to_core_solver_rows() { + unsigned size = 0; + for (auto & row : m_A_values) { + m_external_rows_to_core_solver_rows[row.first] = size; + m_core_solver_rows_to_external_rows[size] = row.first; + size++; + } + } + + void map_external_columns_to_core_solver_columns() { + unsigned size = 0; + for (auto & row : m_A_values) { + for (auto & col : row.second) { + if (col.second == numeric_traits::zero() || m_columns[col.first]->is_fixed()) { + cout << "found fixed column " << endl; + throw "map_external_columns_to_core_solver_columns"; + } + unsigned j = col.first; + auto j_place = m_external_columns_to_core_solver_columns.find(j); + if (j_place == m_external_columns_to_core_solver_columns.end()) { // j is a newcomer + m_external_columns_to_core_solver_columns[j] = size; + m_core_solver_columns_to_external_columns[size++] = j; + } + } + } + } + + void fill_column_names_for_core_solver() { + for (auto it : this->m_columns) { + auto p = this->m_external_columns_to_core_solver_columns.find(it.first); + if (p != this->m_external_columns_to_core_solver_columns.end()) { + this->m_name_map[p->second] = it.second->get_name(); + } + } + } + + unsigned number_of_core_structurals() { return m_external_columns_to_core_solver_columns.size(); } + + + void restore_column_scales_to_one() { + for (unsigned i = 0; i < m_column_scale.size(); i++) m_column_scale[i] = numeric_traits::one(); + } + + void unscale() { + delete m_A; + m_A = nullptr; + fill_A_from_A_values(); + restore_column_scales_to_one(); + fill_m_b(); + } + + void fill_A_from_A_values() { + m_A = new static_matrix(m_A_values.size(), number_of_core_structurals()); + for (auto & t : m_A_values) { + lean_assert(m_external_rows_to_core_solver_rows.find(t.first) != m_external_rows_to_core_solver_rows.end()); + unsigned row = m_external_rows_to_core_solver_rows[t.first]; + for (auto k : t.second) { + lean_assert(m_external_columns_to_core_solver_columns.find(k.first) != m_external_columns_to_core_solver_columns.end()); + unsigned col = m_external_columns_to_core_solver_columns[k.first]; + bool col_is_flipped = m_columns[k.first]->is_flipped(); + + if (!col_is_flipped) { + (*m_A)(row, col) = k.second; + } else { + (*m_A)(row, col) = - k.second; + } + } + } + } + + void fill_matrix_A_and_init_right_side() { + map_external_rows_to_core_solver_rows(); + map_external_columns_to_core_solver_columns(); + lean_assert(m_A == nullptr); + fill_A_from_A_values(); + m_b.resize(m_A->row_count()); + } + + void count_slacks_and_artificials() { + for (int i = row_count() - 1; i >= 0; i--) { + count_slacks_and_artificials_for_row(i); + } + } + + void count_slacks_and_artificials_for_row(unsigned i) { + lean_assert(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); + auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[i]]; + T rs; + switch (constraint.m_relation) { + case Equal: + m_artificials++; + break; + case Greater_or_equal: + m_slacks++; + rs = this->m_b[i]; + if (rs > 0) { + m_artificials++; + } + break; + case Less_or_equal: + m_slacks++; + rs = this->m_b[i]; + if (rs < 0) { + m_artificials++; + } + break; + } + } + + T low_bound_shift_for_row(unsigned i) { + T ret = numeric_traits::zero(); + + auto row = this->m_A_values.find(i); + if (row == this->m_A_values.end()) { + throw "cannot find row "; + } + for (auto col : row->second) { + ret += col.second * this->m_columns[col.first]->get_shift(); + } + return ret; + } + + void fill_m_b() { + for (int i = this->row_count() - 1; i >= 0; i--) { + lean_assert(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); + unsigned external_i = this->m_core_solver_rows_to_external_rows[i]; + auto & constraint = this->m_constraints[external_i]; + this->m_b[i] = constraint.m_rs - low_bound_shift_for_row(external_i); + } + } + + T get_column_value_with_core_solver(unsigned column, lp_core_solver_base * core_solver) const { + auto cit = this->m_columns.find(column); + if (cit == this->m_columns.end()) { + return numeric_traits::zero(); + } + + column_info * ci = cit->second; + + if (ci->is_fixed()) { + return ci->get_fixed_value(); + } + + auto t = this->m_external_columns_to_core_solver_columns.find(column); + if (t != this->m_external_columns_to_core_solver_columns.end()){ + unsigned cj = t->second; + T v = core_solver->get_var_value(cj) * this->m_column_scale[cj]; + if (ci->is_free()) { + return v; + } + if (!ci->is_flipped()) { + return v + ci->get_low_bound(); + } + + // the flipped case when there is only upper bound + return -v + ci->get_upper_bound(); // + } + + return numeric_traits::zero(); // returns zero for out of boundary columns + } + void set_scaled_cost(unsigned j) { + // grab original costs but modify it with the column scales + lean_assert(j < this->m_column_scale.size()); + column_info * ci = this->m_columns[this->m_core_solver_columns_to_external_columns[j]]; + T cost = ci->get_cost(); + if (ci->is_flipped()){ + cost *= -1; + } + lean_assert(ci->is_fixed() == false); + this->m_costs[j] = cost * this->m_column_scale[j]; + } + void print_statistics_on_A() { + cout << "extended A[" << this->m_A->row_count() << "," << this->m_A->column_count() << "]" << endl; + // for (unsigned i = 0; i < this->m_A->row_count(); i++) { + // if (this->m_A->number_of_non_zeroes_in_row(i) <= 2 ) { + // cout << "m_p[" << i << "] = " << this->m_A->number_of_non_zeroes_in_row(i) << endl; + // } + // } + } +public: + lp_settings & settings() { return m_settings;} +}; +} diff --git a/src/util/lp/lu.h b/src/util/lp/lu.h new file mode 100644 index 0000000000..baa7716364 --- /dev/null +++ b/src/util/lp/lu.h @@ -0,0 +1,886 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once + +#include +#include "util/debug.h" +#include "util/numerics/numeric_traits.h" +#include "util/numerics/xnumeral.h" +#include +#include +#include "util/lp/sparse_matrix.h" +#include "util/lp/static_matrix.h" +#include +#include "util/lp/numeric_pair.h" +#include +#include +#include "util/lp/row_eta_matrix.h" +#include "util/lp/square_dense_submatrix.h" +namespace lean { +template +std::string T_to_string(const T & t); // forward definition +#ifndef NDEBUG +template // print the nr x nc submatrix at the top left corner +void print_submatrix(sparse_matrix & m, unsigned mr, unsigned nc) { + vector> A; + vector widths; + for (unsigned i = 0; i < m.row_count() && i < mr ; i++) { + A.push_back(vector()); + for (unsigned j = 0; j < m.column_count() && j < nc; j++) { + A[i].push_back(T_to_string(static_cast(m(i, j)))); + } + } + + for (unsigned j = 0; j < m.column_count() && j < nc; j++) { + widths.push_back(get_width_of_column(j, A)); + } + + print_matrix_with_widths(A, widths); +} + +template +void print_matrix(static_matrix &m) { + vector> A; + vector widths; + std::set> domain = m.get_domain(); + for (unsigned i = 0; i < m.row_count(); i++) { + A.push_back(vector()); + for (unsigned j = 0; j < m.column_count(); j++) { + A[i].push_back(T_to_string(static_cast(m(i, j)))); + } + } + + for (unsigned j = 0; j < m.column_count(); j++) { + widths.push_back(get_width_of_column(j, A)); + } + + print_matrix_with_widths(A, widths); +} + +template +void print_matrix(sparse_matrix& m) { + vector> A; + vector widths; + for (unsigned i = 0; i < m.row_count(); i++) { + A.push_back(vector()); + for (unsigned j = 0; j < m.column_count(); j++) { + A[i].push_back(T_to_string(static_cast(m(i, j)))); + } + } + + for (unsigned j = 0; j < m.column_count(); j++) { + widths.push_back(get_width_of_column(j, A)); + } + + print_matrix_with_widths(A, widths); +} +#endif + +enum class LU_status { OK, Degenerated}; + +template +X dot_product(const std::vector & a, const std::vector & b, unsigned l) { + auto r = zero_of_type(); + for (unsigned i = 0; i < l; i++) { + r += a[i] * b[i]; + } + return r; +} + + +template +class one_elem_on_diag: public tail_matrix { + unsigned m_i; + T m_val; +public: + one_elem_on_diag(unsigned i, T val) : m_i(i), m_val(val) { +#ifndef NDEBUG + m_one_over_val = numeric_traits::one() / m_val; +#endif + } + + one_elem_on_diag(const one_elem_on_diag & o) { + m_i = o.m_i; + m_val = o.m_val; + +#ifndef NDEBUG + m_m = m_n = o.m_m; + m_one_over_val = numeric_traits::one() / o.m_val; +#endif + } + +#ifndef NDEBUG + unsigned m_m; + unsigned m_n; + virtual void set_number_of_rows(unsigned m) { m_m = m; m_n = m; } + virtual void set_number_of_columns(unsigned n) { m_m = n; m_n = n; } + T m_one_over_val; + + T get_elem (unsigned i, unsigned j) const { + if (i == j){ + if (j == m_i) { + return m_one_over_val; + } + return numeric_traits::one(); + } + + return numeric_traits::zero(); + } + + unsigned row_count() const { return m_m; } // not defined } + unsigned column_count() const { return m_m; } // not defined } +#endif + void apply_from_left(vector & w, lp_settings &) { + w[m_i] /= m_val; + } + + void apply_from_right(vector & w) { + w[m_i] /= m_val; + } + + void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) { + w[m_i] /= m_val; + if (settings.abs_val_is_smaller_than_drop_tolerance(w[m_i])) { // todo : is it needed? + w.erase_from_index(m_i); + w[m_i] = numeric_traits::zero(); + } + } + + void conjugate_by_permutation(permutation_matrix & p) { + // this = p * this * p(-1) +#ifndef NDEBUG + // auto rev = p.get_reverse(); + // auto deb = ((*this) * rev); + // deb = p * deb; +#endif + m_i = p.apply_reverse(m_i); + +#ifndef NDEBUG + // lean_assert(*this == deb); +#endif + } +}; // end of one_elem_on_diag + + // This class supports updates of the columns of B, and solves systems Bx=b,and yB=c + // Using Suhl-Suhl method described in the dissertation of Achim Koberstein, Chapter 5 + + +template +class lu { + LU_status m_status = LU_status::OK; +public: + // the fields + unsigned m_dim; + static_matrix const &m_A; + vector& m_basis; + permutation_matrix m_Q; + permutation_matrix m_R; + sparse_matrix m_U; + square_dense_submatrix* m_dense_LU; + + // m_tail is composed of tail_matrices: + // one_off_diagonal_matrix, and transposition_matrix + vector *> m_tail; + lp_settings & m_settings; + vector & m_basis_heading; + bool m_failure = false; + vector & m_non_basic_columns; + indexed_vector m_row_eta_work_vector; + // constructor + // if A is an m by n matrix then basis has length m and values in [0,n); the values are all different + // they represent the set of m columns + lu(static_matrix const & A, + vector& basis, + vector & basis_heading, + lp_settings & settings, + vector & non_basic_columns): + m_dim(A.row_count()), + m_A(A), + m_basis(basis), + m_Q(m_dim), + m_R(m_dim), + m_U(A, basis), // create the square matrix that eventually will be factorized + m_settings(settings), + m_basis_heading(basis_heading), + m_non_basic_columns(non_basic_columns), + m_row_eta_work_vector(A.row_count()){ +#ifndef NDEBUG + debug_test_of_basis(A, basis); +#endif + create_initial_factorization(); + if (get_status() != LU_status::OK) { + if (get_status() == LU_status::Degenerated) { + cout << "lu status is Degenerated" << endl; + } else { + cout << "lu status is " <(get_status()) << endl; + } + return; + } +#ifndef NDEBUG + // lean_assert(check_correctness()); +#endif + } + + void debug_test_of_basis(static_matrix const & A, std::vector & basis) { + std::set set; + for (unsigned i = 0; i < A.row_count(); i++) { + lean_assert(basis[i]< A.column_count()); + set.insert(basis[i]); + } + lean_assert(set.size() == A.row_count()); + } + + + unsigned non_basic_column_index_in_non_basic_columns(unsigned j) { + return - m_basis_heading[j] - 1; + } + + void solve_By(vector & y) { + init_vector_y(y); + solve_By_when_y_is_ready(y); + } + + void solve_Bd_when_w_is_ready(std::vector & d, indexed_vector& w ) { // w - the vector featuring in 24.3 + for (int i = m_dim - 1; i >= 0; i--) { // index ? todo + d[i] = w[i]; + } + solve_By_when_y_is_ready(d); + } + + template + void solve_By_when_y_is_ready(vector & y) { + m_U.double_solve_U_y(y); + m_R.apply_reverse_from_left(y); // see 24.3 from Chvatal + if (precise()) return; + unsigned i = m_dim; + while (i--) { + if (is_zero(y[i])) continue; + if (m_settings.abs_val_is_smaller_than_drop_tolerance(y[i])){ + y[i] = zero_of_type(); + } + } + } + + + void print_indexed_vector(indexed_vector & w, std::ofstream & f) { + f << "vector_start" << endl; + for (unsigned j : w.m_index) { + f << j << " " << w[j] << endl; + } + f << "vector_end" << endl; + } + void print_basis(std::ofstream & f) { + f << "basis_start" << endl; + for (unsigned j : m_basis) + f << j << endl; + f << "basis_end" << endl; + } + void print_matrix_compact(std::ofstream & f) { + f << "matrix_start" << endl; + f << "nrows " << m_A.row_count() << endl; + f << "ncolumns " << m_A.column_count() << endl; + for (unsigned i = 0; i < m_A.row_count(); i++) { + auto & row = m_A.m_rows[i]; + f << "row " << i << endl; + for (auto & t : row.m_cells) { + f << "column " << t.m_j << " value " << t.m_value << endl; + } + f << "row_end" << endl; + } + f << "matrix_end" << endl; + } + + void print(indexed_vector & w) { + string dump_file_name("/tmp/lu"); + remove(dump_file_name.c_str()); + std::ofstream f(dump_file_name); + if (!f.is_open()) { + cout << "cannot open file " << dump_file_name << endl; + return; + } + cout << "writing lu dump to " << dump_file_name << endl; + print_matrix_compact(f); + print_basis(f); + print_indexed_vector(w, f); + f.close(); + } + + void solve_Bd(unsigned a_column, std::vector & d, indexed_vector & w) { + init_vector_w(a_column, w); + solve_Bd_when_w_is_ready(d, w); + } + + bool column_can_be_taken_to_basis(unsigned i) { + return m_basis_heading[i] < 0; + } + + void solve_yB_internal(vector& y) { + // first solve yU = cb*R(-1) + m_R.apply_reverse_from_right(y); // got y = cb*R(-1) + m_U.solve_y_U(y); // got y*U=cb*R(-1) + m_Q.apply_reverse_from_right(y); // + for (auto e = m_tail.rbegin(); e != m_tail.rend(); ++e) { +#ifndef NDEBUG + (*e)->set_number_of_columns(m_dim); +#endif + (*e)->apply_from_right(y); + } + } + + void add_delta_to_solution(vector& yc, vector& y){ + unsigned i = y.size(); + while (i--) + y[i]+=yc[i]; + } + + void find_error_of_yB(vector& yc, const vector& y) { + unsigned i = m_dim; + while (i--) { + yc[i] -= m_A.dot_product_with_column(y, m_basis[i]); + } + } + + // solves y*B = y + // y is the input + + void solve_yB(vector & y) { + vector yc(y); // copy y aside + solve_yB_internal(y); + find_error_of_yB(yc, y); + solve_yB_internal(yc); + add_delta_to_solution(yc, y); + } + + void apply_Q_R_to_U(permutation_matrix & r_wave) { + m_U.multiply_from_right(r_wave); + m_U.multiply_from_left_with_reverse(r_wave); + } + + void change_basis(unsigned entering, unsigned leaving) { + lean_assert(entering < m_A.column_count() && leaving < m_A.column_count()); + int place_in_basis = m_basis_heading[leaving]; + int place_in_non_basis = - m_basis_heading[entering] - 1; + lean_assert(0 <= place_in_basis && place_in_basis < m_A.column_count()); + m_basis_heading[entering] = place_in_basis; + m_basis_heading[leaving] = -place_in_non_basis - 1; + m_basis[place_in_basis] = entering; + m_non_basic_columns[place_in_non_basis] = leaving; + } + + void restore_basis_change(unsigned entering, unsigned leaving) { + if (m_basis_heading[entering] < 0) { + return; // the basis has not been changed + } + change_basis(leaving, entering); + } + + LU_status get_status() { return m_status; } + + void set_status(LU_status status) { m_status = status; } + + // Solving yB = cb to find the entering variable, + // where cb is the cost vector projected to B. + // The result is stored in cb. + + // solving Bd = a ( to find the column d of B^{-1} A_N corresponding to the entering + // variable + + ~lu(){ + for (auto t : m_tail) { + delete t; + } + } + + T B(unsigned i, unsigned j) { + return m_A(i, m_basis[j]); + } + + void init_vector_y(vector & y) { + apply_lp_lists_to_y(y); + m_Q.apply_reverse_from_left(y); + } + + + void perform_transformations_on_w(indexed_vector& w) { + apply_lp_lists_to_w(w); + m_Q.apply_reverse_from_left(w); + lean_assert(numeric_traits::precise() || check_vector_for_small_values(w, m_settings)); + } + + // see Chvatal 24.3 + void init_vector_w(unsigned entering, indexed_vector & w) { + w.clear(); + m_A.copy_column_to_vector(entering, w); // w = a, the column + perform_transformations_on_w(w); + } + + void apply_lp_lists_to_w(indexed_vector & w) { + for (unsigned i = 0; i < m_tail.size(); i++) { + m_tail[i]->apply_from_left_to_T(w, m_settings); + lean_assert(check_vector_for_small_values(w, m_settings)); + } + } + + void apply_lp_lists_to_y(vector& y) { + for (unsigned i = 0; i < m_tail.size(); i++) { + m_tail[i]->apply_from_left(y, m_settings); + } + } + + void swap_rows(int j, int k) { + if (j != k) { + m_Q.transpose_from_left(j, k); + m_U.swap_rows(j, k); + } + } + + void swap_columns(int j, int pivot_column) { + if (j == pivot_column) + return; + m_R.transpose_from_right(j, pivot_column); + m_U.swap_columns(j, pivot_column); + } + + void push_matrix_to_tail(tail_matrix* tm) { + m_tail.push_back(tm); + } + + bool pivot_the_row(int row) { + eta_matrix * eta_matrix = get_eta_matrix_for_pivot(row); + if (eta_matrix == nullptr) { + m_U.shorten_active_matrix(row, nullptr); + return true; + } + if (!m_U.pivot_with_eta(row, eta_matrix, m_settings)) + return false; + eta_matrix->conjugate_by_permutation(m_Q); + push_matrix_to_tail(eta_matrix); + return true; + } + // we're processing the column j now + eta_matrix * get_eta_matrix_for_pivot(unsigned j) { + eta_matrix *ret; + m_U.fill_eta_matrix(j, &ret); + return ret; + } + // we're processing the column j now + eta_matrix * get_eta_matrix_for_pivot(unsigned j, sparse_matrix& copy_of_U) { + eta_matrix *ret; + copy_of_U.fill_eta_matrix(j, &ret); + return ret; + } + + void print_basis() { + std::cout << "basis "; + for (unsigned i = 0; i < m_dim; i++) { + std::cout << m_basis[i] << " "; + } + std::cout << std::endl; + } + + void print_basis_heading() { + print_basis(); + for (unsigned i = 0; i < m_A.column_count(); i++) { + std::cout << m_basis_heading[i] << ","; + } + std::cout << std::endl; + } + + // see page 407 of Chvatal + unsigned transform_U_to_V_by_replacing_column(unsigned leaving, indexed_vector & w) { + int leaving_column = m_basis_heading[leaving]; + // std::cout << "leaving_column = " << leaving_column << std::endl; + unsigned column_to_replace = m_R.apply_reverse(leaving_column); + // std::cout << "leaving_column modified = " << column_to_replace << std::endl; + m_U.replace_column(column_to_replace, w, m_settings); + return column_to_replace; + } + +#ifndef NDEBUG + void check_vector_w(unsigned entering) { + T * w = new T[m_dim]; + m_A.copy_column_to_vector(entering, w); + check_apply_lp_lists_to_w(w); + delete [] w; + } + + void check_apply_matrix_to_vector(matrix *lp, T *w) { + if (lp != nullptr) { + lp -> set_number_of_rows(m_dim); + lp -> set_number_of_columns(m_dim); + apply_to_vector(*lp, w); + } + } + + void check_apply_lp_lists_to_w(T * w) { + for (unsigned i = 0; i < m_tail.size(); i++) { + check_apply_matrix_to_vector(m_tail[i], w); + } + permutation_matrix qr = m_Q.get_reverse(); + apply_to_vector(qr, w); + for (int i = m_dim - 1; i >= 0; i--) { + lean_assert(abs(w[i] - w[i]) < 0.0000001); + } + } + + // provide some access operators for testing + permutation_matrix & Q() { return m_Q; } + permutation_matrix & R() { return m_R; } + matrix & U() { return m_U; } + unsigned tail_size() { return m_tail.size(); } + + tail_matrix * get_lp_matrix(unsigned i) { + return m_tail[i]; + } + + T B_(unsigned i, unsigned j) { + return m_A.get_elem(i, m_basis[j]); + } + + unsigned dimension() { return m_dim; } + +#endif + + void mark_fixed_variable(unsigned column) { + m_basis_heading[column] = -2; + } + + unsigned get_number_of_nonzeroes() { + return m_U.get_number_of_nonzeroes(); + } + + + void process_column(int j) { + unsigned pi, pj; + m_U.get_pivot_for_column(pi, pj, T(m_settings.c_partial_pivoting), j); + if (pi == -1) { + cout << "cannot find the pivot for column " << j << endl; + m_failure = true; + return; + } + swap_columns(j, pj); + swap_rows(j, pi); + if (!pivot_the_row(j)) { + cout << "pivot_the_row(" << j << ") failed" << endl; + m_failure = true; + } + } + + bool is_correct() { +#ifndef NDEBUG + if (get_status() != LU_status::OK) { + return false; + } + dense_matrix left_side = get_left_side(); + dense_matrix right_side = get_right_side(); + return left_side == right_side; +#else + return true; +#endif + } + + int basis_heading(unsigned j) { + lean_assert(j < m_A.column_count()); + return m_basis_heading[j]; + } + +#ifndef NDEBUG + dense_matrix tail_product() { + lean_assert(tail_size() > 0); + dense_matrix left_side = permutation_matrix(m_dim); + for (unsigned i = 0; i < tail_size(); i++) { + matrix* lp = get_lp_matrix(i); + lp->set_number_of_rows(m_dim); + lp->set_number_of_columns(m_dim); + left_side = ((*lp) * left_side); + } + return left_side; + } + dense_matrix get_left_side() { + dense_matrix left_side = get_B(*this); + for (unsigned i = 0; i < tail_size(); i++) { + matrix* lp = get_lp_matrix(i); + lp->set_number_of_rows(m_dim); + lp->set_number_of_columns(m_dim); + left_side = ((*lp) * left_side); + } + return left_side; + } + + dense_matrix get_right_side() { + auto ret = U() * R(); + ret = Q() * ret; + return ret; + } +#endif + + // needed for debugging purposes + void copy_w(T *buffer, indexed_vector & w) { + unsigned i = m_dim; + while (i--) { + buffer[i] = w[i]; + } + } + + // needed for debugging purposes + void restore_w(T *buffer, indexed_vector & w) { + unsigned i = m_dim; + while (i--) { + w[i] = buffer[i]; + } + } + bool all_columns_and_rows_are_active() { + unsigned i = m_dim; + while (i--) { + lean_assert(m_U.col_is_active(i)); + lean_assert(m_U.row_is_active(i)); + } + return true; + } + + bool too_dense(unsigned j) const { + unsigned r = m_dim - j; + if (r < 5) + return false; + return r * r * m_settings.density_threshold <= m_U.get_number_of_nonzeroes_below_row(j); + } + + void pivot_in_dense_mode(unsigned i) { + int j = m_dense_LU->find_pivot_column_in_row(i); + if (j == -1) { + m_failure = true; + return; + } + if (i != j) { + swap_columns(i, j); + m_dense_LU->swap_columns(i, j); + } + m_dense_LU->pivot(i, m_settings); + } + + void create_initial_factorization(){ + m_U.prepare_for_factorization(); + unsigned j; + for (j = 0; j < m_dim; j++) { + process_column(j); + if (m_failure || too_dense(j + 1)) { + break; + } + } + if (m_failure) { + set_status(LU_status::Degenerated); + return; + } + if (j == m_dim) { + lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + return; + } + j++; + // cout << "switching to dense factoring for " << j << endl; + m_dense_LU = new square_dense_submatrix(&m_U, j); + for (; j < m_dim; j++) { + pivot_in_dense_mode(j); + if (m_failure) { + set_status(LU_status::Degenerated); + return; + } + } + m_dense_LU->update_parent_matrix(m_settings); + lean_assert(m_dense_LU->is_L_matrix()); + m_dense_LU->conjugate_by_permutation(m_Q); + push_matrix_to_tail(m_dense_LU); + // lean_assert(is_correct()); + // lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + } + + void calculate_r_wave_and_update_U(unsigned bump_start, unsigned bump_end, permutation_matrix & r_wave) { + lean_assert(bump_start <= bump_end); + if (bump_start == bump_end) { + return; + } + + r_wave[bump_start] = bump_end; // sending the offensive column to the end of the bump + + for ( unsigned i = bump_start + 1 ; i <= bump_end; i++ ) { + r_wave[i] = i - 1; + } + + m_U.multiply_from_right(r_wave); + m_U.multiply_from_left_with_reverse(r_wave); + } + + void scan_last_row_to_work_vector(unsigned lowest_row_of_the_bump) { + vector> & last_row_vec = m_U.get_row_values(m_U.adjust_row(lowest_row_of_the_bump)); + for (auto & iv : last_row_vec) { + if (is_zero(iv.m_value)) continue; + lean_assert(!m_settings.abs_val_is_smaller_than_drop_tolerance(iv.m_value)); + unsigned adjusted_col = m_U.adjust_column_inverse(iv.m_index); + if (adjusted_col < lowest_row_of_the_bump) { + m_row_eta_work_vector.set_value(-iv.m_value, adjusted_col); + } else { + m_row_eta_work_vector.set_value(iv.m_value, adjusted_col); // preparing to calculate the real value in the matrix + } + } + } + + bool diagonal_element_is_off(T diag_element) { + return false; + } + + void pivot_and_solve_the_system(unsigned replaced_column, unsigned lowest_row_of_the_bump) { + // we have the system right side at m_row_eta_work_vector now + // solve the system column wise + for (unsigned j = replaced_column; j < lowest_row_of_the_bump; j++) { + T v = m_row_eta_work_vector[j]; + if (numeric_traits::is_zero(v)) continue; // this column does not contribute to the solution + unsigned aj = m_U.adjust_row(j); + vector> & row = m_U.get_row_values(aj); + for (auto & iv : row) { + unsigned col = m_U.adjust_column_inverse(iv.m_index); + lean_assert(col >= j || numeric_traits::is_zero(iv.m_value)); + if (col == j) continue; + if (numeric_traits::is_zero(iv.m_value)) { + continue; + } + // the -v is for solving the system ( to zero the last row), and +v is for pivoting + T delta = col < lowest_row_of_the_bump? -v * iv.m_value: v * iv.m_value; + lean_assert(numeric_traits::is_zero(delta) == false); + + if (numeric_traits::is_zero(m_row_eta_work_vector[col])) { + if (!m_settings.abs_val_is_smaller_than_drop_tolerance(delta)){ + m_row_eta_work_vector.set_value(delta, col); + } + } else { + T t = (m_row_eta_work_vector[col] += delta); + if (m_settings.abs_val_is_smaller_than_drop_tolerance(t)){ + m_row_eta_work_vector[col] = numeric_traits::zero(); + auto it = std::find(m_row_eta_work_vector.m_index.begin(), m_row_eta_work_vector.m_index.end(), col); + if (it != m_row_eta_work_vector.m_index.end()) + m_row_eta_work_vector.m_index.erase(it); + } + } + } + } + lean_assert(m_row_eta_work_vector.is_OK()); + } + // see Achim Koberstein's thesis page 58, but here we solve the system and pivot to the last + // row at the same time + row_eta_matrix *get_row_eta_matrix_and_set_row_vector(unsigned replaced_column, unsigned lowest_row_of_the_bump, const T & pivot_elem_for_checking) { + if (replaced_column == lowest_row_of_the_bump) return nullptr; + scan_last_row_to_work_vector(lowest_row_of_the_bump); + pivot_and_solve_the_system(replaced_column, lowest_row_of_the_bump); + T denom = std::max(T(1), abs(pivot_elem_for_checking)); + if ( +#ifndef NDEBUG + !is_zero(pivot_elem_for_checking) && +#endif + !m_settings.abs_val_is_smaller_than_pivot_tolerance((m_row_eta_work_vector[lowest_row_of_the_bump] - pivot_elem_for_checking) / denom)) { + // cout << "m_row_eta_work_vector[" << lowest_row_of_the_bump << "] = " << T_to_string(m_row_eta_work_vector[lowest_row_of_the_bump]) << ", but pivot = " << T_to_string(pivot_elem_for_checking) << endl; + set_status(LU_status::Degenerated); + // cout << "diagonal element is off" << endl; + return nullptr; + } +#ifndef NDEBUG + auto ret = new row_eta_matrix(replaced_column, lowest_row_of_the_bump, m_dim); +#else + auto ret = new row_eta_matrix(replaced_column, lowest_row_of_the_bump); +#endif + + for (auto j : m_row_eta_work_vector.m_index) { + if (j < lowest_row_of_the_bump) { + auto & v = m_row_eta_work_vector[j]; + if (!is_zero(v)) { + if (!m_settings.abs_val_is_smaller_than_drop_tolerance(v)){ + ret->push_back(j, v); + } + v = numeric_traits::zero(); + } + } + } // now the lowest_row_of_the_bump contains the rest of the row to the right of the bump with correct values + return ret; + } + + // This method does not update the basis: is_correct() should not be called since it works with the basis. + void replace_column(unsigned leaving, T pivot_elem, indexed_vector & w){ + lean_assert(m_basis_heading[leaving] >= 0); + unsigned replaced_column = transform_U_to_V_by_replacing_column(leaving, w); + unsigned lowest_row_of_the_bump = m_U.lowest_row_in_column(replaced_column); + permutation_matrix r_wave(m_dim); + calculate_r_wave_and_update_U(replaced_column, lowest_row_of_the_bump, r_wave); + auto row_eta = get_row_eta_matrix_and_set_row_vector(replaced_column, lowest_row_of_the_bump, pivot_elem); + if (get_status() == LU_status::Degenerated) { + m_row_eta_work_vector.clear_all(); + return; + } + m_Q.multiply_by_permutation_from_right(r_wave); + m_R.multiply_by_permutation_reverse_from_left(r_wave); + if (row_eta != nullptr) { + row_eta->conjugate_by_permutation(m_Q); + push_matrix_to_tail(row_eta); + } + calculate_Lwave_Pwave_for_bump(replaced_column, lowest_row_of_the_bump); + lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + lean_assert(w.is_OK() && m_row_eta_work_vector.is_OK()); + } + + void calculate_Lwave_Pwave_for_bump(unsigned replaced_column, unsigned lowest_row_of_the_bump){ + T diagonal_elem; + if (replaced_column < lowest_row_of_the_bump) { + diagonal_elem = m_row_eta_work_vector[lowest_row_of_the_bump]; + // lean_assert(m_row_eta_work_vector.is_OK()); + m_U.set_row_from_work_vector_and_clean_work_vector_not_adjusted(m_U.adjust_row(lowest_row_of_the_bump), m_row_eta_work_vector, m_settings); + } else { + diagonal_elem = m_U(lowest_row_of_the_bump, lowest_row_of_the_bump); // todo - get it more efficiently + } + if (m_settings.abs_val_is_smaller_than_pivot_tolerance(diagonal_elem)) { + set_status(LU_status::Degenerated); + return; + } + + calculate_Lwave_Pwave_for_last_row(lowest_row_of_the_bump, diagonal_elem); + // lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + } + + void calculate_Lwave_Pwave_for_last_row(unsigned lowest_row_of_the_bump, T diagonal_element) { + auto l = new one_elem_on_diag(lowest_row_of_the_bump, diagonal_element); +#ifndef NDEBUG + l->set_number_of_columns(m_dim); +#endif + push_matrix_to_tail(l); + m_U.divide_row_by_constant(lowest_row_of_the_bump, diagonal_element, m_settings); + l->conjugate_by_permutation(m_Q); + } + + void prepare_entering(unsigned entering, indexed_vector & w) { + init_vector_w(entering, w); + } +}; // end of lu +template +void init_factorization(lu* & factorization, static_matrix & m_A, std::vector & m_basis, vector & m_basis_heading, lp_settings &m_settings, vector & non_basic_columns) { + if (factorization != nullptr) { + delete factorization; + } + factorization = new lu(m_A, m_basis, m_basis_heading, m_settings, non_basic_columns); + if (factorization->get_status() != LU_status::OK) { + cout << "failing in init_factorization" << endl; + return; + } +} + +#ifndef NDEBUG +template +dense_matrix get_B(lu& f) { + dense_matrix B(f.dimension(), f.dimension()); + for (unsigned i = 0; i < f.dimension(); i++) + for (unsigned j = 0; j < f.dimension(); j++) + B.set_elem(i, j, f.B_(i, j)); + + return B; +} +#endif +} diff --git a/src/util/lp/matrix_domain.h b/src/util/lp/matrix_domain.h new file mode 100644 index 0000000000..5f04041e43 --- /dev/null +++ b/src/util/lp/matrix_domain.h @@ -0,0 +1,78 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/numerics/numeric_traits.h" +#include "util/numerics/xnumeral.h" +#include "util/numerics/mpq.h" +#include "util/numerics/mpz.h" +#include "util/numerics/mpbq.h" +#include "util/numerics/double.h" +#include "util/numerics/float.h" +#include "util/numerics/mpfp.h" +#include +#include + +template +inline void hash_combine(std::size_t & seed, const T & v) { + std::hash hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} + +namespace std { +template struct hash> { + inline size_t operator()(const pair & v) const { + size_t seed = 0; + ::hash_combine(seed, v.first); + ::hash_combine(seed, v.second); + return seed; + } +}; +} + +namespace lean { +using std::unordered_map; + +template +class matrix_domain { + vector> m_domain; +public: + matrix_domain(unsigned rows) { + while (rows--) { + unordered_map t; + m_domain.push_back(t); + } + } + void * find(unsigned i, unsigned j) const { + auto & v = m_domain[i]; + auto t = v.find(j); + if (t == v.end()) { + return nullptr; + } + return t->second; + } + + void erase(unsigned i, unsigned j) { + lean_assert(find(i, j) != nullptr); + m_domain[i].erase(j); + } + + void insert(unsigned i, unsigned j, void * cell) { + lean_assert(m_domain[i].find(j) == m_domain[i].end()); + m_domain[i][j] = cell; + } + + unsigned size() const { + unsigned ret = 0; + for (auto & t : m_domain) { + ret += t.size(); + } + return ret; + } +}; +} diff --git a/src/util/lp/numeric_pair.h b/src/util/lp/numeric_pair.h new file mode 100644 index 0000000000..9eb0ad5b4c --- /dev/null +++ b/src/util/lp/numeric_pair.h @@ -0,0 +1,239 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include +#include "util/numerics/mpq.h" +#include "util/numerics/double.h" + +namespace lean { + template + std::string T_to_string(const T & t); // forward definition + + template + struct convert_struct { + static X convert(const Y & y){ return X(y);} + static bool is_epsilon_small(const X & x, const double & y) { return abs(get_double(x)) < y; } + static bool below_bound_numeric(const X &, const X &, const Y &) { throw "don't call";} + static bool above_bound_numeric(const X &, const X &, const Y &) { throw "don't call";} + }; + + + template <> + struct convert_struct { + static double convert(const mpq & q) {return q.get_double();} + }; + + template + struct numeric_pair { + T x; + T y; + // empty constructor + numeric_pair() {} + // another constructor + + numeric_pair(T xp, T yp) : x(xp), y(yp) {} + template numeric_pair(X xp, Y yp) : numeric_pair(convert_struct::convert(xp), convert_struct::convert(yp)) {} + + bool operator<(const numeric_pair& a) const { + return x < a.x || (x == a.x && y < a.y); + } + + bool operator>(const numeric_pair& a) const { + return x > a.x || (x == a.x && y > a.y); + } + + bool operator==(const numeric_pair& a) const { + return a.x == x && a.y == y; + } + + bool operator!=(const numeric_pair& a) const { + return !(*this == a); + } + + bool operator<=(const numeric_pair& a) const { + return *this < a || *this == a; + } + + bool operator>=(const numeric_pair& a) const { + return *this > a || a == *this; + } + + numeric_pair operator*(const T & a) const { + return numeric_pair(a * x, a * y); + } + + numeric_pair operator/(const T & a) const { + T a_as_T(a); + return numeric_pair(x / a_as_T, y / a_as_T); + } + + numeric_pair operator/(const numeric_pair &) const { + throw "should not be called"; + } + + + numeric_pair operator+(const numeric_pair & a) const { + return numeric_pair(a.x + x, a.y + y); + } + + numeric_pair operator*(const numeric_pair & /*a*/) const { + throw "should not be called"; + } + + + numeric_pair& operator+=(const numeric_pair & a) { + x += a.x; + y += a.y; + return *this; + } + + numeric_pair& operator-=(const numeric_pair & a) { + x -= a.x; + y -= a.y; + return *this; + } + + numeric_pair& operator/=(const T & a) { + x /= a; + y /= a; + return *this; + } + + numeric_pair& operator*=(const T & a) { + x *= a; + y *= a; + return *this; + } + + numeric_pair operator-(const numeric_pair & a) const { + return numeric_pair(x - a.x, y - a.y); + } + + numeric_pair operator-() const { + return numeric_pair(-x, -y); + } + + static bool precize() { return numeric_traits::precize();} + + std::string to_string() const { return std::string("(") + T_to_string(x) + ", " + T_to_string(y) + ")"; } + }; + + + template + std::ostream& operator<<(std::ostream& os, numeric_pair const & obj) { + os << obj.to_string(); + return os; + } + + template + numeric_pair operator*(const X & a, const numeric_pair & r) { + return numeric_pair(a * r.x, a * r.y); + } + + template + numeric_pair operator*(const numeric_pair & r, const X & a) { + return numeric_pair(a * r.x, a * r.y); + } + + + + + // template bool precise() { return numeric_traits::precise();} + template double get_double(const numeric_pair & ) { throw "do not call"; } + template + class numeric_traits> { + public: + static bool precise() { return numeric_traits::precise();} + static numeric_pair zero() { return numeric_pair(numeric_traits::zero(), numeric_traits::zero()); } + static bool is_zero(const numeric_pair & v) { return numeric_traits::is_zero(v.x) && numeric_traits::is_zero(v.y); } + static double get_double(const numeric_pair & v){ return numeric_traits::get_double(v.x); } // just return the double of the first coordinate + static double one() { throw "do not call"; } + }; + template <> + struct convert_struct> { + static double convert(const numeric_pair & q) {return q.x;} + }; + + template bool is_epsilon_small(const X & v, const double& eps); // forward definition { return convert_struct::is_epsilon_small(v, eps);} + + template + struct convert_struct, double> { + static numeric_pair convert(const double & q) { + return numeric_pair(convert_struct::convert(q), zero_of_type()); + } + static bool is_epsilon_small(const numeric_pair & p, const double & eps) { + return convert_struct::is_epsilon_small(p.x, eps) && convert_struct::is_epsilon_small(p.y, eps); + } + static bool below_bound_numeric(const numeric_pair &, const numeric_pair &, const double &) { + throw "do not call"; + } + static bool above_bound_numeric(const numeric_pair &, const numeric_pair &, const double &) { + throw "do not call"; + } + }; + + template <> + struct convert_struct, double> { + static numeric_pair convert(const double & q) { + return numeric_pair(q, 0.0); + } + static bool is_epsilon_small(const numeric_pair & p, const double & eps) { + return std::abs(p.x) < eps && std::abs(p.y) < eps; + } + + static int compare_on_coord(const double & x, const double & bound, const double eps) { + lean_assert(eps > 0); + if (bound == 0) return (x < - eps)? -1: (x > eps? 1 : 0); // it is an important special case + double relative = (bound > 0)? - eps: eps; + return (x < bound * (1.0 + relative) - eps)? -1 : ((x > bound * (1.0 - relative) + eps)? 1 : 0); + } + + static bool below_bound_numeric(const numeric_pair & x, const numeric_pair & bound, const double & eps) { + int r = compare_on_coord(x.x, bound.x, eps); + if (r == 1) return false; + if (r == -1) return true; + // the first coordinates are almost the same + lean_assert(r == 0); + return compare_on_coord(x.y, bound.y, eps) == -1; + } + + static bool above_bound_numeric(const numeric_pair & x, const numeric_pair & bound, const double & eps) { + int r = compare_on_coord(x.x, bound.x, eps); + if (r == -1) return false; + if (r == 1) return true; + // the first coordinates are almost the same + lean_assert(r == 0); + return compare_on_coord(x.y, bound.y, eps) == 1; + } + }; + + template <> + struct convert_struct { + static bool is_epsilon_small(const double& x, const double & eps) { + return x < eps && x > -eps; + } + static double convert(const double & y){ return y;} + static bool below_bound_numeric(const double & x, const double & bound, const double & eps) { + lean_assert(eps > 0); + if (bound == 0) return x < - eps; + double relative = (bound > 0)? - eps: eps; + return x < bound * (1.0 + relative) - eps; + } + static bool above_bound_numeric(const double & x, const double & bound, const double & eps) { + lean_assert(eps > 0); + if (bound == 0) return x > eps; + double relative = (bound > 0)? eps: - eps; + return x > bound * (1.0 + relative) + eps; + } + }; + + template bool is_epsilon_small(const X & v, const double &eps) { return convert_struct::is_epsilon_small(v, eps);} + template bool below_bound_numeric(const X & x, const X & bound, const double& eps) { return convert_struct::below_bound_numeric(x, bound, eps);} + template bool above_bound_numeric(const X & x, const X & bound, const double& eps) { return convert_struct::above_bound_numeric(x, bound, eps);} +} diff --git a/src/util/lp/permutation_matrix.h b/src/util/lp/permutation_matrix.h new file mode 100644 index 0000000000..2f4e6a1647 --- /dev/null +++ b/src/util/lp/permutation_matrix.h @@ -0,0 +1,1238 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/debug.h" +#include "util/numerics/numeric_traits.h" +#include "util/numerics/xnumeral.h" +#include "util/numerics/mpq.h" +#include "util/numerics/mpz.h" +#include "util/numerics/mpbq.h" +#include "util/numerics/double.h" +#include "util/numerics/float.h" +#include "util/numerics/mpfp.h" +#include +#include "util/lp/sparse_vector.h" +#include "util/lp/indexed_vector.h" +#include "util/lp/lp_settings.h" +#include +namespace lean { + using std::string; + using std::endl; + + template + string T_to_string(const T & t) { + // return is_zero(t)?string(" "):string("."); + std::ostringstream strs; + strs << t; + std::string str = strs.str(); + return str; + } + + template <> + string T_to_string(const int & t) { + std::ostringstream strs; + strs << t; + std::string str = strs.str(); + return str; + } + template <> + string T_to_string(const unsigned & t) { + std::ostringstream strs; + strs << t; + std::string str = strs.str(); + return str; + } + + + string T_to_string(const mpq & t) { + std::ostringstream strs; + strs << t.get_double(); + std::string str = strs.str(); + return str; + } + + template + bool val_is_smaller_than_eps(T const & t, double const & eps) { + if (!numeric_traits::precise()) { + return numeric_traits::get_double(t) < eps; + } + return t <= numeric_traits::zero(); + } + + + inline bool is_even(int k) { + return (k/2)*2 == k; + } + + template + bool vectors_are_equal(T * a, T *b, unsigned n) { + double sum = 0; + double max = 0; + if (numeric_traits::precise()) { + for (unsigned i = 0; i < n; i ++){ + if (!numeric_traits::is_zero(a[i] - b[i])) { + std::cout << "a[" << i <<"]" << a[i] << ", " << "b[" << i <<"]" << b[i] << std::endl; + return false; + } + } + } else { + for (unsigned i = 0; i < n; i ++){ + double t = fabs(numeric_traits::get_double(a[i] - b[i])); + if (t > 0.000001) { + std::cout << "a[" << i <<"]" << a[i] << ", " << "b[" << i <<"]" << b[i] << std::endl; + return false; + } + if (t > max) { + max = t; + } + sum += t; + } + } + if (sum > 0.00001) { + return false; + } + // cout << "vectors_are_equal :" << "sum = " << sum << ", max = " << max << endl; + return true; + } + + template + bool vectors_are_equal(T * a, std::vector &b, unsigned n) { + if (numeric_traits::precise()) { + for (unsigned i = 0; i < n; i ++){ + if (!numeric_traits::is_zero(a[i] - b[i])) { + std::cout << "a[" << i <<"]" << a[i] << ", " << "b[" << i <<"]" << b[i] << std::endl; + return false; + } + } + } else { + for (unsigned i = 0; i < n; i ++){ + if (fabs(numeric_traits::get_double(a[i] - b[i])) > 0.000001) { + std::cout << "a[" << i <<"]" << a[i] << ", " << "b[" << i <<"]" << b[i] << std::endl; + return false; + } + } + } + return true; + } + + template + bool vectors_are_equal(const std::vector & a, const buffer &b) { + unsigned n = a.size(); + if (n != b.size()) return false; + if (numeric_traits::precise()) { + for (unsigned i = 0; i < n; i ++){ + if (!numeric_traits::is_zero(a[i] - b[i])) { + std::cout << "a[" << i <<"]" << a[i] << ", " << "b[" << i <<"]" << b[i] << std::endl; + return false; + } + } + } else { + for (unsigned i = 0; i < n; i ++){ + if (fabs(numeric_traits::get_double(a[i] - b[i])) > 0.000001) { + std::cout << "a[" << i <<"] = " << a[i] << ", but " << "b[" << i <<"] = " << b[i] << std::endl; + return false; + } + } + } + return true; + } + template + bool vectors_are_equal(const std::vector & a, const std::vector &b) { + unsigned n = a.size(); + if (n != b.size()) return false; + if (numeric_traits::precise()) { + for (unsigned i = 0; i < n; i ++){ + if (!numeric_traits::is_zero(a[i] - b[i])) { + std::cout << "a[" << i <<"]" << a[i] << ", " << "b[" << i <<"]" << b[i] << std::endl; + return false; + } + } + } else { + for (unsigned i = 0; i < n; i ++){ + if (fabs(numeric_traits::get_double(a[i] - b[i])) > 0.000001) { + std::cout << "a[" << i <<"] = " << a[i] << ", but " << "b[" << i <<"] = " << b[i] << std::endl; + return false; + } + } + } + return true; + } + + template + X max_abs_in_vector(vector& t){ + X r(zero_of_type()); + for (auto & v : t) + r = std::max(abs(v) , r); + return r; + } + + template + X min_abs_in_vector(vector& t){ + X r(zero_of_type()); + for (auto & v : t) { + if (is_zero(v)) continue; + if (is_zero(r)) { + r = abs(v); + } else { + r = std::min(abs(v) , r); + } + } + return r; + } + +#ifndef NDEBUG + // used for debugging purposes only + template + class matrix { + public: + virtual T get_elem (unsigned i, unsigned j) const = 0; + virtual unsigned row_count() const = 0; + virtual unsigned column_count() const = 0; + virtual void set_number_of_rows(unsigned m) = 0; + virtual void set_number_of_columns(unsigned n) = 0; + + virtual ~matrix() {} + + bool is_equal(const matrix& other) { + if (other.row_count() != row_count() || other.column_count() != column_count()) + return false; + lp_settings settings; + for (unsigned i = 0; i < row_count(); i++) { + for (unsigned j = 0; j < column_count(); j++) { + auto a = get_elem(i, j); + auto b = other.get_elem(i, j); + if (numeric_traits::precise()) { + if (a != b) return false; + } else if (fabs(numeric_traits::get_double(a - b)) > 0.000001) { + // cout << "returning false from operator== of matrix comparison" << endl; + // cout << "this matrix is " << endl; + // print_matrix(*this); + // cout << "other matrix is " << endl; + // print_matrix(other); + return false; + } + } + } + return true; + } + bool operator == (matrix const & other) { + return is_equal(other); + } + T operator()(unsigned i, unsigned j) const { return get_elem(i, j); } + }; +#endif + + // These matrices appear at the end of the list + template + class tail_matrix +#ifndef NDEBUG + : public matrix +#endif + { + public: + virtual void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) = 0; + virtual void apply_from_left(vector & w, lp_settings & settings) = 0; + virtual void apply_from_right(vector & w) = 0; + virtual ~tail_matrix() {} + }; + +#ifndef NDEBUG + template + void apply_to_vector(matrix & m, T * w) { + // here m is a square matrix + unsigned dim = m.row_count(); + + T * wc = new T[dim]; + + for (unsigned i = 0; i < dim; i++) { + wc[i] = w[i]; + } + + for (unsigned i = 0; i < dim; i++) { + T t = numeric_traits::zero(); + for (unsigned j = 0; j < dim; j++) { + t += m(i, j) * wc[j]; + } + w[i] = t; + } + delete [] wc; + } + + + // used for debugging purposes only + template + class dense_matrix: public matrix { + public: + struct ref { + unsigned m_i; + dense_matrix & m_s; + ref(unsigned i, dense_matrix & s) :m_i(i * s.m_n), m_s(s){} + T & operator[] (unsigned j) { + return m_s.m_values[m_i + j]; + } + const T & operator[] (unsigned j) const { + return m_s.m_v[m_i + j]; + } + }; + ref operator[] (unsigned i) { + return ref(i, *this); + } + unsigned m_m; // number of rows + unsigned m_n; // number of const + T* m_values;// + dense_matrix(unsigned m, unsigned n) : m_m(m), m_n(n) { + m_values = new T[m * n]; + for (unsigned i = 0; i < m * n; i ++) + m_values[i] = numeric_traits::zero(); + } + + dense_matrix operator*=(matrix const & a){ + lean_assert(column_count() == a.row_count()); + dense_matrix c(row_count(), a.column_count()); + for (unsigned i = 0; i < row_count(); i++) { + for (unsigned j = 0; j < a.column_count(); j++) { + T v = numeric_traits::zero(); + for (unsigned k = 0; k < a.column_count(); k++) { + v += get_elem(i, k) * a(k, j); + } + c.set_elem(i, j, v); + } + } + *this = c; + return *this; + } + + dense_matrix & operator=(matrix const & other){ + if ( this == & other) + return *this; + m_values = new T[m_m * m_n]; + for (unsigned i = 0; i < m_m; i ++) + for (unsigned j = 0; j < m_n; j++) + m_values[i * m_n + j] = other.get_elem(i, j); + return *this; + } + + dense_matrix & operator=(dense_matrix const & other){ + if ( this == & other) + return *this; + m_m = other.m_m; + m_n = other.m_n; + delete [] m_values; + m_values = new T[m_m * m_n]; + for (unsigned i = 0; i < m_m; i ++) + for (unsigned j = 0; j < m_n; j++) + m_values[i * m_n + j] = other.get_elem(i, j); + return *this; + } + + dense_matrix(dense_matrix const & other) : m_m(other.row_count()), m_n(other.column_count()) { + m_values = new T[m_m * m_n]; + for (unsigned i = 0; i < m_m; i ++) + for (unsigned j = 0; j < m_n; j++) + m_values[i * m_n + j] = other.get_elem(i, j); + } + + dense_matrix(matrix const & other) : + m_m(other.row_count()), + m_n(other.column_count()) { + m_values = new T[m_m * m_n]; + for (unsigned i = 0; i < m_m; i++) + for (unsigned j = 0; j < m_n; j++) + m_values[i * m_n + j] = other.get_elem(i, j); + } + + void apply_from_right(T * w) { + T * t = new T[m_m]; + for (int i = 0; i < m_m; i ++) { + T v = numeric_traits::zero(); + for (int j = 0; j < m_m; j++) { + v += w[j]* get_elem(j, i); + } + t[i] = v; + } + + for (int i = 0; i < m_m; i++) { + w[i] = t[i]; + } + delete [] t; + } + + void apply_from_right(vector & w) { + T * t = new T[m_m]; + for (int i = 0; i < m_m; i ++) { + T v = numeric_traits::zero(); + for (int j = 0; j < m_m; j++) { + v += w[j]* get_elem(j, i); + } + t[i] = v; + } + + for (int i = 0; i < m_m; i++) { + w[i] = t[i]; + } + delete [] t; + } + + // void apply_from_right(indexed_vector & w) { + // vector t(w.m_index.size()); + // vector tmp_index(w.m_index.size()); + // copy_aside(t, tmp_index, w); + // clear_data(w); + + // for (int i = 0; i < m_m; i ++) { + // T v = numeric_traits::zero(); + // for (int j = 0; j < m_m; j++) { + // v += w[j]* get_elem(j, i); + // } + // t[i] = v; + // } + + // w.m_index.clear(); + // for (int i = 0; i < m_m; i++) { + // w[i] = t[i]; + // if (!numeric_traits::is_zero(w[i])) { + // w.m_index.push_back(i); + // } + // } + // delete [] t; + // } + T * apply_from_left_with_different_dims(vector & w) { + T * t = new T[m_m]; + for (int i = 0; i < m_m; i ++) { + T v = numeric_traits::zero(); + for (int j = 0; j < m_n; j++) { + v += w[j]* get_elem(i, j); + } + t[i] = v; + } + + return t; + } + void apply_from_left(vector & w , lp_settings & ) { + apply_from_left(w); + } + + void apply_from_left(vector & w) { + T * t = new T[m_m]; + for (int i = 0; i < m_m; i ++) { + T v = numeric_traits::zero(); + for (int j = 0; j < m_m; j++) { + v += w[j]* get_elem(i, j); + } + t[i] = v; + } + + for (int i = 0; i < m_m; i ++) { + w[i] = t[i]; + } + delete [] t; + } + + void apply_from_left(X * w, lp_settings & ) { + T * t = new T[m_m]; + for (int i = 0; i < m_m; i ++) { + T v = numeric_traits::zero(); + for (int j = 0; j < m_m; j++) { + v += w[j]* get_elem(i, j); + } + t[i] = v; + } + + for (int i = 0; i < m_m; i ++) { + w[i] = t[i]; + } + delete [] t; + } + + void apply_from_left_to_X(vector & w, lp_settings & ) { + vector t(m_m); + for (int i = 0; i < m_m; i ++) { + X v = zero_of_type(); + for (int j = 0; j < m_m; j++) { + v += w[j]* get_elem(i, j); + } + t[i] = v; + } + + for (int i = 0; i < m_m; i ++) { + w[i] = t[i]; + } + } + + virtual void set_number_of_rows(unsigned /*m*/) {} + virtual void set_number_of_columns(unsigned /*n*/) { } + + T get_elem(unsigned i, unsigned j) const { return m_values[i * m_n + j]; } + + unsigned row_count() const { return m_m; } + unsigned column_count() const { return m_n; } + + void set_elem(unsigned i, unsigned j, const T& val) { + m_values[i * m_n + j] = val; + } + + // This method pivots row i to row i0 by muliplying row i by + // alpha and adding it to row i0. + void pivot_row_to_row(unsigned i, T alpha, unsigned i0, + double & pivot_epsilon) { + thread_local T _0 = numeric_traits::zero(); + for (unsigned j = 0; j < m_n; j++) { + m_values[i0 * m_n + j] += m_values[i * m_n + j] * alpha; + if (fabs(m_values[i0 + m_n + j]) < pivot_epsilon) { + m_values[i0 + m_n + j] = _0; + } + } + } + + void swap_columns(unsigned a, unsigned b) { + for (unsigned i = 0; i < m_m; i++) { + T t = get_elem(i, a); + set_elem(i, a, get_elem(i, b)); + set_elem(i, b, t); + } + } + + void swap_rows(unsigned a, unsigned b) { + for (unsigned i = 0; i < m_n; i++) { + T t = get_elem(a, i); + set_elem(a, i, get_elem(b, i)); + set_elem(b, i, t); + } + } + + void multiply_row_by_constant(unsigned row, T & t) { + for (unsigned i = 0; i < m_n; i++) { + set_elem(row, i, t * get_elem(row, i)); + } + } + + ~dense_matrix() { + delete [] m_values; + } + }; + + template + dense_matrix operator* (matrix & a, matrix & b){ + dense_matrix ret(a.row_count(), b.column_count()); + for (unsigned i = 0; i < ret.m_m; i++) + for (unsigned j = 0; j< ret.m_n; j++) { + T v = numeric_traits::zero(); + for (unsigned k = 0; k < a.column_count(); k ++){ + v += (a.get_elem(i, k) * b.get_elem(k, j)); + } + ret.set_elem(i, j, v); + } + return ret; + } + + inline unsigned get_width_of_column(unsigned j, vector> & A) { + unsigned r = 0; + for (unsigned i = 0; i < A.size(); i++) { + unsigned s = A[i][j].size(); + if (r < s) { + r = s; + } + } + return r; + } +#endif + inline void print_blanks(int n) { + lean_assert(n >= 0); + while (n--) { + cout << ' '; + } + } +#ifndef NDEBUG + inline void print_matrix_with_widths(vector> & A, vector & ws) { + for (unsigned i = 0; i < A.size(); i++) { + for (unsigned j = 0; j < A[i].size(); j++) { + print_blanks(ws[j] - A[i][j].size()); + cout << A[i][j] << " "; + } + cout << endl; + } + } + + inline void print_string_matrix(vector> & A) { + vector widths; + + for (unsigned j = 0; j < A[0].size(); j++) { + widths.push_back(get_width_of_column(j, A)); + } + + print_matrix_with_widths(A, widths); + std::cout << std::endl; + } + + template + void print_matrix(matrix const & m) { + if (&m == nullptr) { + std::cout << "null" << std::endl; + return; + } + vector> A(m.row_count()); + for (unsigned i = 0; i < m.row_count(); i++) { + for (unsigned j = 0; j < m.column_count(); j++) { + A[i].push_back(T_to_string(m.get_elem(i, j))); + } + } + + print_string_matrix(A); + } + + +#endif + + template + class permutation_matrix + : public tail_matrix { + unsigned m_length; + vector m_permutation; + vector m_rev; + + class ref { + permutation_matrix & m_p; + unsigned m_i; + public: + ref(permutation_matrix & m, unsigned i):m_p(m), m_i(i) {} + + ref & operator=(unsigned v) { m_p.set_val(m_i, v); return *this; } + + ref & operator=(ref const & v) { + m_p.set_val(m_i, v.m_p.m_permutation[v.m_i]); + return *this; + } + operator unsigned & () const { return m_p.m_permutation[m_i]; } + }; + + public: + permutation_matrix() : m_length(0) {} + permutation_matrix(unsigned length): m_length(length), m_permutation(length), m_rev(length) { + unsigned i = m_length; + while (i--) + m_permutation[i] = m_rev[i] = i; + } + + permutation_matrix(unsigned length, vector const & values): m_length(length), m_permutation(length), m_rev(length) { + for (unsigned i = 0; i < length; i++) { + set_val(i, values[i]); + } + } + // create a unit permutation of the given length + void init(unsigned length) { + m_length = length; + m_permutation.resize(length); + m_rev.resize(length); + unsigned i = length; + while (i--) + m_permutation[i] = m_rev[i] = i; + } + + unsigned get_rev(unsigned i) { + return m_rev[i]; + } + +#ifndef NDEBUG + permutation_matrix get_inverse() const { + return permutation_matrix(m_length, m_rev); + } + void print() const { + std::cout << "["; + for (unsigned i = 0; i < m_length; i++) { + std::cout << m_permutation[i]; + if (i < m_length - 1) { + std::cout << ","; + } else { + std::cout << "]"; + } + } + std::cout << std::endl; + } +#endif + // void enlarge(unsigned delta) { + // unsigned len = m_length + delta; + // unsigned * np = new unsigned[len]; + // unsigned * nr = new unsigned[len]; + // memcpy(np, m_permutation, m_length*sizeof(unsigned)); + // memcpy(nr, m_rev, m_length*sizeof(unsigned)); + // unsigned i = m_length; + // m_length = len; + // delete [] m_permutation; + // delete [] m_rev; + // m_permutation = np; + // m_rev = nr; + // for (; i < len; i++) { + // set_val(i, i); + // } + // } + + ref operator[](unsigned i) { return ref(*this, i); } + + unsigned operator[](unsigned i) const { return m_permutation[i]; } + + template + void apply_from_left_perm(vector & w) { +#ifndef NDEBUG + // dense_matrix deb(*this); + // L * deb_w = clone_vector(w, row_count()); + // deb.apply_from_left(deb_w); +#endif + L * t = new L[m_length]; + for (unsigned i = 0; i < m_length; i++) { + t[i] = w[m_permutation[i]]; + } + + for (unsigned i = 0; i < m_length; i++) { + w[i] = t[i]; + } + delete [] t; +#ifndef NDEBUG + // lean_assert(vectors_are_equal(deb_w, w, row_count())); + // delete [] deb_w; +#endif + } + + void apply_from_left(vector & w, lp_settings &) { + apply_from_left_perm(w); + } + + void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) { + apply_from_left_perm(w, settings); + } + + + template + void apply_from_left_perm(indexed_vector & w, lp_settings &) { +#ifndef NDEBUG + // dense_matrix deb(*this); + // T * deb_w = clone_vector(w.m_data, row_count()); + // deb.apply_from_right(deb_w); +#endif + vector t(w.m_index.size()); + vector tmp_index(w.m_index.size()); + copy_aside(t, tmp_index, w); + clear_data(w); + // set the new values + for (unsigned i = t.size(); i > 0;) { + i--; + unsigned j = m_rev[tmp_index[i]]; + w[j] = t[i]; + w.m_index[i] = j; + } +#ifndef NDEBUG + // lean_assert(vectors_are_equal(deb_w, w.m_data, row_count())); + // delete [] deb_w; +#endif + } + + + void apply_from_right(vector & w) { +#ifndef NDEBUG + // dense_matrix deb(*this); + // T * deb_w = clone_vector(w, row_count()); + // deb.apply_from_right(deb_w); +#endif + T * t = new T[m_length]; + for (unsigned i = 0; i < m_length; i++) { + t[i] = w[m_rev[i]]; + } + + for (unsigned i = 0; i < m_length; i++) { + w[i] = t[i]; + } + delete [] t; +#ifndef NDEBUG + // lean_assert(vectors_are_equal(deb_w, w, row_count())); + // delete [] deb_w; +#endif + } + +// void apply_from_right(indexed_vector & w) { +// lean_assert(false); // i think it is never called +// #ifndef NDEBUG +// // dense_matrix deb(*this); +// // T * deb_w = clone_vector(w.m_data, row_count()); +// // deb.apply_from_right(deb_w); +// #endif +// vector t(w.m_index.size()); +// vector tmp_index(w.m_index.size()); +// copy_aside(t, tmp_index, w); +// clear_data(w); +// // set the new values +// for (unsigned i = t.size(); i > 0;) { +// i--; +// unsigned j = m_permutation[tmp_index[i]]; +// w[j] = t[i]; +// w.m_index[i] = j; +// } +// for (unsigned i = 0; i < m_length; i++) { +// w[i] = t[i]; +// } +// #ifndef NDEBUG +// // lean_assert(vectors_are_equal(deb_w, w.m_data, row_count())); +// // delete [] deb_w; +// #endif +// } + + template + void copy_aside(vector & t, vector & tmp_index, indexed_vector & w) { + for (unsigned i = t.size(); i > 0;) { + i--; + unsigned j = w.m_index[i]; + t[i] = w[j]; // copy aside all non-zeroes + tmp_index[i] = j; // and the indices too + } + } + + template + void clear_data(indexed_vector & w) { + // clear old non-zeroes + for (unsigned i = w.m_index.size(); i > 0;) { + i--; + unsigned j = w.m_index[i]; + w[j] = zero_of_type(); + } + } + + template + void apply_reverse_from_left(indexed_vector & w) { + // the result will be w = p(-1) * w +#ifndef NDEBUG + // dense_matrix deb(get_reverse()); + // L * deb_w = clone_vector(w.m_data, row_count()); + // deb.apply_from_left(deb_w); +#endif + vector t(w.m_index.size()); + vector tmp_index(w.m_index.size()); + + copy_aside(t, tmp_index, w); + clear_data(w); + + // set the new values + for (unsigned i = t.size(); i > 0;) { + i--; + unsigned j = m_permutation[tmp_index[i]]; + w[j] = t[i]; + w.m_index[i] = j; + } +#ifndef NDEBUG + // lean_assert(vectors_are_equal(deb_w, w.m_data, row_count())); + // delete [] deb_w; +#endif + } + + template + void apply_reverse_from_left(std::vector & w) { + // the result will be w = p(-1) * w +#ifndef NDEBUG + // dense_matrix deb(get_reverse()); + // T * deb_w = clone_vector(w, row_count()); + // deb.apply_from_left(deb_w); +#endif + vector t(m_length); + for (unsigned i = 0; i < m_length; i++) { + t[m_permutation[i]] = w[i]; + } + + for (unsigned i = 0; i < m_length; i++) { + w[i] = t[i]; + } +#ifndef NDEBUG + // lean_assert(vectors_are_equal(deb_w, w, row_count())); + // delete [] deb_w; +#endif + } + template + void apply_reverse_from_right(vector & w) { + // the result will be w = w * p(-1) +#ifndef NDEBUG + // dense_matrix deb(get_reverse()); + // T * deb_w = clone_vector(w, row_count()); + // deb.apply_from_right(deb_w); +#endif + L * t = new T[m_length]; + for (unsigned i = 0; i < m_length; i++) { + t[i] = w[m_permutation[i]]; + } + + for (unsigned i = 0; i < m_length; i++) { + w[i] = t[i]; + } + delete [] t; +#ifndef NDEBUG + // lean_assert(vectors_are_equal(deb_w, w, row_count())); + // delete deb_w; +#endif + } + + void set_val(unsigned i, unsigned pi) { + lean_assert(i < m_length && pi < m_length); + m_permutation[i] = pi; + m_rev[pi] = i; + } + + void transpose_from_left(unsigned i, unsigned j) { + // the result will be this = (i,j)*this + lean_assert(i < m_length && j < m_length && i != j); + auto pi = m_rev[i]; + auto pj = m_rev[j]; + set_val(pi, j); + set_val(pj, i); + } + + unsigned apply_reverse(unsigned i) const { + return m_rev[i]; + } + + void transpose_from_right(unsigned i, unsigned j) { + // the result will be this = this * (i,j) + lean_assert(i < m_length && j < m_length && i != j); + auto pi = m_permutation[i]; + auto pj = m_permutation[j]; + set_val(i, pj); + set_val(j, pi); + } +#ifndef NDEBUG + T get_elem(unsigned i, unsigned j) const{ + return m_permutation[i] == j? numeric_traits::one() : numeric_traits::zero(); + } + unsigned row_count() const{ return m_length; } + unsigned column_count() const { return m_length; } + virtual void set_number_of_rows(unsigned /*m*/) { } + virtual void set_number_of_columns(unsigned /*n*/) { } +#endif + + unsigned * clone_m_permutation() { + auto r = new unsigned[m_length]; + for (int i = m_length - 1; i >= 0; i--) { + r[i] = m_permutation[i]; + } + return r; + } + + void multiply_by_permutation_from_left(permutation_matrix & p) { + auto clone = clone_m_permutation(); + lean_assert(p.m_length == m_length); + for (unsigned i = 0; i < m_length; i++) { + set_val(i, clone[p[i]]); // we have m(P)*m(Q) = m(QP), where m is the matrix of the permutation + } + delete clone; + } + + // this is multiplication in the matrix sense + void multiply_by_permutation_from_right(permutation_matrix & p) { + auto clone = clone_m_permutation(); + lean_assert(p.m_length == m_length); + for (unsigned i = 0; i < m_length; i++) { + set_val(i, p[clone[i]]); // we have m(P)*m(Q) = m(QP), where m is the matrix of the permutation + } + delete clone; + } + + void multiply_by_reverse_from_right(permutation_matrix & q){ // todo : condensed permutations ? + auto clone = clone_m_permutation(); + // the result is this = this*q(-1) + for (unsigned i = 0; i < m_length; i++) { + set_val(i, q.m_rev[clone[i]]); // we have m(P)*m(Q) = m(QP), where m is the matrix of the permutation + } + delete clone; + } + + void multiply_by_permutation_reverse_from_left(permutation_matrix & r){ // todo : condensed permutations? + // the result is this = r(-1)*this + auto clone = clone_m_permutation(); + // the result is this = this*q(-1) + for (unsigned i = 0; i < m_length; i++) { + set_val(i, clone[r.m_rev[i]]); + } + delete clone; + } + + void shrink_by_one_identity() { + lean_assert(is_identity()); + m_length--; + delete [] m_permutation; + delete [] m_rev; + m_permutation = new unsigned[m_length]; + m_rev = new unsigned[m_length]; + for (unsigned i = 0; i < m_length; i++) { + m_permutation[i] = m_rev[i] = i; + } + } + + bool is_identity() const { + for (unsigned i = 0; i < m_length; i++) { + if (m_permutation[i] != i) { + return false; + } + } + return true; + } + + unsigned size() const { return m_length; } + + unsigned * values() const { return m_permutation; } + }; // end of the permutation class + +#ifndef NDEBUG + template + class permutation_generator { + unsigned m_n; + permutation_generator* m_lower; + bool m_done = false; + permutation_matrix m_current; + unsigned m_last; + public: + permutation_generator(unsigned n): m_n(n), m_current(n) { + lean_assert(n > 0); + if (n > 1) { + m_lower = new permutation_generator(n - 1); + } else { + m_lower = nullptr; + } + + m_last = 0; + } + + permutation_generator(const permutation_generator & o): m_n(o.m_n), m_done(o.m_done), m_current(o.m_current), m_last(o.m_last) { + if (m_lower != nullptr) { + m_lower = new permutation_generator(o.m_lower); + } else { + m_lower = nullptr; + } + } + + bool move_next() { + if (m_done) { + return false; + } + + if (m_lower == nullptr) { + if (m_last == 0) { + m_last++; + return true; + } else { + m_done = true; + return false; + } + } else { + if (m_last < m_n && m_last > 0) { + m_current[m_last - 1] = m_current[m_last]; + m_current[m_last] = m_n - 1; + m_last++; + return true; + } else { + if (m_lower -> move_next()) { + auto lower_curr = m_lower -> current(); + for ( unsigned i = 1; i < m_n; i++ ){ + m_current[i] = (*lower_curr)[i - 1]; + } + m_current[0] = m_n - 1; + m_last = 1; + return true; + } else { + m_done = true; + return false; + } + } + } + } + + ~permutation_generator() { + if (m_lower != nullptr) { + delete m_lower; + } + } + + permutation_matrix *current() { + return &m_current; + } + }; + + template + inline unsigned number_of_inversions(permutation_matrix & p) { + unsigned ret = 0; + unsigned n = p.size(); + for (unsigned i = 0; i < n; i++) { + for (unsigned j = i + 1; j < n; j++) { + if (p[i] > p[j]) { + ret++; + } + } + } + return ret; + } + + template + int sign(permutation_matrix & p) { + return is_even(number_of_inversions(p))? 1: -1; + } + + template + T det_val_on_perm(permutation_matrix* u, const matrix& m) { + unsigned n = m.row_count(); + T ret = numeric_traits::one(); + for (unsigned i = 0; i < n; i++) { + unsigned j = (*u)[i]; + ret *= m(i, j); + } + return ret * sign(*u); + } + + template + T determinant(const matrix& m) { + lean_assert(m.column_count() == m.row_count()); + unsigned n = m.row_count(); + permutation_generator allp(n); + T ret = numeric_traits::zero(); + while (allp.move_next()){ + ret += det_val_on_perm(allp.current(), m); + } + return ret; + } + + +#endif + // this matrix has ones on the diagonal, outside of a column + // and one non-zero element off the diagonal in the column + + template + struct one_off_diagonal_matrix: + public tail_matrix { + unsigned m_i; // the element row + unsigned m_j; // the element column + T m_val_jj; // the value in the column's diagonal element + T m_val_ij; // the value off the diagonal element + public: + one_off_diagonal_matrix(unsigned i, unsigned j, T val_at_jj, T val_at_ij): m_i(i), m_j(j), m_val_jj(val_at_jj), m_val_ij(val_at_ij) { + } + + one_off_diagonal_matrix(const one_off_diagonal_matrix * o):m_i(o.m_i), m_j(o.m_j), m_val_jj(o.m_val_jj), m_val_ij(o.m_val_ij) { +#ifndef NDEBUG + m_m = m_n = o.m_m; +#endif + } + + void conjugate_by_permutation(permutation_matrix & p) { + // this = p * this * p(-1) +#ifndef NDEBUG + // auto rev = p.get_reverse(); + // auto deb = ((*this) * rev); + // deb = p * deb; +#endif + m_j = p.get_rev(m_j); + m_i = p.get_rev(m_i); +#ifndef NDEBUG + // lean_assert(deb == *this); +#endif + } +#ifndef NDEBUG + unsigned m_m; + unsigned m_n; + virtual void set_number_of_rows(unsigned m) { m_n = m_m = m; } + virtual void set_number_of_columns(unsigned n) {m_m = m_n = n; } + + T get_elem (unsigned i, unsigned j) const { + if (j == m_j){ + if (i == m_j){ + return 1 / m_val_jj; + } + if (i == m_i) { + return m_val_ij; + } + return numeric_traits::zero(); + } + + return i == j ? numeric_traits::one() : numeric_traits::zero(); + } + + unsigned row_count() const { return m_m; } // not defined } + unsigned column_count() const { return m_n; } // not defined } +#endif + void apply_from_left(vector & w, lp_settings &) { +#ifndef NDEBUG + // dense_matrix deb(*this); + // T * deb_w = clone_vector(w, row_count()); + // deb.apply_from_left(deb_w); +#endif + auto wj = w[m_j]; + w[m_j] = wj / m_val_jj; + w[m_i] += wj * m_val_ij; +#ifndef NDEBUG + // lean_assert(vectors_are_equal(deb_w, w, row_count())); + // delete deb_w; +#endif + } + + template + void apply_from_left_local(indexed_vector & w, lp_settings & settings) { +#ifndef NDEBUG + // dense_matrix deb(*this); + // T * deb_w = clone_vector(w.m_data, row_count()); + // deb.apply_from_left(deb_w); +#endif + if (is_zero(w[m_j])) { + return; + } + + bool m_i_is_zero = is_zero(w[m_i]); + L wj = w[m_j]; + w[m_j] = wj / m_val_jj; + if (m_i_is_zero) { + w[m_i] = wj * m_val_ij; + w.m_index.push_back(m_i); + } else { + w[m_i] += wj * m_val_ij; // we can get a zero here - do we need to check for it + } + + lean_assert(check_vector_for_small_values(w, settings )); + +#ifndef NDEBUG + // lean_assert(vectors_are_equal(deb_w, w.m_data, row_count())); + // delete deb_w; +#endif + } + + void apply_from_left_to_T(indexed_vector &w, lp_settings &settings) { + apply_from_left_local(w, settings); + } + void apply_from_right(vector & w) { +#ifndef NDEBUG + // dense_matrix deb(*this); + // T * deb_w = clone_vector(w, row_count()); + // deb.apply_from_right(deb_w); +#endif + w[m_j] = w[m_j] / m_val_jj + m_val_ij * w[m_i]; +#ifndef NDEBUG + // lean_assert(vectors_are_equal(deb_w, w, row_count())); + // delete deb_w; +#endif + } + +// void apply_from_right(indexed_vector & w) { +// #ifndef NDEBUG +// // dense_matrix deb(*this); +// // vector deb_w(w.m_data); +// // deb.apply_from_right(deb_w); +// #endif +// bool j_is_used = !numeric_traits::is_zero(w[m_j]); +// if (j_is_used) { +// w[m_j] = w[m_j] / m_val_jj + m_val_ij * w[m_i]; +// } else { +// w[m_j] = m_val_ij * w[m_i]; +// w.m_index.push_back(m_j); +// } +// #ifndef NDEBUG +// // lean_assert(vectors_are_equal(deb_w, w.m_data, row_count())); +// // delete deb_w; +// #endif +// } + }; // end of one_off_diagonal_matrix + +} diff --git a/src/util/lp/row_eta_matrix.h b/src/util/lp/row_eta_matrix.h new file mode 100644 index 0000000000..ed1914a370 --- /dev/null +++ b/src/util/lp/row_eta_matrix.h @@ -0,0 +1,202 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/debug.h" +#include "util/numerics/numeric_traits.h" +#include "util/numerics/xnumeral.h" +#include "util/numerics/mpq.h" +#include "util/numerics/mpz.h" +#include "util/numerics/mpbq.h" +#include "util/numerics/double.h" +#include "util/numerics/float.h" +#include "util/numerics/mpfp.h" +#include +#include "util/lp/sparse_vector.h" +#include "util/lp/indexed_vector.h" + +namespace lean { + // This is the sum of a unit matrix and a lower triangular matrix + // with non-zero elements only in one column +template +class row_eta_matrix + : public tail_matrix { +#ifndef NDEBUG + unsigned m_dimension; +#endif + unsigned m_row_start; + unsigned m_row; + sparse_vector m_row_vector; +public: +#ifndef NDEBUG + row_eta_matrix(unsigned row_start, unsigned row, unsigned dim): +#else + row_eta_matrix(unsigned row_start, unsigned row): +#endif + +#ifndef NDEBUG + m_dimension(dim), +#endif + m_row_start(row_start), m_row(row) { + lean_assert(dim > 0); + } + + void print() { + print_matrix(*this); + } + + const T & get_diagonal_element() const { + return m_row_vector.m_data[m_row]; + } + + void apply_from_left(vector & w, lp_settings & +#ifndef NDEBUG + // settings +#endif +) { +// #ifndef NDEBUG +// dense_matrix deb(*this); +// auto clone_w = clone_vector(w, m_dimension); +// deb.apply_from_left(clone_w, settings); +// #endif + auto w_at_row = w[m_row]; + for (auto it = sparse_vector_iterator(m_row_vector); !it.done(); it.move()) { + w_at_row += w[it.index()] * it.value(); + } + w[m_row] = w_at_row; +// #ifndef NDEBUG +// lean_assert(vectors_are_equal(clone_w, w, m_dimension)); +// delete [] clone_w; +// #endif + } + + template + void apply_from_left_local(indexed_vector & w, lp_settings & settings) { +#ifndef NDEBUG + // dense_matrix deb(*this); + // auto clone_w = clone_vector(w.m_data, m_dimension); + // deb.apply_from_left(clone_w); +#endif + auto w_at_row = w[m_row]; + bool was_zero_at_m_row = is_zero(w_at_row); + + for (auto it = sparse_vector_iterator(m_row_vector); !it.done(); it.move()) { + w_at_row += w[it.index()] * it.value(); + } + + if (!settings.abs_val_is_smaller_than_drop_tolerance(w_at_row)){ + if (was_zero_at_m_row) { + w.m_index.push_back(m_row); + } + w[m_row] = w_at_row; + } else if (!was_zero_at_m_row){ + w[m_row] = zero_of_type(); + auto it = std::find(w.m_index.begin(), w.m_index.end(), m_row); + w.m_index.erase(it); + } + lean_assert(check_vector_for_small_values(w, settings)); +#ifndef NDEBUG + // lean_assert(vectors_are_equal(clone_w, w.m_data, m_dimension)); + // delete clone_w; +#endif + } + + void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) { + apply_from_left_local(w, settings); + } + + void push_back(unsigned row_index, T val ) { + m_row_vector.push_back(row_index, val); + } + + void apply_from_right(vector & w) { + T w_row = w[m_row]; + if (numeric_traits::is_zero(w_row)) return; +#ifndef NDEBUG + // dense_matrix deb(*this); + // auto clone_w = clone_vector(w, m_dimension); + // deb.apply_from_right(clone_w); +#endif + for (auto it = sparse_vector_iterator(m_row_vector); !it.done(); it.move()) { + w[it.index()] += w_row * it.value(); + } +#ifndef NDEBUG + // lean_assert(vectors_are_equal(clone_w, w, m_dimension)); + // delete clone_w; +#endif + } + + void apply_from_right(indexed_vector & w) { + T w_row = w[m_row]; + if (numeric_traits::is_zero(w_row)) return; +#ifndef NDEBUG + // dense_matrix deb(*this); + // auto clone_w = clone_vector(w.m_data, m_dimension); + // deb.apply_from_right(clone_w); +#endif + for (auto it = sparse_vector_iterator(m_row_vector); !it.done(); it.move()) { + T old_val = w[it.index()]; + T v = w[it.index()] += w_row * it.value(); + if (numeric_traits::is_zero(old_val)) { + w.m_index.push_back(it.index()); + } else if (numeric_traits::is_zero(v)) { // it is a very rare case + auto w_it = std::find(w.m_index.begin(), w.m_index.end(), it.index()); + lean_assert(w_it != w.m_index.end()); + w.m_index.erase(w_it); + } + } +#ifndef NDEBUG + // lean_assert(vectors_are_equal(clone_w, w.m_data, m_dimension)); + // for (unsigned i = 0; i < m_dimension; i++) { + // if (!numeric_traits::is_zero(w.m_data[i])) { + // lean_assert(std::find(w.m_index.begin(), w.m_index.end(), i) != w.m_index.end()); + // } + // } + // delete clone_w; +#endif + } + + void conjugate_by_permutation(permutation_matrix & p) { + // this = p * this * p(-1) +#ifndef NDEBUG + // auto rev = p.get_reverse(); + // auto deb = ((*this) * rev); + // deb = p * deb; +#endif + m_row = p.apply_reverse(m_row); + // copy aside the column indices + vector columns; + for (auto it = sparse_vector_iterator(m_row_vector); !it.done(); it.move()) { + columns.push_back(it.index()); + } + for (unsigned i = columns.size(); i-- > 0;) { + m_row_vector.m_data[i].first = p.get_rev(columns[i]); + } +#ifndef NDEBUG + // lean_assert(deb == *this); +#endif + } + + T get_elem(unsigned row, unsigned col) const { + if (row == m_row){ + if (col == row) { + return numeric_traits::one(); + } + return m_row_vector[col]; + } + + return col == row ? numeric_traits::one() : numeric_traits::zero(); + } +#ifndef NDEBUG + unsigned row_count() const { return m_dimension; } + unsigned column_count() const { return m_dimension; } + void set_number_of_rows(unsigned /*m*/) { } + void set_number_of_columns(unsigned /*n*/) { } +#endif +}; // end of row_eta_matrix +} diff --git a/src/util/lp/scaler.h b/src/util/lp/scaler.h new file mode 100644 index 0000000000..05ffe3c729 --- /dev/null +++ b/src/util/lp/scaler.h @@ -0,0 +1,269 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once + +#include "util/numerics/double.h" +#include +#include +#include +#include /* printf, fopen */ +#include /* exit, EXIT_FAILURE */ +namespace lean { + // for scaling an LP + template + class scaler { + vector & m_b; // right side + static_matrix &m_A; // the constraint matrix + const T & m_scaling_minimum; + const T & m_scaling_maximum; + vector& m_column_scale; + lp_settings & m_settings; + public: + // constructor + scaler(vector & b, static_matrix &A, const T & scaling_minimum, const T & scaling_maximum, vector & column_scale, + lp_settings & settings): + m_b(b), + m_A(A), + m_scaling_minimum(scaling_minimum), + m_scaling_maximum(scaling_maximum), + m_column_scale(column_scale), + m_settings(settings) { + lean_assert(m_column_scale.size() == 0); + m_column_scale.resize(m_A.column_count(), numeric_traits::one()); + } + + T right_side_balance() { + T ret = zero_of_type(); + unsigned i = m_A.row_count(); + while (i--) { + T rs = abs(convert_struct::convert(m_b[i])); + if (!is_zero(rs)) { + numeric_traits::log(rs); + ret += rs * rs; + } + } + return ret; + } + + T get_balance() { + return m_A.get_balance(); + } + + T A_min() const { + T min = zero_of_type(); + for (unsigned i = 0; i < m_A.row_count(); i++) { + T t = m_A.get_min_abs_in_row(i); + min = i == 0 ? t : std::min(t, min); + } + return min; + } + + T A_max() const { + T max = zero_of_type(); + for (unsigned i = 0; i < m_A.row_count(); i++) { + T t = m_A.get_max_abs_in_row(i); + max = i == 0? t : std::max(t, max); + } + return max; + } + + T get_A_ratio() const { + T min = A_min(); + T max = A_max(); + T ratio = max / min; + return ratio; + } + + T get_max_ratio_on_rows() const { + T ret = T(1); + unsigned i = m_A.row_count(); + while (i--) { + T t = m_A.get_max_abs_in_row(i)/m_A.get_min_abs_in_row(i); + if (t > ret) + ret = t; + } + return ret; + } + + T get_max_ratio_on_columns() const { + T ret = T(1); + unsigned i = m_A.column_count(); + while (i--) { + T t = m_A.get_max_abs_in_column(i)/m_A.get_min_abs_in_column(i); + if (t > ret) + ret = t; + } + return ret; + } + + void scale_rows_with_geometric_mean() { + unsigned i = m_A.row_count(); + while (i--) { + T max = m_A.get_max_abs_in_row(i); + T min = m_A.get_min_abs_in_row(i); + lean_assert(max > zero_of_type() && min > zero_of_type()); + T gm = T(sqrt(numeric_traits::get_double(max*min))); + m_A.divide_row_by_constant(i, gm); + m_b[i] /= gm; + } + } + + void scale_columns_with_geometric_mean() { + unsigned i = m_A.column_count(); + while (i--) { + T max = m_A.get_max_abs_in_column(i); + T min = m_A.get_min_abs_in_column(i); + T gm = T(1)/T(sqrt(numeric_traits::get_double(max*min))); + m_A.scale_column(i, gm); + m_column_scale[i]*=gm; + } + } + + void scale_once_for_ratio() { + T max_ratio_on_rows = get_max_ratio_on_rows(); + T max_ratio_on_columns = get_max_ratio_on_columns(); + bool scale_rows_first = max_ratio_on_rows > max_ratio_on_columns; + // if max_ratio_on_columns is the largerst then the rows are in worser shape then columns + if (scale_rows_first) { + scale_rows_with_geometric_mean(); + scale_columns_with_geometric_mean(); + } else { + scale_columns_with_geometric_mean(); + scale_rows_with_geometric_mean(); + } + } + + bool scale_with_ratio() { + T ratio = get_A_ratio(); + // The ratio is greater than or equal to one. We would like to diminish it and bring it as close to 1 as possible + unsigned reps = 20; + do { + scale_once_for_ratio(); + T new_r = get_A_ratio(); + if (new_r >= T(0.9) * ratio) + break; + } while (reps--); + + bring_rows_and_columns_maximums_to_one(); + return true; + } + + void bring_row_maximums_to_one() { + unsigned i = m_A.row_count(); + while (i--) { + T t = m_A.get_max_abs_in_row(i); + m_A.divide_row_by_constant(i, t); + m_b[i] /= t; + } + } + + void bring_column_maximums_to_one() { + unsigned i = m_A.column_count(); + while (i--) { + T t = T(1) / m_A.get_max_abs_in_column(i); + m_A.scale_column(i, t); + m_column_scale[i] *= t; + } + } + + void bring_rows_and_columns_maximums_to_one() { + if (get_max_ratio_on_rows() > get_max_ratio_on_columns()) { + bring_row_maximums_to_one(); + bring_column_maximums_to_one(); + } else { + bring_column_maximums_to_one(); + bring_row_maximums_to_one(); + } + } + + bool scale_with_log_balance() { + T balance = get_balance(); + T balance_before_scaling = balance; + // todo : analyze the scale order : rows-columns, or columns-rows. Iterate if needed + for (int i = 0; i < 10; i++) { + scale_rows(); + scale_columns(); + T nb = get_balance(); + if (nb < T(0.9) * balance) { + balance = nb; + } else { + balance = nb; + break; + } + } + return balance <= balance_before_scaling; + } + // Returns true if and only if the scaling was successful. + // It is the caller responsibility to restore the matrix + bool scale() { + if (numeric_traits::precise()) return true; + if (m_settings.scale_with_ratio) + return scale_with_ratio(); + return scale_with_log_balance(); + } + + void scale_rows() { + for (unsigned i = 0; i < m_A.row_count(); i++) + scale_row(i); + } + + void scale_row(unsigned i) { + T row_max = std::max(m_A.get_max_abs_in_row(i), abs(convert_struct::convert(m_b[i]))); + T alpha = numeric_traits::one(); + if (numeric_traits::is_zero(row_max)) { + return; + } + if (numeric_traits::get_double(row_max) < m_scaling_minimum) { + do { + alpha *= 2; + row_max *= 2; + } while (numeric_traits::get_double(row_max) < m_scaling_minimum); + m_A.scale_row(i, alpha); + m_b[i] *= alpha; + } else if (numeric_traits::get_double(row_max) > m_scaling_maximum) { + do { + alpha /= 2; + row_max /= 2; + } while (numeric_traits::get_double(row_max) > m_scaling_maximum); + m_A.scale_row(i, alpha); + m_b[i] *= alpha; + } + } + + void scale_column(unsigned i){ + T column_max = m_A.get_max_abs_in_column(i); + T alpha = numeric_traits::one(); + + if (numeric_traits::is_zero(column_max)){ + return; // the column has zeros only + } + + if (numeric_traits::get_double(column_max) < m_scaling_minimum) { + do { + alpha *= 2; + column_max *= 2; + } while (numeric_traits::get_double(column_max) < m_scaling_minimum); + } else if (numeric_traits::get_double(column_max) > m_scaling_maximum) { + do { + alpha /= 2; + column_max /= 2; + } while (numeric_traits::get_double(column_max) > m_scaling_maximum); + } else { + return; + } + m_A.scale_column(i, alpha); + m_column_scale[i] = alpha; + } + + void scale_columns() { + for (unsigned i = 0; i < m_A.column_count(); i++) { + scale_column(i); + } + } + }; +} diff --git a/src/util/lp/sparse_matrix.h b/src/util/lp/sparse_matrix.h new file mode 100644 index 0000000000..8cf076799d --- /dev/null +++ b/src/util/lp/sparse_matrix.h @@ -0,0 +1,1321 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/numerics/float.h" +#include "util/lp/permutation_matrix.h" +#include +#include "util/lp/static_matrix.h" +#include +#include +#include +#include +#include +#include "util/lp/indexed_value.h" +#include "util/lp/indexed_vector.h" +#include +#include "util/lp/lp_settings.h" +#include "util/lp/eta_matrix.h" +#include "util/lp/binary_heap_upair_queue.h" +namespace lean { + +using std::vector; +using std::cout; + // it is a square matrix +template +class sparse_matrix +#ifndef NDEBUG + : public matrix +#endif +{ + struct col_header { + unsigned m_shortened_markovitz = 0; + vector> m_values; // the actual column values + + col_header() {} + + void shorten_markovich_by_one() { + m_shortened_markovitz++; + } + + void zero_shortened_markovitz() { + m_shortened_markovitz = 0; + } + }; + + binary_heap_upair_queue m_pivot_queue; +public: + vector>> m_rows; + vector m_columns; + permutation_matrix m_row_permutation; + permutation_matrix m_column_permutation; + indexed_vector m_work_pivot_vector; +#ifndef NDEBUG + // dense_matrix m_dense; +#endif + /* + the rule is: row i is mapped to m_row_permutation[i] and + column j is mapped to m_column_permutation.apply_reverse(j) + */ + + unsigned adjust_row(unsigned row) const{ + return m_row_permutation[row]; + } + + unsigned adjust_column(unsigned col) const{ + return m_column_permutation.apply_reverse(col); + } + + unsigned adjust_row_inverse(unsigned row) const{ + return m_row_permutation.apply_reverse(row); + } + + unsigned adjust_column_inverse(unsigned col) const{ + return m_column_permutation[col]; + } + + void copy_column_from_static_matrix(unsigned col, static_matrix const &A, unsigned col_index_in_the_new_matrix) { + vector> const & A_col_vector = A.m_columns[col]; + unsigned size = A_col_vector.size(); + vector> & new_column_vector = m_columns[col_index_in_the_new_matrix].m_values; + for (unsigned l = 0; l < size; l++) { + column_cell const & col_cell = A_col_vector[l]; + unsigned col_offset = new_column_vector.size(); + vector> & row_vector = m_rows[col_cell.m_i]; + unsigned row_offset = row_vector.size(); + new_column_vector.push_back(indexed_value(col_cell.m_value, col_cell.m_i, row_offset)); + row_vector.push_back(indexed_value(col_cell.m_value, col_index_in_the_new_matrix, col_offset)); + } + } + + void copy_B(static_matrix const &A, std::vector & basis) { + unsigned m = A.row_count(); // this should be the size of basis + for (unsigned j = m; j-- > 0;) { + copy_column_from_static_matrix(basis[j], A, j); + } + } + +public: + // constructor that copies columns of the basis from A + sparse_matrix(static_matrix const &A, std::vector & basis) : + m_pivot_queue(A.row_count()), + m_row_permutation(A.row_count()), + m_column_permutation(A.row_count()), + m_work_pivot_vector(A.row_count()) { + init_row_headers(); + init_column_headers(); + copy_B(A, basis); + } + + // helper access definitions for debugging region + + class ref_matrix_element { + sparse_matrix & m_matrix; + unsigned m_row; + unsigned m_col; + public: + ref_matrix_element(sparse_matrix & m, unsigned row, unsigned col):m_matrix(m), m_row(row), m_col(col) {} + ref_matrix_element & operator=(T const & v) { m_matrix.set( m_row, m_col, v); return *this; } + ref_matrix_element & operator=(ref_matrix_element const & v) { m_matrix.set(m_row, m_col, v.m_matrix.get(v.m_row, v.m_col)); return *this; } + operator T () const { return m_matrix.get(m_row, m_col); } + }; + + class ref_row { + sparse_matrix & m_matrix; + unsigned m_row; + public: + ref_row(sparse_matrix & m, unsigned row) : m_matrix(m), m_row(row) {} + ref_matrix_element operator[](unsigned col) const { return ref_matrix_element(m_matrix, m_row, col); } + }; + + void set_with_no_adjusting_for_row(unsigned row, unsigned col, T val) { // should not be used in efficient code + vector> & row_vec = m_rows[row]; + for (auto & iv : row_vec) { + if (iv.m_index == col) { + iv.set_value(val); + return; + } + } + // have not found the column between the indices + row_vec.push_back(indexed_value(val, col)); // what about m_other ??? + } + + void set_with_no_adjusting_for_col(unsigned row, unsigned col, T val) { // should not be used in efficient code + vector> & col_vec = m_columns[col].m_values; + for (auto & iv : col_vec) { + if (iv.m_index == row) { + iv.set_value(val); + return; + } + } + // have not found the column between the indices + col_vec.push_back(indexed_value(val, row)); // what about m_other ??? + } + + + void set_with_no_adjusting(unsigned row, unsigned col, T val) { // should not be used in efficient code + set_with_no_adjusting_for_row(row, col, val); + set_with_no_adjusting_for_col(row, col, val); + } + + void set(unsigned row, unsigned col, T val) { // should not be used in efficient code + lean_assert(row < dimension() && col < dimension()); + // m_dense.set_elem(row, col, val); + row = adjust_row(row); + col = adjust_column(col); + set_with_no_adjusting(row, col, val); + // lean_assert(*this == m_dense); + } + + T const & get_not_adjusted(unsigned row, unsigned col) const { + for (indexed_value const & iv : m_rows[row]) { + if (iv.m_index == col) { + return iv.m_value; + } + } + return numeric_traits::zero(); + } + + T const & get(unsigned row, unsigned col) const { // should not be used in efficient code + row = adjust_row(row); + auto & row_chunk = m_rows[row]; + col = adjust_column(col); + for (indexed_value const & iv : row_chunk) { + if (iv.m_index == col) { + return iv.m_value; + } + } + return numeric_traits::zero(); + } + + ref_row operator[](unsigned row) { return ref_row(*this, row); } + + ref_matrix_element operator()(unsigned row, unsigned col) { return ref_matrix_element(*this, row, col); } + + T operator() (unsigned row, unsigned col) const { return get(row, col); } + + // starting inner classes + + // end of access for debugging helpers + + vector> & get_row_values(unsigned row) { + return m_rows[row]; + } + + vector> const & get_row_values(unsigned row) const { + return m_rows[row]; + } + + vector> & get_column_values(unsigned col) { + return m_columns[col].m_values; + } + + vector> const & get_column_values(unsigned col) const { + return m_columns[col].m_values; + } + + // constructor creating a zero matrix of dim*dim + sparse_matrix(unsigned dim) : + m_pivot_queue(dim), // dim will be the initial size of the queue + m_row_permutation(dim), + m_column_permutation(dim), + m_work_pivot_vector(dim) { + init_row_headers(); + init_column_headers(); + } + + + + unsigned dimension() const {return m_row_permutation.size();} + +#ifndef NDEBUG + unsigned row_count() const {return dimension();} + unsigned column_count() const {return dimension();} +#endif + + void init_row_headers() { + for (unsigned l = 0; l < m_row_permutation.size(); l++) { + m_rows.push_back(vector>()); + } + } + + void init_column_headers() { // do we alway have only a square sparse_matrix? + for (unsigned l = 0; l < m_row_permutation.size(); l++) { + m_columns.push_back(col_header()); + } + } + + unsigned lowest_row_in_column(unsigned j) { + auto & mc = get_column_values(adjust_column(j)); + unsigned ret = 0; + for (auto & iv : mc) { + unsigned row = adjust_row_inverse(iv.m_index); + if (row > ret) { + ret = row; + } + } + return ret; + } + + unsigned number_of_non_zeroes_in_row(unsigned i) const { + lean_assert(i < dimension()); + return m_rows[i].size(); + } + + unsigned number_of_non_zeroes_in_column(unsigned i) const { + lean_assert(i < dimension()); + return m_columns[i].m_values.size(); + } + + + + indexed_value & column_iv_other(indexed_value & iv) { + return m_rows[iv.m_index][iv.m_other]; + } + + indexed_value & row_iv_other(indexed_value & iv) { + lean_assert(m_columns[iv.m_index].m_values.size() > iv.m_other); + return m_columns[iv.m_index].m_values[iv.m_other]; + } + + + void remove_element(vector> & row_vals, unsigned row_offset, vector> & column_vals, unsigned column_offset) { + if (column_offset != column_vals.size() - 1) { + auto & column_iv = column_vals[column_offset] = column_vals.back(); // copy from the tail + column_iv_other(column_iv).m_other = column_offset; + if (row_offset != row_vals.size() - 1) { + auto & row_iv = row_vals[row_offset] = row_vals.back(); // copy from the tail + row_iv_other(row_iv).m_other = row_offset; + } + } else if (row_offset != row_vals.size() - 1) { + auto & row_iv = row_vals[row_offset] = row_vals.back(); // copy from the tail + row_iv_other(row_iv).m_other = row_offset; + } + // do nothing - just decrease the sizes + column_vals.pop_back(); + row_vals.pop_back(); + } + + void remove_element(vector> & row_chunk, indexed_value & row_el_iv) { + auto & column_chunk = get_column_values(row_el_iv.m_index); + indexed_value & col_el_iv = column_chunk[row_el_iv.m_other]; + remove_element(row_chunk, col_el_iv.m_other, column_chunk, row_el_iv.m_other); + } + + void put_max_index_to_0(vector> & row_vals, unsigned max_index) { + if (max_index == 0) return; + indexed_value * max_iv = & row_vals[max_index]; + indexed_value * start_iv = & row_vals[0]; + // update the "other" columns elements which are bound to the start_iv and max_iv + m_columns[max_iv->m_index].m_values[max_iv->m_other].m_other = 0; + m_columns[start_iv->m_index].m_values[start_iv->m_other].m_other = max_index; + + // swap the elements + indexed_value t = * max_iv; + * max_iv = * start_iv; + * start_iv = t; + } + + void set_max_in_row(unsigned row) { + set_max_in_row(m_rows[row]); + } + + void set_max_in_row(vector> & row_vals) { + if (row_vals.size() == 0) + return; + T max_val = numeric_traits::zero(); + int max_index = 0; + for (unsigned i = row_vals.size(); i-- > 0;) { + T iabs = abs(row_vals[i].m_value); + if (iabs > max_val) { + max_val = iabs; + max_index = i; + } + } + put_max_index_to_0(row_vals, max_index); + } + + bool pivot_with_eta(unsigned i, eta_matrix *eta_matrix, lp_settings & settings) { + T pivot = eta_matrix->get_diagonal_element(); + for (auto it = eta_matrix->get_sparse_vector_iterator(); !it.done(); it.move()) { + if (!pivot_row_to_row(i, it.value(), it.index(), settings)) + return false; + } + divide_row_by_constant(i, pivot, settings); + if (!shorten_active_matrix(i, eta_matrix)) { + return false; + } + + return true; + } + + void scan_row_to_work_vector(unsigned row, unsigned pivot_column) { + for (auto & iv : m_rows[row]) { + if (iv.m_index != pivot_column) { + m_work_pivot_vector.set_value(iv.m_value, iv.m_index); + } + } + } + + // This method pivots row i to row i0 by muliplying row i by + // alpha and adding it to row i0. + // After pivoting the row i0 has a max abs value set correctly at the beginning of m_start, + // Returns false if the resulting row is all zeroes, and true otherwise + bool pivot_row_to_row(unsigned i, T alpha, unsigned i0, lp_settings & settings ) { + lean_assert(i < dimension() && i0 < dimension()); + lean_assert(i != i0); + unsigned pivot_col = adjust_column(i); + i = adjust_row(i); + i0 = adjust_row(i0); + scan_row_to_work_vector(i0, pivot_col); + + auto & row_vals = m_rows[i]; + // lean_assert(row_vals.size() > 0); + for (auto & iv : row_vals) { + unsigned j = iv.m_index; + if (j == pivot_col) continue; + T work_array_at_j = m_work_pivot_vector[j]; + if (numeric_traits::is_zero(work_array_at_j)) { + T val = alpha * iv.m_value; + if (settings.abs_val_is_smaller_than_drop_tolerance(val)) { + continue; + } + m_work_pivot_vector.set_value(val, j); + } else { // the index is already inside + // lean_assert(std::find(m_work_pivot_vector.m_index.begin(), + // m_work_pivot_vector.m_index.end(), j) != m_work_pivot_vector.m_index.end()); + T val = alpha * iv.m_value + work_array_at_j; + if (settings.abs_val_is_smaller_than_drop_tolerance(val)) { + m_work_pivot_vector[j] = numeric_traits::zero(); + } else { + m_work_pivot_vector[j] = val; + } + } + } + +#ifndef NDEBUG + lean_assert(numeric_traits::is_zero(m_work_pivot_vector[pivot_col])); +#endif + if (!set_row_from_work_vector_and_clean_work_vector(i0)) { + return false; + } + return true; + } + + // set the max val as well + // returns false if the resulting row is all zeroes, and true otherwise + bool set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned i0, indexed_vector & work_vec, + lp_settings & settings) { + remove_zero_elements_and_set_data_on_existing_elements_not_adjusted(i0, work_vec, settings); + // all non-zero elements in m_work_pivot_vector are new + for (unsigned j : work_vec.m_index) { + if (numeric_traits::is_zero(work_vec[j])) { + continue; + } + lean_assert(!settings.abs_val_is_smaller_than_drop_tolerance(work_vec[j])); + add_new_element(i0, adjust_column(j), work_vec[j]); + work_vec[j] = numeric_traits::zero(); + } + work_vec.m_index.clear(); + auto & row_vals = m_rows[i0]; + if (row_vals.size() == 0) { + return false; + } + set_max_in_row(row_vals); // it helps to find larger pivots + return true; + } + + + // set the max val as well + // returns false if the resulting row is all zeroes, and true otherwise + bool set_row_from_work_vector_and_clean_work_vector(unsigned i0) { + remove_zero_elements_and_set_data_on_existing_elements(i0); + // all non-zero elements in m_work_pivot_vector are new + for (unsigned j : m_work_pivot_vector.m_index) { + if (numeric_traits::is_zero(m_work_pivot_vector[j])) { + continue; + } + add_new_element(i0, j, m_work_pivot_vector[j]); + m_work_pivot_vector[j] = numeric_traits::zero(); + } + m_work_pivot_vector.m_index.clear(); + auto & row_vals = m_rows[i0]; + if (row_vals.size() == 0) { + return false; + } + set_max_in_row(row_vals); // it helps to find larger pivots + return true; + } + + void remove_zero_elements_and_set_data_on_existing_elements(unsigned row) { + auto & row_vals = m_rows[row]; + for (unsigned k = row_vals.size(); k-- > 0;) { // we cannot simply run the iterator since we are removing + // elements from row_vals + auto & row_el_iv = row_vals[k]; + unsigned j = row_el_iv.m_index; + if (is_zero(m_work_pivot_vector[j])) { + remove_element(row_vals, row_el_iv); + } else { + m_columns[j].m_values[row_el_iv.m_other].set_value(m_work_pivot_vector[j]); + row_el_iv.set_value(m_work_pivot_vector[j]); + m_work_pivot_vector[j] = zero_of_type(); + } + } + } + + // work_vec here has not adjusted column indices + void remove_zero_elements_and_set_data_on_existing_elements_not_adjusted(unsigned row, indexed_vector & work_vec, lp_settings & settings) { + auto & row_vals = m_rows[row]; + for (unsigned k = row_vals.size(); k-- > 0;) { // we cannot simply run the iterator since we are removing + // elements from row_vals + auto & row_el_iv = row_vals[k]; + unsigned j = row_el_iv.m_index; + unsigned rj = adjust_column_inverse(j); + T val = work_vec[rj]; + if (settings.abs_val_is_smaller_than_drop_tolerance(val)) { + remove_element(row_vals, row_el_iv); + lean_assert(numeric_traits::is_zero(val)); + } else { + m_columns[j].m_values[row_el_iv.m_other].set_value(row_el_iv.m_value = val); + work_vec[rj] = numeric_traits::zero(); + } + } + } + + + void multiply_from_right(permutation_matrix& p) { + // m_dense = m_dense * p; + m_column_permutation.multiply_by_permutation_from_right(p); + // lean_assert(*this == m_dense); + } + + void multiply_from_left(permutation_matrix& p) { + // m_dense = p * m_dense; + m_row_permutation.multiply_by_permutation_from_left(p); + // lean_assert(*this == m_dense); + } + + void multiply_from_left_with_reverse(permutation_matrix& p) { + // m_dense = p * m_dense; + m_row_permutation.multiply_by_permutation_reverse_from_left(p); + // lean_assert(*this == m_dense); + } + + // adding delta columns at the end of the matrix + void add_columns_at_the_end(unsigned delta) { + for (unsigned i = 0; i < delta; i++) { + col_header col_head; + m_columns.push_back(col_head); + } + m_column_permutation.enlarge(delta); + } + + void delete_column(int i) { + lean_assert(i < dimension()); + for (auto cell = m_columns[i].m_head; cell != nullptr;) { + auto next_cell = cell->m_down; + kill_cell(cell); + cell = next_cell; + } + } + + bool is_a_unit_matrix() { + for (int i = 0; i < m_rows.size(); i++) { + auto * cell = m_rows[i]->m_head; + if (cell == nullptr || cell->m_j != i || cell->m_value != 1 || cell->m_right != nullptr) { + return false; + } + } + return true; + } + + void swap_columns(unsigned a, unsigned b) { + // cout << "swaapoiiin" << endl; + // dense_matrix d(*this); + m_column_permutation.transpose_from_left(a, b); + // d.swap_columns(a, b); + // lean_assert(*this == d); + } + + void swap_rows(unsigned a, unsigned b) { + m_row_permutation.transpose_from_right(a, b); + // m_dense.swap_rows(a, b); + // lean_assert(*this == m_dense); + } + + void divide_row_by_constant(unsigned i, T & t, lp_settings & settings) { + lean_assert(!settings.abs_val_is_smaller_than_zero_tolerance(t)); + i = adjust_row(i); + for (auto & iv : m_rows[i]) { + T v = iv.m_value / t; + if (settings.abs_val_is_smaller_than_drop_tolerance(v)){ + v = numeric_traits::zero(); + } + m_columns[iv.m_index].m_values[iv.m_other].set_value(iv.m_value = v); + } + } + + T dot_product_with_column(T const * y, unsigned j) { + lean_assert(j < dimension()); + T ret = numeric_traits::zero(); + auto & mc = m_columns[adjust_column(j)].m_chunk; + for (int i = mc.m_length - 1; i >= 0; i--) { + auto & iv = mc.m_start[i]; + ret += y[m_row_permutation.apply_reverse(iv.m_index)] * iv.m_value; + } + return ret; + } + + bool close(T a, T b) { + return // (numeric_traits::precise() && numeric_traits::is_zero(a - b)) + // || + fabs(numeric_traits::get_double(a - b)) < 0.0000001; + } + + // solving x * this = y, and putting the answer into y + // the matrix here has to be upper triangular + void solve_y_U(std::vector & y) const { // works by rows +#ifndef NDEBUG + // T * rs = clone_vector(y, dimension()); +#endif + unsigned end = dimension() - 1; + for (unsigned i = 0; i < end; i++) { + // all y[i] has correct values already + const T & yv = y[i]; + if (numeric_traits::is_zero(yv)) continue; + auto & mc = get_row_values(adjust_row(i)); + for (auto & c : mc) { + unsigned col = adjust_column_inverse(c.m_index); + if (col != i) { + y[col] -= c.m_value * yv; + } + } + } +#ifndef NDEBUG + // dense_matrix deb(*this); + // T * clone_y = clone_vector(y, dimension()); + // deb.apply_from_right(clone_y); + // lean_assert(vectors_are_equal(rs, clone_y, dimension())); + // delete [] clone_y; + // delete [] rs; +#endif + } + + // fills the indices for such that y[i] can be not a zero + // sort them so the smaller indices come first + void fill_reachable_indices(std::set & rset, T *y) { + // std::queue q; + // int m = dimension(); + // for (int i = m - 1; i >= 0; i--) { + // if (!numeric_traits::is_zero(y[i])){ + // for (cell * c = m_columns[adjust_column(i)].m_head; c != nullptr; c = c->m_down) { + // unsigned row = adjust_row_inverse(c->m_i); + // q.push(row); + // } + // } + // } + // while (!q.empty()) { + // unsigned i = q.front(); + // q.pop(); + // for (cell * c = m_columns[adjust_column(i)].m_head; c != nullptr; c = c->m_down) { + // unsigned row = adjust_row_inverse(c->m_i); + // if (rset.find(row) == rset.end()){ + // rset.insert(row); + // q.push(row); + // } + // } + // } + } + + // solving this * x = y, and putting the answer into y + // the matrix here has to be upper triangular + void solve_U_y_(T * y) { // the row wise version +#ifndef NDEBUG + // T * rs = clone_vector(y, dimension()); +#endif + lean_assert(dimension() == dimension()); + for (int i = dimension() - 2 ; i >= 0; i--) { + auto & mc = get_row_values(adjust_row(i)); + for (auto & c : mc) { + unsigned col = m_column_permutation[c.m_index]; + lean_assert(col > i || (col == i && close(c.m_value, numeric_traits::one()))); + if (col == i) { + continue; + } + y[i] -= y[col] * c.m_value; + } + } +#ifndef NDEBUG + // dense_matrix deb(*this); + // T * clone_y = clone_vector(y, dimension()); + // deb.apply_from_left(clone_y); + // lean_assert(vectors_are_equal(rs, clone_y, dimension())); + // delete [] rs; + // delete [] clone_y; +#endif + } + // solving this * x = y, and putting the answer into y + // the matrix here has to be upper triangular + void solve_U_y(T * y) { // the columns have to be correct - it is a column wise version +#ifndef NDEBUG + // T * rs = clone_vector(y, dimension()); +#endif + for (unsigned j = dimension() - 1; j > 0; j--) { + T yj = y[j]; + if (numeric_traits::is_zero(yj)) continue; + auto & mc = m_columns[adjust_column(j)].m_values; + for (auto & iv : mc) { + unsigned i = adjust_row_inverse(iv.m_index); + if (i != j) { + y[i] -= iv.m_value * yj; + } + } + } +#ifndef NDEBUG + // dense_matrix deb(*this); + // T * clone_y = clone_vector(y, dimension()); + // deb.apply_from_left(clone_y); + // lean_assert(vectors_are_equal(rs, clone_y, dimension())); +#endif + } + + template + void find_error_in_solution_U_y(vector& y_orig, vector & y) { + unsigned i = dimension(); + while (i--) { + y_orig[i] -= dot_product_with_row(i, y); + } + } + + template + void add_delta_to_solution(const vector& del, vector & y) { + unsigned i = dimension(); + while (i--) { + y[i] += del[i]; + } + } + + template + void double_solve_U_y(vector& y){ + vector y_orig(y); // copy y aside + solve_U_y(y); + find_error_in_solution_U_y(y_orig, y); + // y_orig contains the error now + solve_U_y(y_orig); + add_delta_to_solution(y_orig, y); + } + // solving this * x = y, and putting the answer into y + // the matrix here has to be upper triangular + template + void solve_U_y(std::vector & y) { // it is a column wise version +#ifndef NDEBUG + // T * rs = clone_vector(y, dimension()); +#endif + + for (unsigned j = dimension(); j--; ) { + const L & yj = y[j]; + if (is_zero(yj)) continue; + auto & mc = m_columns[adjust_column(j)].m_values; + for (auto & iv : mc) { + unsigned i = adjust_row_inverse(iv.m_index); + if (i != j) { + y[i] -= iv.m_value * yj; + } + } + } +#ifndef NDEBUG + // dense_matrix deb(*this); + // T * clone_y = clone_vector(y, dimension()); + // deb.apply_from_left(clone_y); + // lean_assert(vectors_are_equal(rs, clone_y, dimension())); +#endif + } + +#ifndef NDEBUG + T get_elem(unsigned i, unsigned j) const { return get(i, j); } + unsigned get_number_of_rows() const { return dimension(); } + unsigned get_number_of_columns() const { return dimension(); } + virtual void set_number_of_rows(unsigned /*m*/) { } + virtual void set_number_of_columns(unsigned /*n*/) { } +#endif + template + L dot_product_with_row (unsigned row, const vector & y) const { + L ret = zero_of_type(); + auto & mc = get_row_values(adjust_row(row)); + for (auto & c : mc) { + unsigned col = m_column_permutation[c.m_index]; + ret += c.m_value * y[col]; + } + return ret; + } + + unsigned get_number_of_nonzeroes() const { + unsigned ret = 0; + for (unsigned i = dimension(); i--; ) { + ret += number_of_non_zeroes_in_row(i); + } + return ret; + } + + unsigned get_number_of_nonzeroes_below_row(unsigned row) const { + unsigned ret = 0; + for (unsigned i = dimension() - 1; + static_cast(i) >= static_cast(row); i--) { + ret += number_of_non_zeroes_in_row(adjust_row(i)); + } + return ret; + } + + bool get_non_zero_column_in_row(unsigned i, unsigned *j) const { + // go over the i-th row + auto & mc = get_row_values(adjust_row(i)); + if (mc.size() > 0) { + *j = m_column_permutation[mc[0].m_index]; + return true; + } + return false; + } + + void remove_element_that_is_not_in_w(vector> & column_vals, indexed_value & col_el_iv) { + auto & row_chunk = m_rows[col_el_iv.m_index]; + indexed_value & row_el_iv = row_chunk[col_el_iv.m_other]; + unsigned index_in_row = col_el_iv.m_other; + remove_element(row_chunk, col_el_iv.m_other, column_vals, row_el_iv.m_other); + if (index_in_row == 0) + set_max_in_row(row_chunk); + } + + + // w contains the new column + // the old column inside of the matrix has not been changed yet + void remove_elements_that_are_not_in_w_and_update_common_elements(unsigned column_to_replace, indexed_vector & w) { + // -------------------------------- + // column_vals represents the old column + auto & column_vals = m_columns[column_to_replace].m_values; + for (unsigned k = column_vals.size(); k-- > 0;) { + indexed_value & col_el_iv = column_vals[k]; + unsigned i = col_el_iv.m_index; + T w_data_at_i = w[adjust_row_inverse(i)]; + if (numeric_traits::is_zero(w_data_at_i)) { + remove_element_that_is_not_in_w(column_vals, col_el_iv); + } else { + auto& row_chunk = m_rows[i]; + unsigned index_in_row = col_el_iv.m_other; + if (index_in_row == 0) { + bool look_for_max = abs(w_data_at_i) < abs(row_chunk[0].m_value); + row_chunk[0].set_value(col_el_iv.m_value = w_data_at_i); + if (look_for_max) + set_max_in_row(i); + } else { + row_chunk[index_in_row].set_value(col_el_iv.m_value = w_data_at_i); + if (abs(w_data_at_i) > abs(row_chunk[0].m_value)) + put_max_index_to_0(row_chunk, index_in_row); + } + w[adjust_row_inverse(i)] = numeric_traits::zero(); + } + } + } + + void add_new_element(unsigned row, unsigned col, T val) { + auto & row_vals = m_rows[row]; + auto & col_vals = m_columns[col].m_values; + unsigned row_el_offs = row_vals.size(); + unsigned col_el_offs = col_vals.size(); + row_vals.push_back(indexed_value(val, col, col_el_offs)); + col_vals.push_back(indexed_value(val, row, row_el_offs)); + } + + // w contains the "rest" of the new column; all common elements of w and the old column has been zeroed + // the old column inside of the matrix has not been changed yet + void add_new_elements_of_w_and_clear_w(unsigned column_to_replace, indexed_vector & w, lp_settings & settings) { + for (unsigned i : w.m_index) { + T w_at_i = w[i]; + if (numeric_traits::is_zero(w_at_i)) continue; // was dealt with already + if (!settings.abs_val_is_smaller_than_drop_tolerance(w_at_i)) { + unsigned ai = adjust_row(i); + add_new_element(ai, column_to_replace, w_at_i); + auto & row_chunk = m_rows[ai]; + lean_assert(row_chunk.size() > 0); + if (abs(w_at_i) > abs(row_chunk[0].m_value)) + put_max_index_to_0(row_chunk, row_chunk.size() - 1); + } + w[i] = numeric_traits::zero(); + } + w.m_index.clear(); + } + + void replace_column(unsigned column_to_replace, indexed_vector & w, lp_settings &settings) { + column_to_replace = adjust_column(column_to_replace); + remove_elements_that_are_not_in_w_and_update_common_elements(column_to_replace, w); + add_new_elements_of_w_and_clear_w(column_to_replace, w, settings); + } + + T const & get_max_in_row(unsigned row) const { + return m_rows[adjust_row(row)][0].m_value; + } + + T const & get_max_in_row_without_adjusting(unsigned row) const { + return m_rows[row][0].m_value; + } + + + unsigned pivot_score(unsigned i, unsigned j) { + // It goes like this (rnz-1)(cnz-1) is the Markovitz number, that is the max number of + // new non zeroes we can obtain after the pivoting. + // In addition we will get another cnz - 1 elements in the eta matrix created for this pivot, + // which gives rnz(cnz-1). For example, is 0 for a column singleton, but not for + // a row singleton ( which is not a column singleton). + + auto col_header = m_columns[j]; + + return get_row_values(i).size() * (col_header.m_values.size() - col_header.m_shortened_markovitz - 1); + } + + void enqueue_domain_into_pivot_queue() { + lean_assert(m_pivot_queue.size() == 0); + for (unsigned i = 0; i < dimension(); i++) { + auto & rh = m_rows[i]; + unsigned rnz = rh.size(); + for (auto iv : rh) { + unsigned j = iv.m_index; + m_pivot_queue.enqueue(i, j, rnz * (m_columns[j].m_values.size() - 1)); + } + } + } + + void set_max_in_rows() { + unsigned i = dimension(); + while (i--) + set_max_in_row(i); + } + + + void zero_shortened_markovitz_numbers() { + for (auto & ch : m_columns) + ch.zero_shortened_markovitz(); + } + + void prepare_for_factorization() { + zero_shortened_markovitz_numbers(); + set_max_in_rows(); + enqueue_domain_into_pivot_queue(); + } + + void recover_pivot_queue(vector & rejected_pivots) { + for (auto p : rejected_pivots) { + m_pivot_queue.enqueue(p.first, p.second, pivot_score(p.first, p.second)); + } + } + + int elem_is_too_small(unsigned i, unsigned j, const T & c_partial_pivoting) { + auto & row_chunk = m_rows[i]; + + if (j == row_chunk[0].m_index) { + return 0; // the max element is at the head + } + T max = abs(row_chunk[0].m_value); + for (unsigned k = 1; k < row_chunk.size(); k++) { + auto &iv = row_chunk[k]; + if (iv.m_index == j) + return abs(iv.m_value) * c_partial_pivoting < max ? 1: 0; + } + return 2; // the element became zero but it still sits in the active pivots? + cout << "column " << j << " does not belong to row " << i << endl; + throw "cannot be here"; + } + + bool remove_row_from_active_pivots_and_shorten_columns(unsigned row) { + unsigned arow = adjust_row(row); + for (auto & iv : m_rows[arow]) { + m_pivot_queue.remove(arow, iv.m_index); + if (adjust_column_inverse(iv.m_index) <= row) + continue; // this column will be removed anyway + auto & col = m_columns[iv.m_index]; + + col.shorten_markovich_by_one(); + if (col.m_values.size() <= col.m_shortened_markovitz) + return false; // got a zero column + } + return true; + } + + void remove_pivot_column(unsigned row) { + unsigned acol = adjust_column(row); + for (auto & iv : m_columns[acol].m_values) + if (adjust_row_inverse(iv.m_index) >= row) + m_pivot_queue.remove(iv.m_index, acol); + } + + void update_active_pivots(unsigned row) { + unsigned arow = adjust_row(row); + for (auto & iv : m_rows[arow]) { + col_header & ch = m_columns[iv.m_index]; + int cols = ch.m_values.size() - ch.m_shortened_markovitz - 1; + lean_assert(cols >= 0); + for (auto &ivc : ch.m_values) { + unsigned i = ivc.m_index; + if (adjust_row_inverse(i) <= row) continue; // the i is not an active row + m_pivot_queue.enqueue(i, iv.m_index, m_rows[i].size()*cols); + } + } + } + + bool shorten_active_matrix(unsigned row, eta_matrix *eta_matrix) { + if (!remove_row_from_active_pivots_and_shorten_columns(row)) + return false; + remove_pivot_column(row); + // need to know the max priority of the queue here + update_active_pivots(row); + if (eta_matrix == nullptr) return true; + // it looks like double work, but the pivot scores have changed for all rows + // touched by eta_matrix + for (auto it = eta_matrix->get_sparse_vector_iterator(); !it.done(); it.move()) { + unsigned row = adjust_row(it.index()); + auto & row_values = m_rows[row]; + unsigned rnz = row_values.size(); + for (auto & iv : row_values) { + col_header& ch = m_columns[iv.m_index]; + int cnz = ch.m_values.size() - ch.m_shortened_markovitz - 1; + lean_assert(cnz >= 0); + m_pivot_queue.enqueue(row, iv.m_index, rnz * cnz); + } + } + + return true; + } + + unsigned pivot_score_without_shortened_counters(unsigned i, unsigned j, unsigned k) { + auto &cols = m_columns[j].m_values; + unsigned cnz = cols.size(); + for (auto & iv : cols) { + if (adjust_row_inverse(iv.m_index) < k) + cnz--; + } + lean_assert(cnz > 0); + return m_rows[i].m_values.size() * (cnz - 1); + } +#ifndef NDEBUG + bool can_improve_score_for_row(unsigned row, unsigned score, T const & c_partial_pivoting, unsigned k) { + unsigned arow = adjust_row(row); + auto & row_vals = m_rows[arow].m_values; + auto & begin_iv = row_vals[0]; + T row_max = abs(begin_iv.m_value); + lean_assert(adjust_column_inverse(begin_iv.m_index) >= k); + if (pivot_score_without_shortened_counters(arow, begin_iv.m_index, k) < score) { + print_active_matrix(k); + return true; + } + for (unsigned jj = 1; jj < row_vals.size(); jj++) { + auto & iv = row_vals[jj]; + lean_assert(adjust_column_inverse(iv.m_index) >= k); + lean_assert(abs(iv.m_value) <= row_max); + if (c_partial_pivoting * abs(iv.m_value) < row_max) continue; + if (pivot_score_without_shortened_counters(arow, iv.m_index, k) < score) { + print_active_matrix(k); + return true; + } + } + return false; + } + bool really_best_pivot(unsigned i, unsigned j, T const & c_partial_pivoting, unsigned k) { + unsigned queue_pivot_score = pivot_score_without_shortened_counters(i, j, k); + for (unsigned ii = k; ii < dimension(); ii++) { + lean_assert(!can_improve_score_for_row(ii, queue_pivot_score, c_partial_pivoting, k)); + } + return true; + } + void print_active_matrix(unsigned k) { + cout << "active matrix for k = " << k << endl; + if (k >= dimension()) { + cout << "empty" << endl; + return; + } + unsigned dim = dimension() - k; + dense_matrix b(dim, dim); + for (unsigned i = 0; i < dim; i++) + for (unsigned j = 0; j < dim; j++ ) + b.set_elem(i, j, zero_of_type()); + for (int i = k; i < dimension(); i++) { + unsigned col = adjust_column(i); + for (auto &iv : get_column_values(col)) { + unsigned row = iv.m_index; + unsigned row_ex = this->adjust_row_inverse(row); + if (row_ex < k) continue; + auto v = this->get_not_adjusted(row, col); + b.set_elem(row_ex - k, i -k, v); + } + } + print_matrix(b); + } +#endif + bool pivot_queue_is_correct_for_row(unsigned i, unsigned k) { + unsigned arow = adjust_row(i); + for (auto & iv : m_rows[arow].m_values) { + lean_assert(pivot_score_without_shortened_counters(arow, iv.m_index, k + 1) == + m_pivot_queue.get_priority(arow, iv.m_index)); + } + return true; + } + + bool pivot_queue_is_correct_after_pivoting(int k) { + for (unsigned i = k + 1; i < dimension(); i++ ) + lean_assert(pivot_queue_is_correct_for_row(i, k)); + lean_assert(m_pivot_queue.is_correct()); + return true; + } + + + bool get_pivot_for_column(unsigned &i, unsigned &j, T const & c_partial_pivoting, unsigned k) { + vector pivots_candidates_that_are_too_small; + while (!m_pivot_queue.is_empty()) { + m_pivot_queue.dequeue(i, j); + unsigned i_inv = adjust_row_inverse(i); + if (i_inv < k) continue; + unsigned j_inv = adjust_column_inverse(j); + if (j_inv < k) continue; + int small = elem_is_too_small(i, j, c_partial_pivoting); + if (!small) { +#ifndef NDEBUG + // if (!really_best_pivot(i, j, c_partial_pivoting, k)) { + // print_active_matrix(k); + // lean_assert(false); + // } +#endif + + recover_pivot_queue(pivots_candidates_that_are_too_small); + i = i_inv; + j = j_inv; + return true; + } + if (small != 2) // 2 means that the pair is not in the matrix + pivots_candidates_that_are_too_small.emplace_back(i, j); + } + recover_pivot_queue(pivots_candidates_that_are_too_small); + return false; + /* + unsigned m = dimension(); + unsigned markovitz_number_min = m * m; + unsigned iterations = 0; + for (unsigned k = 2; k <= m; k++){ + if (markovitz_number_min < (k-1) * (k-1)) + return true; + + if (get_pivot_in_k_short_columns(k, markovitz_number_min, i, j, c_partial_pivoting, iterations) + || + get_pivot_in_k_short_rows(k, markovitz_number_min, i, j, c_partial_pivoting, iterations)) { + return true; + } + if (iterations > search_depth * 2 && markovitz_number_min < m * m) + return true; + } + return markovitz_number_min < m * m; + */ + } + + bool elem_is_too_small(vector> & row_chunk, indexed_value & iv, T const & c_partial_pivoting) { + if (&iv == &row_chunk[0]) { + return false; // the max element is at the head + } + T val = abs(iv.m_value); + T max = abs(row_chunk[0].m_value); + return val * c_partial_pivoting < max; + } + + unsigned number_of_non_zeros_in_row(unsigned row) const { + return m_rows[row].m_values.size(); + } + + unsigned number_of_non_zeros_in_column(unsigned col) const { + return m_columns[col].m_values.size(); + } + + + + bool shorten_columns_by_pivot_row(unsigned i, unsigned pivot_column) { + vector> & row_chunk = get_row_values(i); + + for (indexed_value & iv : row_chunk) { + unsigned j = iv.m_index; + if (j == pivot_column) { + lean_assert(!col_is_active(j)); + continue; + } + m_columns[j].shorten_markovich_by_one(); + + if (m_columns[j].m_shortened_markovitz >= get_column_values(j).size()) { // got the zero column under the row! + return false; + } + } + return true; + } + + bool col_is_active(unsigned j, unsigned pivot) { + return adjust_column_inverse(j) > pivot; + } + + bool row_is_active(unsigned i, unsigned pivot) { + return adjust_row_inverse(i) > pivot; + } + + void fill_eta_matrix(unsigned j, eta_matrix ** eta) { + vector> & col_chunk = get_column_values(adjust_column(j)); + bool is_unit = true; + for (auto & iv : col_chunk) { + unsigned i = adjust_row_inverse(iv.m_index); + if (i > j) { + is_unit = false; + break; + } + if (i == j && iv.m_value != 1) { + is_unit = false; + break; + } + } + + if (is_unit) { + *eta = nullptr; + return; + } + +#ifndef NDEBUG + *eta = new eta_matrix(j, dimension()); +#else + *eta = new eta_matrix(j); +#endif + for (auto & iv : col_chunk) { + unsigned i = adjust_row_inverse(iv.m_index); + if (i < j) { + continue; + } + if (i > j) { + (*eta)->push_back(i, - iv.m_value); + } else { // i == j + (*eta)->set_diagonal_element(iv.m_value); + } + } + (*eta)->divide_by_diagonal_element(); + } + + bool is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings & settings) const { + for (unsigned i = 0; i < dimension(); i++) { + vector> const & row_chunk = get_row_values(i); + lean_assert(row_chunk.size()); + T const & max = abs(row_chunk[0].m_value); + unsigned ai = adjust_row_inverse(i); + for (auto & iv : row_chunk) { + lean_assert(abs(iv.m_value) <= max); + unsigned aj = adjust_column_inverse(iv.m_index); + if (!(ai <= aj || numeric_traits::is_zero(iv.m_value))) + return false; + if (aj == ai) { + if (iv.m_value != 1) { + cout << "value at diagonal = " << iv.m_value << endl; + return false; + } + } + if (settings.abs_val_is_smaller_than_drop_tolerance(iv.m_value) && (!is_zero(iv.m_value))) + return false; + } + } + return true; + } + + bool is_upper_triangular_until(unsigned k) const { + for (unsigned j = 0; j < dimension() && j < k; j++) { + unsigned aj = adjust_column(j); + auto & col = get_column_values(aj); + for (auto & iv : col) { + unsigned row = adjust_row_inverse(iv.m_index); + if (row > j) + return false; + } + } + return true; + } + + + + void check_column_vs_rows(unsigned col) { + auto & mc = get_column_values(col); + for (indexed_value & column_iv : mc) { + indexed_value & row_iv = column_iv_other(column_iv); + if (row_iv.m_index != col) { + cout << "m_other in row does not belong to column " << col << ", but to column " << row_iv.m_index << endl; + lean_assert(false); + } + + if (& row_iv_other(row_iv) != &column_iv) { + cout << "row and col do not point to each other" << endl; + lean_assert(false); + } + + if (row_iv.m_value != column_iv.m_value) { + cout << "the data from col " << col << " for row " << column_iv.m_index << " is different in the column " << endl; + cout << "in the col it is " << column_iv.m_value << ", but in the row it is " << row_iv.m_value << endl; + lean_assert(false); + } + } + } + + void check_row_vs_columns(unsigned row) { + auto & mc = get_row_values(row); + for (indexed_value & row_iv : mc) { + indexed_value & column_iv = row_iv_other(row_iv); + + if (column_iv.m_index != row) { + cout << "col_iv does not point to correct row " << row << " but to " << column_iv.m_index << endl; + lean_assert(false); + } + + if (& row_iv != & column_iv_other(column_iv)) { + cout << "row and col do not point to each other" << endl; + lean_assert(false); + } + + if (row_iv.m_value != column_iv.m_value) { + cout << "the data from col " << column_iv.m_index << " for row " << row << " is different in the column " << endl; + cout << "in the col it is " << column_iv.m_value << ", but in the row it is " << row_iv.m_value << endl; + lean_assert(false); + } + } + } + + void check_rows_vs_columns() { + for (unsigned i = 0; i < dimension(); i++) { + check_row_vs_columns(i); + } + } + + void check_columns_vs_rows() { + for (unsigned i = 0; i < dimension(); i++) { + check_column_vs_rows(i); + } + } + + void map_domain_to_vector(unordered_map, unsigned> & domain, vector> & vec) { + lean_assert(domain.size() == 0 && vec.size() == 0); + for (unsigned i = 0; i < dimension(); i++) { + vector> & row = get_row_values(i); + for (auto & iv : row) { + unsigned j = iv.m_index; + unsigned nz = vec.size(); + pair p(i, j); + domain[p] = nz; + vec.push_back(p); + } + } + } + +#ifndef NDEBUG + void check_matrix() { + check_rows_vs_columns(); + check_columns_vs_rows(); + } +#endif +}; +}; diff --git a/src/util/lp/sparse_vector.h b/src/util/lp/sparse_vector.h new file mode 100644 index 0000000000..37e33a387c --- /dev/null +++ b/src/util/lp/sparse_vector.h @@ -0,0 +1,93 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/debug.h" +#include "util/numerics/numeric_traits.h" +#include "util/numerics/xnumeral.h" +#include "util/numerics/mpq.h" +#include "util/numerics/mpz.h" +#include "util/numerics/mpbq.h" +#include "util/numerics/double.h" +#include "util/numerics/float.h" +#include "util/numerics/mpfp.h" +#include "util/lp/lp_settings.h" +namespace lean { +using std::vector; +using std::pair; +template +void zero_vector(T * t, unsigned size) { + while (size-- > 0) { // it can be made faster by copying big chunks + t[size] = numeric_traits::zero(); + } +} + +template +T abs (T const & v) { return v >= zero_of_type() ? v : -v; } + + +template +class sparse_vector_iterator; // forward definition + +template +class sparse_vector { +public: + vector> m_data; + void push_back(unsigned index, T val) { + m_data.emplace_back(index, val); + } +#ifndef NDEBUG + T operator[] (unsigned i) const { + for (auto t : m_data) { + if (t.first == i) return t.second; + } + return numeric_traits::zero(); + } +#endif + + void divide(T const & a) { + lean_assert(!lp_settings::is_eps_small_general(a, 1e-12)); + for (auto & t : m_data) { + t.second /= a; + } + } + + unsigned size() const { + return m_data.size(); + } + + friend sparse_vector_iterator; +}; + +template +class sparse_vector_iterator { + typedef typename vector< pair >::iterator p_it; + p_it m_it; + p_it m_end; +public: + sparse_vector_iterator(sparse_vector & s_v) : m_it(s_v.m_data.begin()), + m_end(s_v.m_data.end()) { + } + + bool done() { + return m_it == m_end; + } + + void move() { + m_it++; + } + + unsigned index() { + return m_it->first; + } + + const T & value() const { + return m_it->second; + } +}; +} diff --git a/src/util/lp/square_dense_submatrix.h b/src/util/lp/square_dense_submatrix.h new file mode 100644 index 0000000000..e4e1f72d04 --- /dev/null +++ b/src/util/lp/square_dense_submatrix.h @@ -0,0 +1,434 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/numerics/float.h" +#include "util/lp/permutation_matrix.h" +#include +#include "util/lp/static_matrix.h" +#include +#include +#include +#include +#include +#include "util/lp/indexed_value.h" +#include "util/lp/indexed_vector.h" +#include +#include "util/lp/lp_settings.h" +#include "util/lp/eta_matrix.h" +#include "util/lp/binary_heap_upair_queue.h" +namespace lean { +using std::vector; +using std::cout; +template +class square_dense_submatrix : public tail_matrix { + // the submatrix uses the permutations of the parent matrix to access the elements + struct ref { + unsigned m_i_offset; + square_dense_submatrix & m_s; + ref(unsigned i, square_dense_submatrix & s) : + m_i_offset((i - s.m_index_start) * s.m_dim), m_s(s){} + T & operator[] (unsigned j) { + lean_assert(j >= m_s.m_index_start); + return m_s.m_v[m_i_offset + m_s.adjust_column(j) - m_s.m_index_start]; + } + const T & operator[] (unsigned j) const { + lean_assert(j >= m_s.m_index_start); + return m_s.m_v[m_i_offset + m_s.adjust_column(j) - m_s.m_index_start]; + } + }; +public: // debug + unsigned m_index_start; + unsigned m_dim; + vector m_v; + sparse_matrix * m_parent = nullptr; + permutation_matrix m_row_permutation; +public: + permutation_matrix m_column_permutation; + bool is_active() const { return m_parent != nullptr; } + + square_dense_submatrix() {} + + square_dense_submatrix (sparse_matrix *parent_matrix, unsigned index_start) : + m_index_start(index_start), + m_dim(parent_matrix->dimension() - index_start), + m_v(m_dim * m_dim), + m_parent(parent_matrix), + m_row_permutation(m_parent->dimension()), + m_column_permutation(m_parent->dimension()) { + int row_offset = - static_cast(m_index_start); + for (unsigned i = index_start; i < parent_matrix->dimension(); i++) { + unsigned row = parent_matrix->adjust_row(i); + for (auto & iv : parent_matrix->get_row_values(row)) { + unsigned j = parent_matrix->adjust_column_inverse(iv.m_index); + lean_assert(j>= m_index_start); + m_v[row_offset + j] = iv.m_value; + } + row_offset += m_dim; + } + } + + void init(sparse_matrix *parent_matrix, unsigned index_start) { + m_index_start = index_start; + m_dim = parent_matrix->dimension() - index_start; + m_v.resize(m_dim * m_dim); + m_parent = parent_matrix; + m_column_permutation.init(m_parent->dimension()); + for (unsigned i = index_start; i < parent_matrix->dimension(); i++) { + unsigned row = parent_matrix->adjust_row(i); + for (auto & iv : parent_matrix->get_row_values(row)) { + unsigned j = parent_matrix->adjust_column_inverse(iv.m_index); + (*this)[i][j] = iv.m_value; + } + } + } + + ref operator[] (unsigned i) { + lean_assert(i >= m_index_start); + lean_assert(i < m_parent->dimension()); + return ref(i, *this); + } + + int find_pivot_column_in_row(unsigned i) const { + int j = -1; + T max = zero_of_type(); + lean_assert(i >= m_index_start); + unsigned row_start = (i - m_index_start) * m_dim; + for (unsigned k = i; k < m_parent->dimension(); k++) { + unsigned col = adjust_column(k); // this is where the column is in the row + unsigned offs = row_start + col - m_index_start; + T t = abs(m_v[offs]); + if (t > max) { + j = k; + max = t; + } + } + return j; + } + + void swap_columns(unsigned i, unsigned j) { + if (i == j) return; + m_column_permutation.transpose_from_left(i, j); + } + + unsigned adjust_column(unsigned col) const{ + return m_column_permutation.apply_reverse(col); + } + + unsigned adjust_column_inverse(unsigned col) const{ + return m_column_permutation[col]; + } + unsigned adjust_row(unsigned row) const{ + return m_row_permutation[row]; + } + + unsigned adjust_row_inverse(unsigned row) const{ + return m_row_permutation.apply_reverse(row); + } + + void pivot(unsigned i, lp_settings & settings) { + divide_row_by_pivot(i); + for (unsigned k = i + 1; k < m_parent->dimension(); k++) + pivot_row_to_row(i, k, settings); + } + + void pivot_row_to_row(unsigned i, unsigned row, lp_settings & settings) { + lean_assert(i < row); + unsigned pj = adjust_column(i); // the pivot column + unsigned pjd = pj - m_index_start; + unsigned pivot_row_offset = (i-m_index_start)*m_dim; + T pivot = m_v[pivot_row_offset + pjd]; + unsigned row_offset= (row-m_index_start)*m_dim; + T m = m_v[row_offset + pjd]; + lean_assert(!is_zero(pivot)); + m_v[row_offset + pjd] = -m * pivot; // creating L matrix + for (unsigned j = m_index_start; j < m_parent->dimension(); j++) { + if (j == pj) { + pivot_row_offset++; + row_offset++; + continue; + } + auto t = m_v[row_offset] - m_v[pivot_row_offset] * m; + if (settings.abs_val_is_smaller_than_drop_tolerance(t)) { + m_v[row_offset] = zero_of_type(); + } else { + m_v[row_offset] = t; + } + row_offset++; pivot_row_offset++; + // at the same time we pivot the L too + } + } + + void divide_row_by_pivot(unsigned i) { + unsigned pj = adjust_column(i); // the pivot column + unsigned irow_offset = (i - m_index_start) * m_dim; + T pivot = m_v[irow_offset + pj - m_index_start]; + lean_assert(!is_zero(pivot)); + for (unsigned k = m_index_start; k < m_parent->dimension(); k++) { + if (k == pj){ + m_v[irow_offset++] = one_of_type() / pivot; // creating the L matrix diagonal + continue; + } + m_v[irow_offset++] /= pivot; + } + } + + void update_parent_matrix(lp_settings & settings) { + for (unsigned i = m_index_start; i < m_parent->dimension(); i++) + update_existing_or_delete_in_parent_matrix_for_row(i, settings); + push_new_elements_to_parent_matrix(settings); + for (unsigned i = m_index_start; i < m_parent->dimension(); i++) + m_parent->set_max_in_row(m_parent->adjust_row(i)); + } + + void update_existing_or_delete_in_parent_matrix_for_row(unsigned i, lp_settings & settings) { + bool diag_updated = false; + unsigned ai = m_parent->adjust_row(i); + auto & row_vals = m_parent->get_row_values(ai); + for (unsigned k = 0; k < row_vals.size(); k++) { + auto & iv = row_vals[k]; + unsigned j = m_parent->adjust_column_inverse(iv.m_index); + if (j < i) { + m_parent->remove_element(row_vals, iv); + k--; + } else if (i == j) { + m_parent->m_columns[iv.m_index].m_values[iv.m_other].set_value(iv.m_value = one_of_type()); + diag_updated = true; + } else { // j > i + T & v = (*this)[i][j]; + if (settings.abs_val_is_smaller_than_drop_tolerance(v)) { + m_parent->remove_element(row_vals, iv); + k--; + } else { + m_parent->m_columns[iv.m_index].m_values[iv.m_other].set_value(iv.m_value = v); + v = zero_of_type(); // only new elements are left above the diagonal + } + } + } + if (!diag_updated) { + unsigned aj = m_parent->adjust_column(i); + m_parent->add_new_element(ai, aj, one_of_type()); + } + } + + void push_new_elements_to_parent_matrix(lp_settings & settings) { + for (unsigned i = m_index_start; i < m_parent->dimension() - 1; i++) { + unsigned ai = m_parent->adjust_row(i); + for (unsigned j = i + 1; j < m_parent->dimension(); j++) { + T & v = (*this)[i][j]; + if (!settings.abs_val_is_smaller_than_drop_tolerance(v)) { + unsigned aj = m_parent->adjust_column(j); + m_parent->add_new_element(ai, aj, v); + } + v = zero_of_type(); // leave only L elements now + } + } + } + template + L row_by_vector_product(unsigned i, const vector & v) { + lean_assert(i >= m_index_start); + + unsigned row_in_subm = i - m_index_start; + unsigned row_offset = row_in_subm * m_dim; + L r = zero_of_type(); + for (unsigned j = 0; j < m_dim; j++) + r += m_v[row_offset + j] * v[adjust_column_inverse(m_index_start + j)]; + return r; + } + + template + L column_by_vector_product(unsigned j, const vector & v) { + lean_assert(j >= m_index_start); + + unsigned offset = j - m_index_start; + L r = zero_of_type(); + for (unsigned i = 0; i < m_dim; i++, offset += m_dim) + r += m_v[offset] * v[adjust_row_inverse(m_index_start + i)]; + return r; + } + + template + L row_by_indexed_vector_product(unsigned i, const indexed_vector & v) { + lean_assert(i >= m_index_start); + + unsigned row_in_subm = i - m_index_start; + unsigned row_offset = row_in_subm * m_dim; + L r = zero_of_type(); + for (unsigned j = 0; j < m_dim; j++) + r += m_v[row_offset + j] * v[adjust_column_inverse(m_index_start + j)]; + return r; + } + + template + void apply_from_left_local(indexed_vector & w, lp_settings & settings) { +#ifndef NDEBUG + // dense_matrix deb(*this); + // vector deb_w(w.m_data.size()); + // for (unsigned i = 0; i < w.m_data.size(); i++) + // deb_w[i] = w[i]; + + // deb.apply_from_left(deb_w); +#endif // use indexed vector here + +#ifndef DO_NOT_USE_INDEX + vector t(m_parent->dimension(), zero_of_type()); + for (auto k : w.m_index) { + unsigned j = adjust_column(k); // k-th element will contribute only to column j + if (j < m_index_start) { + t[adjust_row_inverse(j)] = w[k]; + } else { + const L & v = w[k]; + for (unsigned i = 0; i < m_dim; i++) { + unsigned row = adjust_row_inverse(m_index_start + i); + unsigned offs = i * m_dim + j - m_index_start; + t[row] += m_v[offs] * v; + } + } + } + w.m_index.clear(); + for (unsigned i = 0; i < m_parent->dimension(); i++) { + const L & v = t[i]; + if (!settings.abs_val_is_smaller_than_drop_tolerance(v)){ + w.m_index.push_back(i); + w.m_data[i] = v; + } else { + w.m_data[i] = zero_of_type(); + } + } +#else + vector t(m_parent->dimension()); + for (unsigned i = 0; i < m_index_start; i++) { + t[adjust_row_inverse(i)] = w[adjust_column_inverse(i)]; + } + for (unsigned i = m_index_start; i < m_parent->dimension(); i++){ + t[adjust_row_inverse(i)] = row_by_indexed_vector_product(i, w); + } + for (unsigned i = 0; i < m_parent->dimension(); i++) { + w.set_value(t[i], i); + } + for (unsigned i = 0; i < m_parent->dimension(); i++) { + const L & v = t[i]; + if (!is_zero(v)) + w.m_index.push_back(i); + w.m_data[i] = v; + } +#endif +#ifndef NDEBUG + // cout << "w final" << endl; + // print_vector(w.m_data); + // lean_assert(vectors_are_equal(deb_w, w.m_data)); + // lean_assert(w.is_OK()); +#endif + } + + template + void apply_from_left_to_vector(vector & w) { + // lp_settings & settings) { + // dense_matrix deb(*this); + // vector deb_w(w); + // deb.apply_from_left_to_X(deb_w, settings); + // // cout << "deb" << endl; + // // print_matrix(deb); + // // cout << "w" << endl; + // // print_vector(w.m_data); + // // cout << "deb_w" << endl; + // // print_vector(deb_w); + vector t(m_parent->dimension()); + for (unsigned i = 0; i < m_index_start; i++) { + t[adjust_row_inverse(i)] = w[adjust_column_inverse(i)]; + } + for (unsigned i = m_index_start; i < m_parent->dimension(); i++){ + t[adjust_row_inverse(i)] = row_by_vector_product(i, w); + } + for (unsigned i = 0; i < m_parent->dimension(); i++) { + w[i] = t[i]; + } +#ifndef NDEBUG + // cout << "w final" << endl; + // print_vector(w.m_data); + // lean_assert(vectors_are_equal(deb_w, w)); +#endif + } + + bool is_L_matrix() const { + lean_assert(m_row_permutation.is_identity()); + for (unsigned i = 0; i < m_parent->dimension(); i++) { + if (i < m_index_start) { + lean_assert(m_column_permutation[i] == i); + continue; + } + unsigned row_offs = (i-m_index_start)*m_dim; + for (unsigned k = 0; k < m_dim; k++) { + unsigned j = m_index_start + k; + unsigned jex = adjust_column_inverse(j); + if (jex > i) { + lean_assert(is_zero(m_v[row_offs + k])); + } else if (jex == i) { + lean_assert(!is_zero(m_v[row_offs + k])); + } + } + } + return true; + } + + void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) { + apply_from_left_local(w, settings); + } + + void apply_from_right(indexed_vector & w) { + lean_assert(false); // not implemented + } + void apply_from_left(vector & w, lp_settings & /*settings*/) { + apply_from_left_to_vector(w);// , settings); + } + + void apply_from_right(vector & w) { +#ifndef NDEBUG + // dense_matrix deb(*this); + // vector deb_w(w); + // deb.apply_from_right(deb_w); +#endif + vector t(w.size()); + for (unsigned j = 0; j < m_index_start; j++) { + t[adjust_column_inverse(j)] = w[adjust_row_inverse(j)]; + } + for (unsigned j = m_index_start; j < m_parent->dimension(); j++) { + t[adjust_column_inverse(j)] = column_by_vector_product(j, w); + } + // std::copy(t.begin(), t.end(), w); // does not compile + lean_assert(w.size() == t.size()); + w = t; +#ifndef NDEBUG + // lean_assert(vectors_are_equal(deb_w, w)); +#endif + } + + + + +#ifndef NDEBUG + + T get_elem (unsigned i, unsigned j) const { + i = adjust_row(i); + j = adjust_column(j); + if (i < m_index_start || j < m_index_start) + return i == j? one_of_type() : zero_of_type(); + unsigned offs = (i - m_index_start)* m_dim + j - m_index_start; + return m_v[offs]; + } + unsigned row_count() const { return m_parent->row_count();} + unsigned column_count() const { return row_count();} + void set_number_of_rows(unsigned /* m */) {} + void set_number_of_columns(unsigned /* n */) {}; +#endif + void conjugate_by_permutation(permutation_matrix & q) { + m_row_permutation.multiply_by_permutation_from_left(q); + m_column_permutation.multiply_by_reverse_from_right(q); + } +}; +} diff --git a/src/util/lp/static_matrix.h b/src/util/lp/static_matrix.h new file mode 100644 index 0000000000..c4fee1635b --- /dev/null +++ b/src/util/lp/static_matrix.h @@ -0,0 +1,501 @@ +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once +#include +#include "util/numerics/numeric_traits.h" +#include "util/numerics/xnumeral.h" +#include "util/numerics/mpq.h" +#include "util/numerics/mpz.h" +#include "util/numerics/mpbq.h" +#include "util/numerics/double.h" +#include "util/numerics/float.h" +#include "util/numerics/mpfp.h" +#include +#include "util/lp/sparse_vector.h" +#include +#include +#include "util/lp/matrix_domain.h" +#include "util/lp/indexed_vector.h" + +namespace lean { +template +struct column_cell { + unsigned m_i; // points to the row + unsigned m_offset; // the offset of the element in the matrix row + T m_value; + column_cell(unsigned i, unsigned offset, T v) : m_i(i), m_offset(offset), m_value(v) { + } +}; + +template +class row_cell { +public: + unsigned m_j; // points to the column + unsigned m_offset; // offset in column + row_cell(unsigned j, unsigned offset, T const & val) : m_j(j), m_offset(offset), m_value(val) { + } + const T & get_val() const { return m_value;} + T & get_val() { return m_value;} + void set_val(T v) { + m_value = v; + } +private: + T m_value; +}; + + + + // each assignment for this matrix should be issued only once!!! +template +class static_matrix +#ifndef NDEBUG + : public matrix +#endif +{ +#ifndef NDEBUG + std::set> m_domain; +#endif +public: + typedef vector> row_strip; + typedef vector> column_strip; + vector m_work_pivot_vector; + + vector m_rows; + vector m_columns; + // starting inner classes + class ref { + static_matrix & m_matrix; + unsigned m_row; + unsigned m_col; + public: + ref(static_matrix & m, unsigned row, unsigned col):m_matrix(m), m_row(row), m_col(col) {} + ref & operator=(T const & v) { m_matrix.set( m_row, m_col, v); return *this; } + + ref & operator=(ref const & v) { m_matrix.set(m_row, m_col, v.m_matrix.get(v.m_row, v.m_col)); return *this; } + + operator T () const { return m_matrix.get_elem(m_row, m_col); } + }; + + class ref_row { + static_matrix & m_matrix; + unsigned m_row; + public: + ref_row(static_matrix & m, unsigned row):m_matrix(m), m_row(row) {} + ref operator[](unsigned col) const { return ref(m_matrix, m_row, col); } + }; + +public: + void init_row_columns(unsigned m, unsigned n) { + lean_assert(m_rows.size() == 0 && m_columns.size() == 0); + for (unsigned i = 0; i < m; i++){ + m_rows.push_back(row_strip()); + } + for (unsigned j = 0; j < n; j++){ + m_columns.push_back(column_strip()); + } + } + + // constructor with no parameters + static_matrix() {} + + // constructor + static_matrix(unsigned m, unsigned n): m_work_pivot_vector(m, numeric_traits::zero()) { + init_row_columns(m, n); + } + // constructor that copies columns of the basis from A + static_matrix(static_matrix const &A, unsigned * basis) : + m_work_pivot_vector(A.row_count(), numeric_traits::zero()) { + unsigned m = A.row_count(); + init_row_columns(m, m); + while (m--) { + for (auto & col : A.m_columns[m]){ + set(col.m_i, m, A.get_value_of_column_cell(col)); + } + } + } + + void clear() { + m_work_pivot_vector.clear(); + m_rows.clear(); + m_columns.clear(); +#ifndef NDEBUG + m_domain.clear(); +#endif + } + + void init_work_pivot_vector(unsigned m) { + while (m--) m_work_pivot_vector.push_back(numeric_traits::zero()); + } + + void init_empty_matrix(unsigned m, unsigned n) { + init_work_pivot_vector(m); + init_row_columns(m, n); + } + + unsigned row_count() const { return m_rows.size(); } + + unsigned column_count() const { return m_columns.size(); } + template + L dot_product_with_row(unsigned row, const std::vector & w) { + L ret = zero_of_type(); + lean_assert(row < m_rows.size()); + for (auto & it : m_rows[row]) { + ret += w[it.m_j] * it.get_val(); + } + return ret; + }; + + unsigned lowest_row_in_column(unsigned col) { + lean_assert(col < column_count()); + column_strip & colstrip = m_columns[col]; + lean_assert(colstrip.size() > 0); + unsigned ret = 0; + for (auto & t : colstrip) { + if (t.m_i > ret) { + ret = t.m_i; + } + } + return ret; + } + + T dot_product_with_column(const std::vector & y, unsigned j) const { + lean_assert(j < column_count()); + T ret = numeric_traits::zero(); + for (auto & it : m_columns[j]) { + ret += y[it.m_i] * it.m_value; // get_value_of_column_cell(it); + } + return ret; + } + + void add_columns_at_the_end(unsigned delta) { + for (unsigned i = 0; i < delta; i++) + add_column(); + } + + void add_column() { + m_columns.push_back(column_strip()); + } + + void forget_last_columns(unsigned how_many_to_forget) { + lean_assert(m_columns.size() >= how_many_to_forget); + unsigned j = column_count() - 1; + for (; how_many_to_forget > 0; how_many_to_forget--) { + remove_last_column(j --); + } + } + + void remove_last_column(unsigned j) { + column_strip & col = m_columns.back(); + for (auto & it : col) { + auto & row = m_rows[it.m_i]; + unsigned offset = row.size() - 1; + for (auto row_it = row.rbegin(); row_it != row.rend(); row_it ++) { + if (row_it->m_j == j) { + row.erase(row.begin() + offset); + break; + } + offset--; + } + } + m_columns.pop_back(); + } + + void scale_row(unsigned row, T const & alpha) { + for (auto & t : m_rows[row]) { + t.set_val(t.get_val() * alpha); + m_columns[t.m_j][t.m_offset].m_value *= alpha; + } + } + + void divide_row_by_constant(unsigned row, T const & alpha) { + for (auto & t : m_rows[row]) { + t.set_val(t.get_val() / alpha); + m_columns[t.m_j][t.m_offset].m_value /= alpha; + } + } + + void scale_column(unsigned column, T const & alpha) { + for (auto & t : m_columns[column]) { + t.m_value *= alpha; + auto & r = m_rows[t.m_i][t.m_offset]; + r.set_val(r.get_val() *= alpha); + } + } + +#ifndef NDEBUG + void regen_domain() { + m_domain.clear(); + for (int i = 0; i < m_rows.size(); i++){ + for (auto & t : m_rows[i]) { + m_domain.insert(std::make_pair(i, t.m_j)); + } + } + } +#endif + + // offs - offset in columns + row_cell make_row_cell(unsigned row, unsigned offs, T const & val) { + row_cell r(row, offs, val); + return r; + } + + column_cell make_column_cell(unsigned column, unsigned offset, T const & val) { + column_cell r(column, offset, val); + return r; + } + + void set(unsigned row, unsigned col, T const & val) { + if (numeric_traits::is_zero(val)) return; + lean_assert(row < row_count() && col < column_count()); +#ifndef NDEBUG + pair p(row, col); + lean_assert(m_domain.find(p) == m_domain.end()); + m_domain.insert(p); +#endif + auto & r = m_rows[row]; + unsigned offs_in_cols = m_columns[col].size(); + m_columns[col].push_back(make_column_cell(row, r.size(), val)); + r.push_back(make_row_cell(col, offs_in_cols, val)); + } + + ref operator()(unsigned row, unsigned col) { return ref(*this, row, col); } + + std::set> get_domain() { + std::set> ret; + for (unsigned i = 0; i < m_rows.size(); i++) { + for (auto it : m_rows[i]) { + ret.insert(std::make_pair(i, it.m_j)); + } + } + return ret; + } + + + void copy_column_to_vector (unsigned j, indexed_vector & v) const { + lean_assert(j < m_columns.size()); + for (auto & it : m_columns[j]) { + if (!is_zero(it.m_value)) + v.set_value(it.m_value, it.m_i); + } + } + void copy_column_to_vector (unsigned j, vector & v) const { + v.resize(row_count(), numeric_traits::zero()); + for (auto & it : m_columns[j]) { + if (!is_zero(it.m_value)) + v[it.m_i]=it.m_value; + } + } + + void add_column_to_vector (const T & a, unsigned j, T * v) const { + for (auto & it : m_columns[j]) { + v[it.m_i] += a * it.m_value; + } + } + + T get_max_abs_in_row(unsigned row) const { + T ret = numeric_traits::zero(); + for (auto & t : m_rows[row]) { + T a = abs(t.get_val()); + if (a > ret) { + ret = a; + } + } + return ret; + } + + T get_min_abs_in_row(unsigned row) const { + bool first_time = true; + T ret = numeric_traits::zero(); + for (auto & t : m_rows[row]) { + T a = abs(t.get_val()); + if (first_time) { + ret = a; + first_time = false; + } else if (a < ret) { + ret = a; + } + } + return ret; + } + + + T get_max_abs_in_column(unsigned column) const { + T ret = numeric_traits::zero(); + for (auto & t : m_columns[column]) { + T a = abs(t.m_value); + if (a > ret) { + ret = a; + } + } + return ret; + } + + T get_min_abs_in_column(unsigned column) const { + bool first_time = true; + T ret = numeric_traits::zero(); + for (auto & t : m_columns[column]) { + T a = abs(t.m_value); + if (first_time) { + first_time = false; + ret = a; + } else if (a < ret) { + ret = a; + } + } + return ret; + } + +#ifndef NDEBUG + void check_consistency() { + unordered_map, T> by_rows; + for (int i = 0; i < m_rows.size(); i++){ + for (auto & t : m_rows[i]) { + pair p(i, t.m_j); + lean_assert(by_rows.find(p) == by_rows.end()); + by_rows[p] = t.get_val(); + } + } + unordered_map, T> by_cols; + for (int i = 0; i < m_columns.size(); i++){ + for (auto & t : m_columns[i]) { + pair p(t.m_i, i); + lean_assert(by_cols.find(p) == by_cols.end()); + by_cols[p] = get_value_of_column_cell(t); + } + } + lean_assert(by_rows.size() == by_cols.size()); + + for (auto & t : by_rows) { + auto ic = by_cols.find(t.first); + if (ic == by_cols.end()){ + cout << "rows have pair (" << t.first.first <<"," << t.first.second << "), but columns don't " << endl; + } + lean_assert(ic != by_cols.end()); + lean_assert(t.second == ic->second); + } + } +#endif + + + void cross_out_row(unsigned k) { +#ifndef NDEBUG + check_consistency(); +#endif + cross_out_row_from_columns(k, m_rows[k]); + fix_row_indices_in_each_column_for_crossed_row(k); + m_rows.erase(m_rows.begin() + k); +#ifndef NDEBUG + regen_domain(); + check_consistency(); +#endif + } + + // + void fix_row_indices_in_each_column_for_crossed_row(unsigned k) { + for (unsigned j = 0; j < m_columns.size(); j++) { + auto & col = m_columns[j]; + for (int i = 0; i < col.size(); i++) { + if (col[i].m_i > k) { + col[i].m_i--; + } + } + } + } + + void cross_out_row_from_columns(unsigned k, row_strip & row) { + for (auto & t : row) { + cross_out_row_from_column(t.m_j, k); + } + } + + void cross_out_row_from_column(unsigned col, unsigned k) { + auto & s = m_columns[col]; + for (unsigned i = 0; i < s.size(); i++) { + if (s[i].m_i == k) { + s.erase(s.begin() + i); + break; + } + } + } + + T get_elem(unsigned i, unsigned j) const { // should not be used in efficient code !!!! + for (auto & t : m_rows[i]) { + if (t.m_j == j) { + return t.get_val(); + } + } + return numeric_traits::zero(); + } + + + unsigned number_of_non_zeroes_in_column(unsigned j) const { + return m_columns[j].size(); + } + + unsigned number_of_non_zeroes_in_row(unsigned i) const { + return m_rows[i].number_of_non_zeros(); + } + + void scan_row_to_work_vector(unsigned i) { + for (auto & rc : m_rows[i]) { + m_work_pivot_vector[rc.m_j] = rc.get_val(); + } + } + + void clean_row_work_vector(unsigned i) { + for (auto & rc : m_rows[i]) { + m_work_pivot_vector[rc.m_j] = numeric_traits::zero(); + } + } + + +#ifndef NDEBUG + unsigned get_number_of_rows() const { return row_count(); } + unsigned get_number_of_columns() const { return column_count(); } + virtual void set_number_of_rows(unsigned /*m*/) { } + virtual void set_number_of_columns(unsigned /*n*/) { } +#endif + // const T & get_value_of_column_cell(column_cell const & cc) const { + // lean_assert(cc.m_i < m_rows.size()); + // lean_assert(cc.m_offset < m_rows[cc.m_i].size()); + // return m_rows[cc.m_i][cc.m_offset].get_val(); + // } + + T get_max_val_in_row(unsigned i) const { + lean_assert(false); + throw 0;// not implemented + } + + T get_balance() const { + T ret = zero_of_type(); + for (unsigned i = 0; i < row_count(); i++) { + ret += get_row_balance(i); + } + return ret; + } + + T get_row_balance(unsigned row) const { + T ret = zero_of_type(); + for (auto & t : m_rows[row]) { + if (numeric_traits::is_zero(t.get_val())) continue; + T a = abs(t.get_val()); + numeric_traits::log(a); + ret += a * a; + } + return ret; + } + bool col_val_equal_to_row_val() const { + for (auto & r : m_rows) { + for (auto & rc : r) { + lean_assert(rc.get_val() == m_columns[rc.m_j][rc.m_offset].m_value); + } + } + return true; + } +}; +} diff --git a/src/util/lp/suhl_pivot_chooser.h b/src/util/lp/suhl_pivot_chooser.h new file mode 100644 index 0000000000..5be9527f1c --- /dev/null +++ b/src/util/lp/suhl_pivot_chooser.h @@ -0,0 +1,65 @@ + +/* + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. + + Author: Lev Nachmanson +*/ + +#pragma once + +#include +#include "util/debug.h" +#include "util/numerics/numeric_traits.h" +#include "util/numerics/xnumeral.h" + +#include +#include "util/lp/lp_settings.h" +#include "util/lp/sparse_matrix.h" +#include "util/lp/sparse_vector.h" +#include "util/lp/pivot_chooser_base.h" + + +namespace lean { + // following "Computing Sparse LU Factorizations for Large-Scale Linear Programming Bases", by Suhl, Suhl +template +class suhl_pivot_chooser : public pivot_chooser_base { +// m_U is a square matrix + sparse_matrix & m_U; + lp_settings const & m_settings; +public: +// constructor + suhl_pivot_chooser(sparse_matrix & U, lp_settings const & settings): m_U(U), m_settings(settings) { + lean_assert(U.row_count() == U.column_count()); + } + + bool get_column_singleton(unsigned * i, unsigned *j) { + return m_U.find_column_singleton(i, j); + } + + bool get_row_singleton(unsigned* i, unsigned *j) { + return m_U.find_row_singleton(i, j); + } + + void pivot_update_kernel(unsigned i, unsigned j) { + } + + bool get_pivot_not_adjusted(unsigned *i, unsigned * j) { + if (get_column_singleton(i, j)) { + return true; + } + if (get_row_singleton(i, j)) { + return true; + } + return m_U.get_non_singleton_pivot(i, j, m_settings.depth_of_rook_search, T(m_settings.c_partial_pivoting)); + } + + int get_pivot(unsigned i, unsigned * j) { + if (get_pivot_not_adjusted(&i, j)) { + *j = m_U.adjust_column_inverse(*j); + return m_U.adjust_row_inverse(i); + } + return -1; + } +}; +} diff --git a/src/util/numerics/double.cpp b/src/util/numerics/double.cpp index ba97c6fe7f..143852064d 100644 --- a/src/util/numerics/double.cpp +++ b/src/util/numerics/double.cpp @@ -24,8 +24,6 @@ void double_abs(double & v) { v = std::abs(v); } void double_ceil(double & v) { v = std::ceil(v); } void double_floor(double & v) { v = std::floor(v); } -static double g_zero = 0.0; -double const & numeric_traits::zero() { - return g_zero; -} +double numeric_traits::g_zero = 0.0; +double numeric_traits::g_one = 1.0; }; diff --git a/src/util/numerics/double.h b/src/util/numerics/double.h index 34d4e84e65..45847fab54 100644 --- a/src/util/numerics/double.h +++ b/src/util/numerics/double.h @@ -42,8 +42,10 @@ public: static void neg(double & v) { v = -v; } static void inv(double & v) { v = 1.0/v; } static void reset(double & v) { v = 0.0; } - static double const & zero(); - + static double g_zero; + static double const & zero() { return g_zero; } + static double g_one; + static double const & one() { return g_one; } static void power(double & v, unsigned k) { double_power(v, k); } static void abs(double & v) { double_abs(v); } static void ceil(double & v) { double_ceil(v); } @@ -55,6 +57,8 @@ public: return v1 > v2 ? v1 : v2; } + static double const & get_double(double const & d) { return d;} + // constants static const double constexpr pi_l = (3373259426.0 + 273688.0 / (1<<21)) / (1<<30); static const double constexpr pi_n = (3373259426.0 + 273688.0 / (1<<21)) / (1<<30); diff --git a/src/util/numerics/float.cpp b/src/util/numerics/float.cpp index 04f4d69856..d66af90006 100644 --- a/src/util/numerics/float.cpp +++ b/src/util/numerics/float.cpp @@ -28,4 +28,9 @@ static float g_zero = 0.0; float const & numeric_traits::zero() { return g_zero; } + +static float g_one = 1.0; +float const & numeric_traits::one() { + return g_one; +} }; diff --git a/src/util/numerics/float.h b/src/util/numerics/float.h index 7a11d842e4..bf70d5faaf 100644 --- a/src/util/numerics/float.h +++ b/src/util/numerics/float.h @@ -43,11 +43,13 @@ public: static void inv(float & v) { v = 1.0/v; } static void reset(float & v) { v = 0.0; } static float const & zero(); + static float const & one(); static void power(float & v, unsigned k) { float_power(v, k); } static void abs(float & v) { float_abs(v); } static void ceil(float & v) { float_ceil(v); } static void floor(float & v) { float_floor(v); } + static double get_double(float const & d) { return static_cast(d); } static float const & min(float const & v1, float const & v2) { return v1 < v2 ? v1 : v2; diff --git a/src/util/numerics/mpq.cpp b/src/util/numerics/mpq.cpp index 02ad31fb59..311b39cf95 100644 --- a/src/util/numerics/mpq.cpp +++ b/src/util/numerics/mpq.cpp @@ -137,6 +137,11 @@ mpq const & numeric_traits::zero() { return *g_zero; } +static mpq * g_one = nullptr; +mpq const & numeric_traits::one() { + return *g_one; +} + serializer & operator<<(serializer & s, mpq const & n) { std::ostringstream out; out << n; @@ -146,12 +151,14 @@ serializer & operator<<(serializer & s, mpq const & n) { void initialize_mpq() { g_zero = new mpq(); + g_one = new mpq(1); numeric_traits::initialize(); } void finalize_mpq() { numeric_traits::finalize(); delete g_zero; + delete g_one; } mpq read_mpq(deserializer & d) { diff --git a/src/util/numerics/mpq.h b/src/util/numerics/mpq.h index f3b075f07c..384dfff4ce 100644 --- a/src/util/numerics/mpq.h +++ b/src/util/numerics/mpq.h @@ -239,11 +239,13 @@ public: static void inv(mpq & v) { v.inv(); } static void reset(mpq & v) { v = 0; } static mpq const & zero(); + static mpq const & one(); static void power(mpq & v, unsigned k) { _power(v, v, k); } static void abs(mpq & v) { v.abs(); } static void ceil(mpq & v) { v.ceil(); } static void floor(mpq & v) { v.floor(); } + static double get_double(mpq const & d) { return d.get_double(); } // constants static inline mpq pi_lower() { return *pi_l; }