3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 17:15:31 +00:00

add cube mode

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2017-09-24 10:53:57 -07:00
commit ae9a6664d4
144 changed files with 6012 additions and 3174 deletions

View file

@ -201,7 +201,7 @@ public:
m_todo.push_back(d);
unsigned qhead = 0;
while (qhead < m_todo.size()) {
d = m_todo[qhead];
d = m_todo[qhead];
qhead++;
if (d->is_leaf()) {
vs.push_back(to_leaf(d)->m_value);

View file

@ -236,7 +236,7 @@ template<typename T>
struct ptr_hash {
typedef T * data;
unsigned operator()(T * ptr) const {
return get_ptr_hash(ptr);
return get_ptr_hash(ptr);
}
};

View file

@ -119,12 +119,12 @@ class inf_eps_rational {
bool is_rational() const { return m_infty.is_zero() && m_r.is_rational(); }
int64 get_int64() const {
SASSERT(is_int64());
SASSERT(is_int64());
return m_r.get_int64();
}
uint64 get_uint64() const {
SASSERT(is_uint64());
SASSERT(is_uint64());
return m_r.get_uint64();
}
@ -168,45 +168,45 @@ class inf_eps_rational {
inf_eps_rational & operator=(const inf_eps_rational & r) {
m_infty = r.m_infty;
m_r = r.m_r;
return *this;
return *this;
}
inf_eps_rational & operator=(const Numeral & r) {
m_infty.reset();
m_r = r;
return *this;
return *this;
}
inf_eps_rational & operator+=(const inf_eps_rational & r) {
m_infty += r.m_infty;
m_r += r.m_r;
return *this;
return *this;
}
inf_eps_rational & operator-=(const inf_eps_rational & r) {
m_infty -= r.m_infty;
m_r -= r.m_r;
return *this;
return *this;
}
inf_eps_rational & operator-=(const inf_rational & r) {
m_r -= r;
return *this;
return *this;
}
inf_eps_rational & operator+=(const inf_rational & r) {
m_r += r;
return *this;
return *this;
}
inf_eps_rational & operator+=(const rational & r) {
m_r += r;
return *this;
return *this;
}
inf_eps_rational & operator-=(const rational & r) {
m_r -= r;
return *this;
return *this;
}
inf_eps_rational & operator*=(const rational & r1) {

View file

@ -110,12 +110,12 @@ class inf_int_rational {
bool is_rational() const { return m_second == 0; }
int64 get_int64() const {
SASSERT(is_int64());
SASSERT(is_int64());
return m_first.get_int64();
}
uint64 get_uint64() const {
SASSERT(is_uint64());
SASSERT(is_uint64());
return m_first.get_uint64();
}
@ -132,7 +132,7 @@ class inf_int_rational {
inf_int_rational & operator=(const inf_int_rational & r) {
m_first = r.m_first;
m_second = r.m_second;
return *this;
return *this;
}
inf_int_rational & operator=(const rational & r) {
@ -154,7 +154,7 @@ class inf_int_rational {
inf_int_rational & operator+=(const inf_int_rational & r) {
m_first += r.m_first;
m_second += r.m_second;
return *this;
return *this;
}
inf_int_rational & operator*=(const rational & r) {
@ -163,7 +163,7 @@ class inf_int_rational {
}
m_first *= r;
m_second *= r.get_int32();
return *this;
return *this;
}
@ -171,17 +171,17 @@ class inf_int_rational {
inf_int_rational & operator-=(const inf_int_rational & r) {
m_first -= r.m_first;
m_second -= r.m_second;
return *this;
return *this;
}
inf_int_rational & operator+=(const rational & r) {
m_first += r;
return *this;
return *this;
}
inf_int_rational & operator-=(const rational & r) {
m_first -= r;
return *this;
return *this;
}
inf_int_rational & operator++() {

View file

@ -123,12 +123,12 @@ class inf_rational {
bool is_rational() const { return m_second.is_zero(); }
int64 get_int64() const {
SASSERT(is_int64());
SASSERT(is_int64());
return m_first.get_int64();
}
uint64 get_uint64() const {
SASSERT(is_uint64());
SASSERT(is_uint64());
return m_first.get_uint64();
}
@ -145,7 +145,7 @@ class inf_rational {
inf_rational & operator=(const inf_rational & r) {
m_first = r.m_first;
m_second = r.m_second;
return *this;
return *this;
}
inf_rational & operator=(const rational & r) {
@ -167,23 +167,23 @@ class inf_rational {
inf_rational & operator+=(const inf_rational & r) {
m_first += r.m_first;
m_second += r.m_second;
return *this;
return *this;
}
inf_rational & operator-=(const inf_rational & r) {
m_first -= r.m_first;
m_second -= r.m_second;
return *this;
return *this;
}
inf_rational & operator+=(const rational & r) {
m_first += r;
return *this;
return *this;
}
inf_rational & operator-=(const rational & r) {
m_first -= r;
return *this;
return *this;
}
inf_rational & operator*=(const rational & r1) {

View file

@ -67,7 +67,7 @@ class inf_s_integer {
inf_s_integer & operator=(const inf_s_integer & r) {
m_first = r.m_first;
m_second = r.m_second;
return *this;
return *this;
}
inf_s_integer & operator=(const rational & r) {
m_first = static_cast<int>(r.get_int64());
@ -90,20 +90,20 @@ class inf_s_integer {
inf_s_integer & operator+=(const inf_s_integer & r) {
m_first += r.m_first;
m_second += r.m_second;
return *this;
return *this;
}
inf_s_integer & operator-=(const inf_s_integer & r) {
m_first -= r.m_first;
m_second -= r.m_second;
return *this;
return *this;
}
inf_s_integer & operator+=(const s_integer & r) {
m_first += r.get_int();
return *this;
return *this;
}
inf_s_integer & operator-=(const s_integer & r) {
m_first -= r.get_int();
return *this;
return *this;
}
inf_s_integer & operator*=(const s_integer & r1) {
m_first *= r1.get_int();

View file

@ -1,392 +0,0 @@
/*
Copyright (c) 2017 Microsoft Corporation
Author: Lev Nachmanson
*/
// this is a part of lp_primal_core_solver that deals with the tableau
#include "util/lp/lp_primal_core_solver.h"
namespace lp {
template <typename T, typename X> void lp_primal_core_solver<T, X>::one_iteration_tableau() {
int entering = choose_entering_column_tableau();
if (entering == -1) {
decide_on_status_when_cannot_find_entering();
}
else {
advance_on_entering_tableau(entering);
}
lp_assert(this->inf_set_is_correct());
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::advance_on_entering_tableau(int entering) {
X t;
int leaving = find_leaving_and_t_tableau(entering, t);
if (leaving == -1) {
this->set_status(lp_status::UNBOUNDED);
return;
}
advance_on_entering_and_leaving_tableau(entering, leaving, t);
}
/*
template <typename T, typename X> int lp_primal_core_solver<T, X>::choose_entering_column_tableau_rows() {
int i = find_inf_row();
if (i == -1)
return -1;
return find_shortest_beneficial_column_in_row(i);
}
*/
template <typename T, typename X> int lp_primal_core_solver<T, X>::choose_entering_column_tableau() {
//this moment m_y = cB * B(-1)
unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter();
lp_assert(numeric_traits<T>::precise());
if (number_of_benefitial_columns_to_go_over == 0)
return -1;
if (this->m_basis_sort_counter == 0) {
sort_non_basis();
this->m_basis_sort_counter = 20;
}
else {
this->m_basis_sort_counter--;
}
unsigned j_nz = this->m_m() + 1; // this number is greater than the max column size
std::list<unsigned>::iterator entering_iter = m_non_basis_list.end();
for (auto non_basis_iter = m_non_basis_list.begin(); number_of_benefitial_columns_to_go_over && non_basis_iter != m_non_basis_list.end(); ++non_basis_iter) {
unsigned j = *non_basis_iter;
if (!column_is_benefitial_for_entering_basis(j))
continue;
// if we are here then j is a candidate to enter the basis
unsigned t = this->m_A.number_of_non_zeroes_in_column(j);
if (t < j_nz) {
j_nz = t;
entering_iter = non_basis_iter;
if (number_of_benefitial_columns_to_go_over)
number_of_benefitial_columns_to_go_over--;
}
else if (t == j_nz && this->m_settings.random_next() % 2 == 0) {
entering_iter = non_basis_iter;
}
}// while (number_of_benefitial_columns_to_go_over && initial_offset_in_non_basis != offset_in_nb);
if (entering_iter == m_non_basis_list.end())
return -1;
unsigned entering = *entering_iter;
m_sign_of_entering_delta = this->m_d[entering] > 0 ? 1 : -1;
if (this->m_using_infeas_costs && this->m_settings.use_breakpoints_in_feasibility_search)
m_sign_of_entering_delta = -m_sign_of_entering_delta;
m_non_basis_list.erase(entering_iter);
m_non_basis_list.push_back(entering);
return entering;
}
template <typename T, typename X>
unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
init_run_tableau();
if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) {
this->set_status(lp_status::FEASIBLE);
return 0;
}
if ((!numeric_traits<T>::precise()) && this->A_mult_x_is_off()) {
this->set_status(lp_status::FLOATING_POINT_ERROR);
return 0;
}
do {
if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over((this->m_using_infeas_costs? "inf t" : "feas t"), * this->m_settings.get_message_ostream())) {
return this->total_iterations();
}
if (this->m_settings.use_tableau_rows()) {
one_iteration_tableau_rows();
}
else
one_iteration_tableau();
switch (this->get_status()) {
case lp_status::OPTIMAL: // double check that we are at optimum
case lp_status::INFEASIBLE:
if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible())
break;
if (!numeric_traits<T>::precise()) {
if(this->m_look_for_feasible_solution_only)
break;
this->init_lu();
if (this->m_factorization->get_status() != LU_status::OK) {
this->set_status(lp_status::FLOATING_POINT_ERROR);
break;
}
init_reduced_costs();
if (choose_entering_column(1) == -1) {
decide_on_status_when_cannot_find_entering();
break;
}
this->set_status(lp_status::UNKNOWN);
} else { // precise case
if ((!this->infeasibility_costs_are_correct())) {
init_reduced_costs_tableau(); // forcing recalc
if (choose_entering_column_tableau() == -1) {
decide_on_status_when_cannot_find_entering();
break;
}
this->set_status(lp_status::UNKNOWN);
}
}
break;
case lp_status::TENTATIVE_UNBOUNDED:
this->init_lu();
if (this->m_factorization->get_status() != LU_status::OK) {
this->set_status(lp_status::FLOATING_POINT_ERROR);
break;
}
init_reduced_costs();
break;
case lp_status::UNBOUNDED:
if (this->current_x_is_infeasible()) {
init_reduced_costs();
this->set_status(lp_status::UNKNOWN);
}
break;
case lp_status::UNSTABLE:
lp_assert(! (numeric_traits<T>::precise()));
this->init_lu();
if (this->m_factorization->get_status() != LU_status::OK) {
this->set_status(lp_status::FLOATING_POINT_ERROR);
break;
}
init_reduced_costs();
break;
default:
break; // do nothing
}
} while (this->get_status() != lp_status::FLOATING_POINT_ERROR
&&
this->get_status() != lp_status::UNBOUNDED
&&
this->get_status() != lp_status::OPTIMAL
&&
this->get_status() != lp_status::INFEASIBLE
&&
this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements
&&
this->total_iterations() <= this->m_settings.max_total_number_of_iterations
&&
!(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only));
lp_assert(this->get_status() == lp_status::FLOATING_POINT_ERROR
||
this->current_x_is_feasible() == false
||
this->calc_current_x_is_feasible_include_non_basis());
return this->total_iterations();
}
template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_entering_and_leaving_tableau(int entering, int leaving, X & t) {
CASSERT("A_off", this->A_mult_x_is_off() == false);
lp_assert(leaving >= 0 && entering >= 0);
lp_assert((this->m_settings.simplex_strategy() ==
simplex_strategy_enum::tableau_rows) ||
m_non_basis_list.back() == static_cast<unsigned>(entering));
lp_assert(this->m_using_infeas_costs || !is_neg(t));
lp_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes
if (entering == leaving) {
advance_on_entering_equal_leaving_tableau(entering, t);
return;
}
if (!is_zero(t)) {
if (this->current_x_is_feasible() || !this->m_settings.use_breakpoints_in_feasibility_search ) {
if (m_sign_of_entering_delta == -1)
t = -t;
}
this->update_basis_and_x_tableau(entering, leaving, t);
CASSERT("A_off", this->A_mult_x_is_off() == false);
this->iters_with_no_cost_growing() = 0;
} else {
this->pivot_column_tableau(entering, this->m_basis_heading[leaving]);
this->change_basis(entering, leaving);
}
if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible())
return;
if (this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows) {
if (need_to_switch_costs()) {
this->init_reduced_costs_tableau();
}
lp_assert(!need_to_switch_costs());
std::list<unsigned>::iterator it = m_non_basis_list.end();
it--;
* it = static_cast<unsigned>(leaving);
}
}
template <typename T, typename X>
void lp_primal_core_solver<T, X>::advance_on_entering_equal_leaving_tableau(int entering, X & t) {
CASSERT("A_off", !this->A_mult_x_is_off() );
this->update_x_tableau(entering, t * m_sign_of_entering_delta);
if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible())
return;
if (need_to_switch_costs()) {
init_reduced_costs_tableau();
}
this->iters_with_no_cost_growing() = 0;
}
template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_and_t_tableau(unsigned entering, X & t) {
unsigned k = 0;
bool unlimited = true;
unsigned row_min_nz = this->m_n() + 1;
m_leaving_candidates.clear();
auto & col = this->m_A.m_columns[entering];
unsigned col_size = col.size();
for (;k < col_size && unlimited; k++) {
const column_cell & c = col[k];
unsigned i = c.m_i;
const T & ed = this->m_A.get_val(c);
lp_assert(!numeric_traits<T>::is_zero(ed));
unsigned j = this->m_basis[i];
limit_theta_on_basis_column(j, - ed * m_sign_of_entering_delta, t, unlimited);
if (!unlimited) {
m_leaving_candidates.push_back(j);
row_min_nz = this->m_A.m_rows[i].size();
}
}
if (unlimited) {
if (try_jump_to_another_bound_on_entering_unlimited(entering, t))
return entering;
return -1;
}
X ratio;
for (;k < col_size; k++) {
const column_cell & c = col[k];
unsigned i = c.m_i;
const T & ed = this->m_A.get_val(c);
lp_assert(!numeric_traits<T>::is_zero(ed));
unsigned j = this->m_basis[i];
unlimited = true;
limit_theta_on_basis_column(j, -ed * m_sign_of_entering_delta, ratio, unlimited);
if (unlimited) continue;
unsigned i_nz = this->m_A.m_rows[i].size();
if (ratio < t) {
t = ratio;
m_leaving_candidates.clear();
m_leaving_candidates.push_back(j);
row_min_nz = i_nz;
} else if (ratio == t && i_nz < row_min_nz) {
m_leaving_candidates.clear();
m_leaving_candidates.push_back(j);
row_min_nz = this->m_A.m_rows[i].size();
} else if (ratio == t && i_nz == row_min_nz) {
m_leaving_candidates.push_back(j);
}
}
ratio = t;
unlimited = false;
if (try_jump_to_another_bound_on_entering(entering, t, ratio, unlimited)) {
t = ratio;
return entering;
}
if (m_leaving_candidates.size() == 1)
return m_leaving_candidates[0];
k = this->m_settings.random_next() % m_leaving_candidates.size();
return m_leaving_candidates[k];
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::init_run_tableau() {
// print_matrix(&(this->m_A), std::cout);
CASSERT("A_off", this->A_mult_x_is_off() == false);
lp_assert(basis_columns_are_set_correctly());
this->m_basis_sort_counter = 0; // to initiate the sort of the basis
this->set_total_iterations(0);
this->iters_with_no_cost_growing() = 0;
lp_assert(this->inf_set_is_correct());
if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)
return;
if (this->m_settings.backup_costs)
backup_and_normalize_costs();
m_epsilon_of_reduced_cost = numeric_traits<X>::precise() ? zero_of_type<T>() : T(1) / T(10000000);
if (this->m_settings.use_breakpoints_in_feasibility_search)
m_breakpoint_indices_queue.resize(this->m_n());
if (!numeric_traits<X>::precise()) {
this->m_column_norm_update_counter = 0;
init_column_norms();
}
if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows)
init_tableau_rows();
lp_assert(this->reduced_costs_are_correct_tableau());
lp_assert(!this->need_to_pivot_to_basis_tableau());
}
template <typename T, typename X> bool lp_primal_core_solver<T, X>::
update_basis_and_x_tableau(int entering, int leaving, X const & tt) {
lp_assert(this->use_tableau());
update_x_tableau(entering, tt);
this->pivot_column_tableau(entering, this->m_basis_heading[leaving]);
this->change_basis(entering, leaving);
return true;
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::
update_x_tableau(unsigned entering, const X& delta) {
this->add_delta_to_x_and_call_tracker(entering, delta);
if (!this->m_using_infeas_costs) {
for (const auto & c : this->m_A.m_columns[entering]) {
unsigned i = c.m_i;
this->update_x_with_delta_and_track_feasibility(this->m_basis[i], - delta * this->m_A.get_val(c));
}
} else { // m_using_infeas_costs == true
lp_assert(this->column_is_feasible(entering));
lp_assert(this->m_costs[entering] == zero_of_type<T>());
// m_d[entering] can change because of the cost change for basic columns.
for (const auto & c : this->m_A.m_columns[entering]) {
unsigned i = c.m_i;
unsigned j = this->m_basis[i];
this->add_delta_to_x_and_call_tracker(j, -delta * this->m_A.get_val(c));
update_inf_cost_for_column_tableau(j);
if (is_zero(this->m_costs[j]))
this->remove_column_from_inf_set(j);
else
this->insert_column_into_inf_set(j);
}
}
CASSERT("A_off", this->A_mult_x_is_off() == false);
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::
update_inf_cost_for_column_tableau(unsigned j) {
lp_assert(this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows);
lp_assert(this->m_using_infeas_costs);
T new_cost = get_infeasibility_cost_for_column(j);
T delta = this->m_costs[j] - new_cost;
if (is_zero(delta))
return;
this->m_costs[j] = new_cost;
update_reduced_cost_for_basic_column_cost_change(delta, j);
}
template <typename T, typename X> void lp_primal_core_solver<T, X>::init_reduced_costs_tableau() {
if (this->current_x_is_infeasible() && !this->m_using_infeas_costs) {
init_infeasibility_costs();
} else if (this->current_x_is_feasible() && this->m_using_infeas_costs) {
if (this->m_look_for_feasible_solution_only)
return;
this->m_costs = m_costs_backup;
this->m_using_infeas_costs = false;
}
unsigned size = this->m_basis_heading.size();
for (unsigned j = 0; j < size; j++) {
if (this->m_basis_heading[j] >= 0)
this->m_d[j] = zero_of_type<T>();
else {
T& d = this->m_d[j] = this->m_costs[j];
for (auto & cc : this->m_A.m_columns[j]) {
d -= this->m_costs[this->m_basis[cc.m_i]] * this->m_A.get_val(cc);
}
}
}
}
}

View file

@ -135,7 +135,7 @@ public:
value const& get(key const& k, value const& default_value) const {
entry* e = find_core(k);
if (e) {
return e->get_data().m_value;
return e->get_data().m_value;
}
else {
return default_value;

View file

@ -1217,12 +1217,18 @@ void mpf_manager::to_sbv_mpq(mpf_rounding_mode rm, const mpf & x, scoped_mpq & o
default: UNREACHABLE();
}
if (inc) m_mpz_manager.inc(z);
TRACE("mpf_dbg_sbv",
tout << "SBV: (" << to_string(x) << ") == " << m_mpq_manager.to_string(z) << std::endl;
tout << "sign=" << t.sign() << " last=" << last << " round=" << round <<
" sticky=" << sticky << " inc=" << inc << std::endl; );
}
else
m_mpz_manager.mul2k(z, (unsigned) e);
m_mpq_manager.set(o, z);
if (x.sign) m_mpq_manager.neg(o);
TRACE("mpf_dbg", tout << "SBV = " << m_mpq_manager.to_string(o) << std::endl;);
}
void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) {
@ -1248,6 +1254,8 @@ void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) {
m_mpz_manager.mul2k(o, sbits - 1);
m_mpz_manager.add(o, sig(x), o);
}
TRACE("mpf_dbg", tout << "IEEE_BV = " << m_mpz_manager.to_string(o) << std::endl;);
}
void mpf_manager::renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, mpz & sig) {

View file

@ -422,7 +422,7 @@ inline bool operator>(rational const & r1, rational const & r2) {
}
inline bool operator<(rational const & r1, int r2) {
return r1 < rational(r2);
return r1 < rational(r2);
}
inline bool operator<=(rational const & r1, rational const & r2) {
@ -450,11 +450,11 @@ inline rational operator+(rational const & r1, rational const & r2) {
}
inline rational operator+(int r1, rational const & r2) {
return rational(r1) + r2;
return rational(r1) + r2;
}
inline rational operator+(rational const & r1, int r2) {
return r1 + rational(r2);
return r1 + rational(r2);
}
@ -463,11 +463,11 @@ inline rational operator-(rational const & r1, rational const & r2) {
}
inline rational operator-(rational const & r1, int r2) {
return r1 - rational(r2);
return r1 - rational(r2);
}
inline rational operator-(int r1, rational const & r2) {
return rational(r1) - r2;
return rational(r1) - r2;
}
inline rational operator-(rational const & r) {
@ -492,11 +492,11 @@ inline rational operator/(rational const & r1, rational const & r2) {
}
inline rational operator/(rational const & r1, int r2) {
return r1 / rational(r2);
return r1 / rational(r2);
}
inline rational operator/(int r1, rational const & r2) {
return rational(r1) / r2;
inline rational operator/(int r1, rational const & r2) {
return rational(r1) / r2;
}
inline rational power(rational const & r, unsigned p) {

View file

@ -110,7 +110,7 @@ public:
mach_timespec_t _stop;
clock_get_time(m_host_clock, &_stop);
m_time += (_stop.tv_sec - m_start.tv_sec) * 1000000000ull;
m_time += (_stop.tv_nsec - m_start.tv_nsec);
m_time += (_stop.tv_nsec - m_start.tv_nsec);
m_running = false;
}
}
@ -163,8 +163,8 @@ public:
struct timespec _stop;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &_stop);
m_time += (_stop.tv_sec - m_start.tv_sec) * 1000000000ull;
if (m_time != 0 || _stop.tv_nsec >= m_start.tv_nsec)
m_time += (_stop.tv_nsec - m_start.tv_nsec);
if (m_time != 0 || _stop.tv_nsec >= m_start.tv_nsec)
m_time += (_stop.tv_nsec - m_start.tv_nsec);
m_running = false;
}
}

View file

@ -154,13 +154,13 @@ template<class T, size_t N> char (*ArraySizer(T (&)[N]))[N];
template<typename IT>
void display(std::ostream & out, const IT & begin, const IT & end, const char * sep, bool & first) {
for(IT it = begin; it != end; ++it) {
if (first) {
first = false;
}
else {
out << sep;
}
out << *it;
if (first) {
first = false;
}
else {
out << sep;
}
out << *it;
}
}
@ -173,9 +173,9 @@ void display(std::ostream & out, const IT & begin, const IT & end, const char *
template<typename T>
struct delete_proc {
void operator()(T * ptr) {
if (ptr) {
dealloc(ptr);
}
if (ptr) {
dealloc(ptr);
}
}
};