void ast_gen::store_parallel_accesses_for_current_dimension(isl_ast_build * builder) { // Parallel = { [a[i] -> a[j]] -> [[t_i] -> [t_j]] : t_i < t_j } // NOTE: Reduce number of relations by making the relation non-reflexive, // i.e. by relating times with < instead of !=. // NOTE: Since parallel accesses are only used for storage allocation // where only their distances matter, // and the distances remain the same accross periods, // it is sufficient to store accesses for a single period. isl::union_map schedule = isl_ast_build_get_schedule(builder); isl::space schedule_space = isl_ast_build_get_schedule_space(builder); int dimension = schedule_space.dimension(isl::space::output) - 1; auto access_relations = (m_model_summary.read_relations | m_model_summary.write_relations) .in_domain(m_model_summary.domains) .in_range(m_model_summary.array_domains); auto access_schedule = schedule; access_schedule.map_domain_through(access_relations); access_schedule.for_each([&](const isl::map & m) { auto parallel = m.cross(m); // parallel_times: { [i_0 ... i_d] -> [j_0 ... j_d] : i_0 == j_0 ... j_d < j_d } auto sched_relation_space = isl::space::from(schedule_space, schedule_space); auto parallel_times = isl::basic_map::universe(sched_relation_space); for (int i = 0; i < dimension; i++) parallel_times.add_constraint (sched_relation_space.in(i) == sched_relation_space.out(i)); parallel_times.add_constraint (sched_relation_space.in(dimension) < sched_relation_space.out(dimension)); parallel = parallel.in_range(parallel_times.wrapped()); auto parallel_accesses = parallel.domain().unwrapped(); if (parallel_accesses.is_empty()) return true; if (verbose<ast_gen>::enabled()) { cout << " -- Access schedule: " << endl; m_printer.print(m); cout << endl; cout << " => Parallel accesses:" << endl; m_printer.print_each_in(parallel_accesses); } m_model.parallel_accesses |= parallel_accesses; return true; }); }
int main( ) { double x[state_dim+1]; double objective[state_dim+1] = {0, -2.5, -5.0, -3.4}; double ieq_coeff[ieq_dim] = {425, 400, 600}; double ieq_matrix[ieq_dim][state_dim+1] = {{0,2,10,4}, {0,6,5,8}, {0, 7, 10, 8}}; double eq_coeff[eq_dim]; // = {30}; double eq_matrix[eq_dim][state_dim+1]; // lprec *lp; // lp = make_lp(eq_dim+ieq_dim, state_dim); set_obj_fn (lp, objective); for(int i=0; i<ieq_dim; i++) { add_constraint( lp, ieq_matrix[i], LE, ieq_coeff[i] ); } for(int i=0; i<eq_dim; i++) { add_constraint( lp, eq_matrix[i], EQ, eq_coeff[i] ); } // set_verbose(lp, 0); set_presolve(lp, PRESOLVE_ROWS | PRESOLVE_COLS | PRESOLVE_LINDEP, get_presolveloops(lp)); solve(lp); // std::cout << "f : " << get_objective(lp) << std::endl; std::cout << "x :" ; double col0 = get_Norig_columns(lp); double row0 = get_Norig_rows(lp); for(int i = 1; i <= col0; i++) { double _x = get_var_primalresult(lp, row0 + i); std::cout << " " << _x ; } std::cout << std::endl; }
bool ilp_problem_t::add_constraints_of_transitive_unification( term_t t1, term_t t2, term_t t3) { std::string key = util::format("%ld:%ld:%ld", t1.get_hash(), t2.get_hash(), t3.get_hash()); /* IGNORE TRIPLETS WHICH HAVE BEEN CONSIDERED ALREADY. */ if (m_log_of_term_triplet_for_transitive_unification.count(key) > 0) return false; pg::node_idx_t n_t1t2 = m_graph->find_sub_node(t1, t2); pg::node_idx_t n_t2t3 = m_graph->find_sub_node(t2, t3); pg::node_idx_t n_t3t1 = m_graph->find_sub_node(t3, t1); if (n_t1t2 < 0 or n_t2t3 < 0 or n_t3t1 < 0) return false; variable_idx_t v_t1t2 = find_variable_with_node(n_t1t2); variable_idx_t v_t2t3 = find_variable_with_node(n_t2t3); variable_idx_t v_t3t1 = find_variable_with_node(n_t3t1); if (v_t1t2 < 0 or v_t2t3 < 0 or v_t3t1 < 0) return false; std::string name1 = util::format("transitivity:(%s,%s,%s)", t1.string().c_str(), t2.string().c_str(), t3.string().c_str()); constraint_t con_trans1(name1, OPR_GREATER_EQ, -1); con_trans1.add_term(v_t1t2, +1.0); con_trans1.add_term(v_t2t3, -1.0); con_trans1.add_term(v_t3t1, -1.0); std::string name2 = util::format("transitivity:(%s,%s,%s)", t2.string().c_str(), t3.string().c_str(), t1.string().c_str()); constraint_t con_trans2(name2, OPR_GREATER_EQ, -1); con_trans2.add_term(v_t1t2, -1.0); con_trans2.add_term(v_t2t3, +1.0); con_trans2.add_term(v_t3t1, -1.0); std::string name3 = util::format("transitivity:(%s,%s,%s)", t3.string().c_str(), t1.string().c_str(), t2.string().c_str()); constraint_t con_trans3(name3, OPR_GREATER_EQ, -1); con_trans3.add_term(v_t1t2, -1.0); con_trans3.add_term(v_t2t3, -1.0); con_trans3.add_term(v_t3t1, +1.0); constraint_idx_t idx_trans1 = add_constraint(con_trans1); constraint_idx_t idx_trans2 = add_constraint(con_trans2); constraint_idx_t idx_trans3 = add_constraint(con_trans3); // FOR CUTTING-PLANE add_laziness_of_constraint(idx_trans1); add_laziness_of_constraint(idx_trans2); add_laziness_of_constraint(idx_trans3); m_log_of_term_triplet_for_transitive_unification.insert(key); return 1; }
variable_idx_t ilp_problem_t::add_variable_of_edge( pg::edge_idx_t idx, double coef, bool do_add_constraint_for_node) { const pg::edge_t &edge = m_graph->edge(idx); if (ms_do_economize) { variable_idx_t var(-1); if (edge.is_chain_edge()) variable_idx_t var = find_variable_with_hypernode(edge.head()); if (edge.is_unify_edge() and edge.head() < 0) variable_idx_t var = find_variable_with_hypernode(edge.tail()); if (var >= 0) { m_map_edge_to_variable[idx] = var; return var; } } variable_idx_t var = add_variable(variable_t( util::format("edge(%d):hn(%d,%d)", idx, edge.tail(), edge.head()), 0.0)); if (do_add_constraint_for_node) { variable_idx_t v_tail = find_variable_with_hypernode(edge.tail()); variable_idx_t v_head = find_variable_with_hypernode(edge.head()); /* IF THE EDGE IS TRUE, TAIL AND HEAD MUST BE TRUE, TOO. */ if (v_tail >= 0 and (v_head >= 0 or edge.head() < 0)) { constraint_t con( util::format("e_hn_dependency:e(%d):hn(%d,%d)", idx, edge.tail(), edge.head()), OPR_GREATER_EQ, 0.0); con.add_term(v_tail, 1.0); if (edge.head() >= 0) con.add_term(v_head, 1.0); con.add_term(var, -1.0 * con.terms().size()); add_constraint(con); } /* IF LITERAL NODES IN THE HEAD ARE TRUE, THE NODE MUST BE TRUE, TOO. */ if (edge.is_chain_edge() and v_head >= 0) { constraint_t con( util::format("n_e_dependency:e(%d)", idx), OPR_GREATER_EQ, 0.0); con.add_term(v_head, -1.0); con.add_term(var, con.terms().size()); add_constraint(con); } } m_map_edge_to_variable[idx] = var; return var; }
void ilp_problem_t:: add_constrains_of_conditions_for_chain(pg::edge_idx_t idx) { const pg::edge_t &edge = m_graph->edge(idx); variable_idx_t v_edge = find_variable_with_edge(idx); if (v_edge < 0) return; if (not edge.is_chain_edge()) return; hash_set<pg::node_idx_t> conds1, conds2; bool is_available = m_graph->check_availability_of_chain(idx, &conds1, &conds2); // IF THE CHAIN IS NOT AVAILABLE, HEAD-HYPERNODE MUST BE FALSE. if (not is_available) add_constancy_of_variable(v_edge, 0.0); else { if (not conds1.empty()) { // TO PERFORM THE CHAINING, NODES IN conds1 MUST BE TRUE. constraint_t con( util::format("node_must_be_true_for_chain:e(%d)", idx), OPR_GREATER_EQ, 0.0); for (auto n = conds1.begin(); n != conds1.end(); ++n) { variable_idx_t _v = find_variable_with_node(*n); assert(_v >= 0); con.add_term(_v, 1.0); } con.add_term(v_edge, -1.0 * con.terms().size()); add_constraint(con); } if (not conds2.empty()) { // TO PERFORM THE CHAINING, NODES IN conds2 MUST NOT BE TRUE. constraint_t con( util::format("node_must_be_false_for_chain:e(%d)", idx), OPR_GREATER_EQ, 0.0); for (auto n = conds2.begin(); n != conds2.end(); ++n) { variable_idx_t _v = find_variable_with_node(*n); assert(_v >= 0); con.add_term(_v, -1.0); } double b = -1.0 * con.terms().size(); con.add_term(v_edge, b); con.set_bound(b); add_constraint(con); } } }
void memory_model_sct::write_serialization_external( symex_target_equationt &equation) { for(address_mapt::const_iterator a_it=address_map.begin(); a_it!=address_map.end(); a_it++) { const a_rect &a_rec=a_it->second; // This is quadratic in the number of writes // per address. Perhaps some better encoding // based on 'places'? for(event_listt::const_iterator w_it1=a_rec.writes.begin(); w_it1!=a_rec.writes.end(); ++w_it1) { event_listt::const_iterator next=w_it1; ++next; for(event_listt::const_iterator w_it2=next; w_it2!=a_rec.writes.end(); ++w_it2) { // external? if((*w_it1)->source.thread_nr== (*w_it2)->source.thread_nr) continue; // ws is a total order, no two elements have the same rank // s -> w_evt1 before w_evt2; !s -> w_evt2 before w_evt1 symbol_exprt s=nondet_bool_symbol("ws-ext"); // write-to-write edge add_constraint( equation, implies_exprt(s, before(*w_it1, *w_it2)), "ws-ext", (*w_it1)->source); add_constraint( equation, implies_exprt(not_exprt(s), before(*w_it2, *w_it1)), "ws-ext", (*w_it1)->source); } } } }
void hbox::add( area &a, double fraction ) { precondition( !_init, "cannot add new areas after update" ); add_constraint( a.top() == _top + _padding + _spacing ); add_constraint( a.bottom() == _bottom - _padding - _spacing ); // if ( fraction > 1e-8 ) // add_constraint( weak || a.width() >= width() * fraction ); add_constraint( a.left() == _current + _spacing ); add_constraint( a.width() >= a.minimum_width() ); _current = a.right() + _spacing; }
bool CFeasibilityMap::SolveLP(Matrix &A, ColumnVector &b) { lprec *lp ; int n_row = A.nrows(); int n_col = A.ncols(); lp = make_lp(0,n_col) ; double *input_row = new double[1+n_col]; for (int i_row=1; i_row<=n_row; i_row++){ input_row[0] = 0 ; for (int j=1; j<=n_col; j++){ input_row[j] = A(i_row,j) ; } add_constraint(lp, input_row, LE, b(i_row)) ; } delete [] input_row; double *input_obj = new double[1+n_col]; // The first zero is for matrix form input_obj[0] = 0 ; for (int j=1; j<=n_col; j++){ input_obj[j] = 1 ; } set_obj_fn(lp, input_obj) ; delete [] input_obj; set_verbose(lp, IMPORTANT); // NEUTRAL (0), IMPORTANT (3), NORMAL (4), FULL (6) bool is_feasible = (solve(lp)==0); // 0: feasible solution found, 2: not found // solution for minimizing objective function delete_lp(lp); return is_feasible; }
size_t ilp_problem_t::add_constrains_of_exclusive_chains( const std::list< hash_set<pg::edge_idx_t> > &exc) { size_t num_of_added_constraints(0); for (auto it = exc.begin(); it != exc.end(); ++it) { std::string name = "exclusive_chains(" + util::join(it->begin(), it->end(), ",") + ")"; constraint_t con(name, OPR_GREATER_EQ, -1.0); for (auto e = it->begin(); e != it->end(); ++e) { variable_idx_t v = find_variable_with_edge(*e); if (v >= 0) con.add_term(v, -1.0); else break; } if (con.terms().size() == it->size()) { add_constraint(con); ++num_of_added_constraints; } } return num_of_added_constraints; }
static void get_paren( char *buf, long *minp, long *maxp, int parent) { int lth; get_must(0, buf); if (!strcmp(buf, size_w)) { get_size(buf, minp, maxp, parent); // if (type == ASN_UTCTIME || type == ASN_GENTIME) *minp = *maxp = 0; } else { if (find_name(classname)->type != ASN_OBJ_ID && (*buf == '_' || (*buf >= '0' && *buf <= '9') || !strncmp(buf, min_w, 3))) { /* convert any upper bounds to numbers */ get_min_max(buf, minp, maxp, parent); option |= ASN_RANGE_FLAG; } else for (; *buf != ')'; get_must(0, buf)) { lth = strlen(buf); cat(&buf[lth++], " "); add_constraint(buf, lth); } } }
/** Add an edit constraint for a given variable. * The application should call this for every variable it is planning * to suggest a new value for, before calling begin_edit(). */ simplex_solver& add_edit_var(const variable& v, const strength& s = strength::strong(), double weight = 1.0) { add_constraint(std::make_shared<edit_constraint>(v, s, weight)); return *this; }
/* Add a constraint to the problem, row is the constraint row, rh is the right hand side, constr_type is the type of constraint (LE (<=), GE(>=), EQ(=)) */ long __declspec(dllexport) WINAPI _add_constraint(lprec *lp, double *row, long constr_type, double rh) { long ret; if (lp != NULL) { freebuferror(); ret = add_constraint(lp, row,(short) constr_type, rh); } else ret = 0; return(ret); }
nlopt_result NLOPT_STDCALL nlopt_add_inequality_constraint(nlopt_opt opt, nlopt_func fc, void *fc_data, double tol) { nlopt_result ret; if (!opt || !inequality_ok(opt->algorithm)) ret = NLOPT_INVALID_ARGS; else ret = add_constraint(&opt->m, &opt->m_alloc, &opt->fc, 1, fc, NULL, fc_data, &tol); if (ret < 0 && opt && opt->munge_on_destroy) opt->munge_on_destroy(fc_data); return ret; }
variable_idx_t ilp_problem_t::add_variable_of_hypernode( pg::hypernode_idx_t idx, double coef, bool do_add_constraint_for_member) { const std::vector<pg::node_idx_t> &hypernode = m_graph->hypernode(idx); if (hypernode.empty()) return -1; if (ms_do_economize) { /* IF A HYERNODE INCLUDE ONLY ONE LITERAL-NODE, * USE THE NODE'S VARIABLE AS THE HYPERNODE'S VARIABLE. */ if (hypernode.size() == 1) { const pg::node_t &node = m_graph->node(hypernode.front()); if (not node.is_equality_node() and not node.is_non_equality_node()) { variable_idx_t var = find_variable_with_node(hypernode.front()); if (var >= 0) { m_map_hypernode_to_variable[idx] = var; return var; } } } } std::string nodes = util::join(hypernode.begin(), hypernode.end(), ","); std::string name = util::format("hn(%d):n(%s)", idx, nodes.c_str()); variable_idx_t var = add_variable(variable_t(name, coef)); if (do_add_constraint_for_member) { /* FOR A HYPERNODE BEING TRUE, ITS ALL MEMBERS MUST BE TRUE TOO. */ constraint_t cons( util::format("hn_n_dependency:hn(%d):n(%s)", idx, nodes.c_str()), OPR_GREATER_EQ, 0.0); for (auto n = hypernode.begin(); n != hypernode.end(); ++n) { variable_idx_t v = find_variable_with_node(*n); if (v < 0) return -1; cons.add_term(v, 1.0); } cons.set_bound(0.0, 1.0 * (cons.terms().size() - 1)); cons.add_term(var, -1.0 * cons.terms().size()); add_constraint(cons); } m_map_hypernode_to_variable[idx] = var; return var; }
int CLPLpsolve::addConstraint(CLPConstraint* c) { if (!m_rowsPreAllocated) //false { if (c->getNumCoefficients() <= 0) return 0; REAL * row = new REAL[c->getNumCoefficients()]; int * colno = new int[c->getNumCoefficients()]; //double coefs = new double[c->getNumCoefficients()]; for (int i = 0; i < c->getNumCoefficients(); ++i) { row[i] = c->getCoefficients().at(i); colno[i] = (c->getCoefficientColumns().at(i)) + 1; } //REAL *row = &c->getCoefficients().at(0); //int *colno = &c->getCoefficientColumns().at(0); char sense; switch (c->getType()) { case lpLessThanConstraint: sense = LE; break; case lpGreaterThanConstraint: sense = GE; break; case lpEqualToConstraint: sense = EQ; break; } //m_status = add_constraintex(m_env, c->getNumCoefficients(), row, colno, sense, c->getRhs()); m_status = add_constraint(m_env, row, sense, c->getRhs()); ++m_rowCount; m_status = set_row_name(m_env, m_rowCount, const_cast<char*>(c->getName().c_str())); delete [] row; delete [] colno; } return getStatus(); }
nlopt_result NLOPT_STDCALL nlopt_add_precond_equality_constraint(nlopt_opt opt, nlopt_func fc, nlopt_precond pre, void *fc_data, double tol) { nlopt_result ret; if (!opt || !equality_ok(opt->algorithm) || nlopt_count_constraints(opt->p, opt->h) + 1 > opt->n) ret = NLOPT_INVALID_ARGS; else ret = add_constraint(&opt->p, &opt->p_alloc, &opt->h, 1, fc, NULL, pre, fc_data, &tol); if (ret < 0 && opt && opt->munge_on_destroy) opt->munge_on_destroy(fc_data); return ret; }
nlopt_result NLOPT_STDCALL nlopt_add_inequality_mconstraint(nlopt_opt opt, unsigned m, nlopt_mfunc fc, void *fc_data, const double *tol) { nlopt_result ret; if (!m) { /* empty constraints are always ok */ if (opt && opt->munge_on_destroy) opt->munge_on_destroy(fc_data); return NLOPT_SUCCESS; } if (!opt || !inequality_ok(opt->algorithm)) ret = NLOPT_INVALID_ARGS; else ret = add_constraint(&opt->m, &opt->m_alloc, &opt->fc, m, NULL, fc, NULL, fc_data, tol); if (ret < 0 && opt && opt->munge_on_destroy) opt->munge_on_destroy(fc_data); return ret; }
void memory_model_sct::program_order( symex_target_equationt &equation) { per_thread_mapt per_thread_map; build_per_thread_map(equation, per_thread_map); thread_spawn(equation, per_thread_map); // iterate over threads for(per_thread_mapt::const_iterator t_it=per_thread_map.begin(); t_it!=per_thread_map.end(); t_it++) { const event_listt &events=t_it->second; // iterate over relevant events in the thread event_it previous=equation.SSA_steps.end(); for(event_listt::const_iterator e_it=events.begin(); e_it!=events.end(); e_it++) { if(is_memory_barrier(*e_it)) continue; if(previous==equation.SSA_steps.end()) { // first one? previous=*e_it; continue; } add_constraint( equation, before(previous, *e_it), "po", (*e_it)->source); previous=*e_it; } } }
bool CFeasibilityMap::SolveLP(Matrix &A, ColumnVector &b, ColumnVector &x) { lprec *lp ; int n_row = A.nrows(); int n_col = A.ncols(); x = ColumnVector(n_col); x = 0; lp = make_lp(0,n_col) ; double *input_row = new double[1+n_col]; for (int i_row=1; i_row<=n_row; i_row++){ input_row[0] = 0 ; // The first zero is for matrix form for (int j=1; j<=n_col; j++){ input_row[j] = A(i_row,j) ; } add_constraint(lp, input_row, LE, b(i_row)) ; } delete [] input_row; double *input_obj = new double[1+n_col]; // The first zero is for matrix form input_obj[0] = 0 ; for (int j=1; j<=n_col; j++){ input_obj[j] = 1 ; } set_obj_fn(lp, input_obj) ; delete [] input_obj; set_verbose(lp, IMPORTANT); // NEUTRAL (0), IMPORTANT (3), NORMAL (4), FULL (6) bool is_feasible = (solve(lp)==0); // 0: feasible solution found, 2: not found // solution for minimizing objective function double* x_min = new double[n_col]; double* x_max = new double[n_col]; if (is_feasible) { get_variables(lp, x_min); set_maxim(lp); is_feasible = (solve(lp)==0); // 0: feasible solution found, 2: not found if (is_feasible) { get_variables(lp, x_max); for (int i = 0; i < n_col; i++) { x(i+1) = (x_min[i] + x_max[i]) / 2.0; } } } delete [] x_min; delete [] x_max; delete_lp(lp); return is_feasible; }
constraint_idx_t ilp_problem_t::add_constraint_of_mutual_exclusion( pg::node_idx_t n1, pg::node_idx_t n2, const pg::unifier_t &uni) { std::string key = (n1 < n2) ? util::format("%d:%d", n1, n2) : util::format("%d:%d", n2, n1); /* IGNORE TUPLES WHICH HAVE BEEN CONSIDERED ALREADY. */ if(m_log_of_node_tuple_for_mutual_exclusion.count(key) > 0) return -1; variable_idx_t var1 = find_variable_with_node(n1); variable_idx_t var2 = find_variable_with_node(n2); if( var1 < 0 or var2 < 0 ) return -1; /* N1 AND N2 CANNOT BE TRUE AT SAME TIME. */ constraint_t con( util::format("inconsistency:n(%d,%d)", n1, n2), OPR_LESS_EQ, 1.0); con.add_term(var1, 1.0); con.add_term(var2, 1.0); bool f_fails = false; const std::set<literal_t> &subs = uni.substitutions(); for (auto sub = subs.begin(); sub != subs.end(); ++sub) { const term_t &term1 = sub->terms[0]; const term_t &term2 = sub->terms[1]; if (term1.is_constant() and term2.is_constant() and term1 != term2) return -1; pg::node_idx_t sub_node = m_graph->find_sub_node(term1, term2); if (sub_node < 0) return -1; variable_idx_t sub_var = find_variable_with_node(sub_node); if (sub_var < 0) return -1; con.add_term(sub_var, 1.0); con.set_bound(con.bound() + 1.0); } m_log_of_node_tuple_for_mutual_exclusion.insert(key); return add_constraint(con); }
bool add_constraints(int argc, char ** argv, struct mpd_connection *conn) { struct constraint *constraints; if (argc % 2 != 0) DIE("arguments must be pairs of search types and queries\n"); int numconstraints = get_constraints(argc, argv, &constraints); if (numconstraints < 0) return false; for (int i = 0; i < numconstraints; i++) { add_constraint(conn, &constraints[i]); } free(constraints); return true; }
void ilp_problem_t::add_constraints_to_forbid_chaining_from_explained_node( pg::edge_idx_t idx_unify, pg::node_idx_t idx_explained, std::list<constraint_idx_t> *out) { const pg::edge_t &e_uni = m_graph->edge(idx_unify); if (not e_uni.is_unify_edge()) return; // IF A LITERAL IS UNIFIED AND EXPLAINED BY ANOTHER ONE, // THEN CHAINING FROM THE LITERAL IS FORBIDDEN. variable_idx_t v_uni = find_variable_with_edge(idx_unify); if (v_uni < 0) return; auto from = m_graph->hypernode(e_uni.tail()); if (from[0] != idx_explained and from[1] != idx_explained) return; auto hns = m_graph->search_hypernodes_with_node(idx_explained); for (auto hn = hns->begin(); hn != hns->end(); ++hn) { auto es = m_graph->search_edges_with_hypernode(*hn); for (auto j = es->begin(); j != es->end(); ++j) { const pg::edge_t &e_ch = m_graph->edge(*j); if (not e_ch.is_chain_edge() or e_ch.tail() != (*hn)) continue; constraint_t con( util::format("unify_or_chain:e(%d):e(%d)", idx_unify, *j), OPR_GREATER_EQ, -1.0); variable_idx_t v_ch = find_variable_with_edge(*j); if (v_ch >= 0) { con.add_term(v_ch, -1.0); con.add_term(v_uni, -1.0); constraint_idx_t con_idx = add_constraint(con); if (con_idx >= 0 and out != NULL) out->push_back(con_idx); } } } }
constraint_idx_t ilp_problem_t:: add_constraint_of_dependence_of_node_on_hypernode(pg::node_idx_t idx) { const pg::node_t &node = m_graph->node(idx); if (node.is_equality_node() or node.is_non_equality_node()) return -1; variable_idx_t var_node = find_variable_with_node(idx); if (var_node < 0) return -1; hash_set<pg::hypernode_idx_t> masters; if (node.is_equality_node() or node.is_non_equality_node()) { auto hns = m_graph->search_hypernodes_with_node(idx); if (hns != NULL) { hash_set<pg::edge_idx_t> parental_edges; for (auto it = hns->begin(); it != hns->end(); ++it) m_graph->enumerate_parental_edges(*it, &parental_edges); for (auto it = parental_edges.begin(); it != parental_edges.end(); ++it) masters.insert(m_graph->edge(*it).head()); } } else if (node.master_hypernode() >= 0) masters.insert(node.master_hypernode()); /* TO LET A NODE BE TRUE, ITS MASTER-HYPERNODES IS TRUE */ constraint_t con(util::format("n_dependency:n(%d)", idx), OPR_GREATER_EQ, 0.0); for (auto it = masters.begin(); it != masters.end(); ++it) { variable_idx_t var_master = find_variable_with_hypernode(*it); if (var_node != var_master and var_master >= 0) con.add_term(var_master, 1.0); } if (con.terms().empty()) return -1; con.add_term(var_node, -1.0); return add_constraint(con); }
constraint_idx_t ilp_problem_t:: add_constraint_of_dependence_of_hypernode_on_parents(pg::hypernode_idx_t idx) { variable_idx_t var = find_variable_with_hypernode(idx); if (var < 0) return -1; hash_set<pg::hypernode_idx_t> parents; m_graph->enumerate_parental_hypernodes(idx, &parents); if (parents.empty()) return -1; /* TO LET A HYPERNODE BE TRUE, ANY OF ITS PARENTS ARE MUST BE TRUE. */ constraint_t con(util::format("hn_dependency:hn(%d)", idx), OPR_GREATER_EQ, 0.0); con.add_term(var, -1.0); for( auto hn = parents.begin(); hn != parents.end(); ++hn ) { variable_idx_t v = find_variable_with_hypernode(*hn); if (v >= 0) con.add_term( v, 1.0 ); } return add_constraint(con); }
void memory_model_sct::thread_spawn( symex_target_equationt &equation, const per_thread_mapt &per_thread_map) { // thread spawn: the spawn precedes the first // instruction of the new thread in program order unsigned next_thread_id=0; for(eventst::const_iterator e_it=equation.SSA_steps.begin(); e_it!=equation.SSA_steps.end(); e_it++) { if(is_spawn(e_it)) { per_thread_mapt::const_iterator next_thread= per_thread_map.find(++next_thread_id); if(next_thread==per_thread_map.end()) continue; // For SC and several weaker memory models a memory barrier // at the beginning of a thread can simply be ignored, because // we enforce program order in the thread-spawn constraint // anyway. Memory models with cumulative memory barriers // require explicit handling of these. event_listt::const_iterator n_it=next_thread->second.begin(); for( ; n_it!=next_thread->second.end() && (*n_it)->is_memory_barrier(); ++n_it) ; if(n_it!=next_thread->second.end()) add_constraint( equation, before(e_it, *n_it), "thread-spawn", e_it->source); } } }
void memory_model_sct::thread_spawn( symex_target_equationt &equation, const per_thread_mapt &per_thread_map) { // thread spawn: the spawn precedes the first // instruction of the new thread in program order unsigned next_thread_id=0; for(eventst::const_iterator e_it=equation.SSA_steps.begin(); e_it!=equation.SSA_steps.end(); e_it++) { if(is_spawn(e_it)) { per_thread_mapt::const_iterator next_thread= per_thread_map.find(++next_thread_id); if(next_thread==per_thread_map.end()) continue; // add a constraint for all events, // considering regression/cbmc-concurrency/pthread_create_tso1 for(event_listt::const_iterator n_it=next_thread->second.begin(); n_it!=next_thread->second.end(); n_it++) { if(!(*n_it)->is_memory_barrier()) add_constraint( equation, before(e_it, *n_it), "thread-spawn", e_it->source); } } } }
char *call_lp(int next_expr(int)) {int i,constraints; expr_type_t goal_type; char *retval, *retval2; /* initially the expression to be checked is in entropy_expr. determine first the variables */ init_var_assignment(); /* start collecting variables */ add_expr_variables(); /* variables in the expression to be checked */ constraints=0; for(i=0;next_expr(i)==0;i++){ /* go over all constraints */ constraints++; // Markov constraints give several cols if(entropy_expr.type==ent_Markov){ constraints+=entropy_expr.n-3; } add_expr_variables(); } /* figure out final variables, rows, cols, number of Shannon */ if(do_variable_assignment()){ // number of variables is less than 2 return "number of final random variables is less than 2"; } /* get memory for row and column permutation */ cols += constraints; rowperm=malloc((rows+1)*sizeof(int)); colperm=malloc((cols+1)*sizeof(int)); if(!rowperm || !colperm){ if(rowperm){ free(rowperm); rowperm=NULL; } if(colperm){ free(colperm); colperm=NULL; } return "the problem is too large, not enough memory"; } for(i=0;i<=rows;i++) rowperm[i]=i; perm_array(rows+1,rowperm); for(i=0;i<=cols;i++) colperm[i]= i-1; perm_array(cols+1,colperm); /* the expression to be checked, this will be the goal */ if(constraints) next_expr(-1); goal_type=entropy_expr.type; // ent_eq, ent_ge create_glp(); // create a new glp instance for(i=0;i<entropy_expr.n;i++){ row_idx[i+1]=varidx(entropy_expr.item[i].var); row_val[i+1]=entropy_expr.item[i].coeff; } add_goal(entropy_expr.n); // right hand side value // go over the columns add them to the lp instance for(i=1;i<=cols;i++){ int colct=colperm[i]; if(add_shannon(i,colct)){ // this is a constraint add_constraint(i,colct-(shannon+var_no),next_expr); } } /* call the lp */ init_glp_parameters(); if(parm.presolve!=GLP_ON) // generate the first basis glp_adv_basis(P,0); retval=invoke_lp(); // call again with -1.0 when checking for ent_eq if(goal_type==ent_eq && (retval==EXPR_TRUE || retval==EXPR_FALSE)){ next_expr(-1); // reload the problem for(i=0;i<entropy_expr.n;i++){ row_idx[i+1]=varidx(entropy_expr.item[i].var); row_val[i+1]=-entropy_expr.item[i].coeff; } add_goal(entropy_expr.n); // right hand side value retval2=invoke_lp(); if(retval2==EXPR_TRUE){ if(retval==EXPR_FALSE) retval=EQ_LE_ONLY; } else if(retval2==EXPR_FALSE){ if(retval==EXPR_TRUE) retval=EQ_GE_ONLY; } else { retval=retval2; } } /* release allocated memory */ release_glp(); if(rowperm){ free(rowperm); rowperm=NULL; } if(colperm){ free(colperm); colperm=NULL; } return retval; }
double QuadProg::solve_quadprog(Matrix<double>& G, Vector<double>& g0, const Matrix<double>& CE, const Vector<double>& ce0, const Matrix<double>& CI, const Vector<double>& ci0, Vector<double>& x) { std::ostringstream msg; { //Ensure that the dimensions of the matrices and vectors can be //safely converted from unsigned int into to int without overflow. unsigned mx = std::numeric_limits<int>::max(); if(G.ncols() >= mx || G.nrows() >= mx || CE.nrows() >= mx || CE.ncols() >= mx || CI.nrows() >= mx || CI.ncols() >= mx || ci0.size() >= mx || ce0.size() >= mx || g0.size() >= mx){ msg << "The dimensions of one of the input matrices or vectors were " << "too large." << std::endl << "The maximum allowable size for inputs to solve_quadprog is:" << mx << std::endl; throw std::logic_error(msg.str()); } } int n = G.ncols(), p = CE.ncols(), m = CI.ncols(); if ((int)G.nrows() != n) { msg << "The matrix G is not a square matrix (" << G.nrows() << " x " << G.ncols() << ")"; throw std::logic_error(msg.str()); } if ((int)CE.nrows() != n) { msg << "The matrix CE is incompatible (incorrect number of rows " << CE.nrows() << " , expecting " << n << ")"; throw std::logic_error(msg.str()); } if ((int)ce0.size() != p) { msg << "The vector ce0 is incompatible (incorrect dimension " << ce0.size() << ", expecting " << p << ")"; throw std::logic_error(msg.str()); } if ((int)CI.nrows() != n) { msg << "The matrix CI is incompatible (incorrect number of rows " << CI.nrows() << " , expecting " << n << ")"; throw std::logic_error(msg.str()); } if ((int)ci0.size() != m) { msg << "The vector ci0 is incompatible (incorrect dimension " << ci0.size() << ", expecting " << m << ")"; throw std::logic_error(msg.str()); } x.resize(n); register int i, j, k, l; /* indices */ int ip; // this is the index of the constraint to be added to the active set Matrix<double> R(n, n), J(n, n); Vector<double> s(m + p), z(n), r(m + p), d(n), np(n), u(m + p), x_old(n), u_old(m + p); double f_value, psi, c1, c2, sum, ss, R_norm; double inf; if (std::numeric_limits<double>::has_infinity) inf = std::numeric_limits<double>::infinity(); else inf = 1.0E300; double t, t1, t2; /* t is the step lenght, which is the minimum of the partial step length t1 * and the full step length t2 */ Vector<int> A(m + p), A_old(m + p), iai(m + p); int q, iq, iter = 0; Vector<bool> iaexcl(m + p); /* p is the number of equality constraints */ /* m is the number of inequality constraints */ q = 0; /* size of the active set A (containing the indices of the active constraints) */ #ifdef TRACE_SOLVER std::cout << std::endl << "Starting solve_quadprog" << std::endl; print_matrix("G", G); print_vector("g0", g0); print_matrix("CE", CE); print_vector("ce0", ce0); print_matrix("CI", CI); print_vector("ci0", ci0); #endif /* * Preprocessing phase */ /* compute the trace of the original matrix G */ c1 = 0.0; for (i = 0; i < n; i++) { c1 += G[i][i]; } /* decompose the matrix G in the form L^T L */ cholesky_decomposition(G); #ifdef TRACE_SOLVER print_matrix("G", G); #endif /* initialize the matrix R */ for (i = 0; i < n; i++) { d[i] = 0.0; for (j = 0; j < n; j++) R[i][j] = 0.0; } R_norm = 1.0; /* this variable will hold the norm of the matrix R */ /* compute the inverse of the factorized matrix G^-1, this is the initial value for H */ c2 = 0.0; for (i = 0; i < n; i++) { d[i] = 1.0; forward_elimination(G, z, d); for (j = 0; j < n; j++) J[i][j] = z[j]; c2 += z[i]; d[i] = 0.0; } #ifdef TRACE_SOLVER print_matrix("J", J); #endif /* c1 * c2 is an estimate for cond(G) */ /* * Find the unconstrained minimizer of the quadratic form 0.5 * x G x + g0 x * this is a feasible point in the dual space * x = G^-1 * g0 */ cholesky_solve(G, x, g0); for (i = 0; i < n; i++) x[i] = -x[i]; /* and compute the current solution value */ f_value = 0.5 * scalar_product(g0, x); #ifdef TRACE_SOLVER std::cout << "Unconstrained solution: " << f_value << std::endl; print_vector("x", x); #endif /* Add equality constraints to the working set A */ iq = 0; for (i = 0; i < p; i++) { for (j = 0; j < n; j++) np[j] = CE[j][i]; compute_d(d, J, np); update_z(z, J, d, iq); update_r(R, r, d, iq); #ifdef TRACE_SOLVER print_matrix("R", R, n, iq); print_vector("z", z); print_vector("r", r, iq); print_vector("d", d); #endif /* compute full step length t2: i.e., the minimum step in primal space s.t. the contraint becomes feasible */ t2 = 0.0; if (fabs(scalar_product(z, z)) > std::numeric_limits<double>::epsilon()) // i.e. z != 0 t2 = (-scalar_product(np, x) - ce0[i]) / scalar_product(z, np); /* set x = x + t2 * z */ for (k = 0; k < n; k++) x[k] += t2 * z[k]; /* set u = u+ */ u[iq] = t2; for (k = 0; k < iq; k++) u[k] -= t2 * r[k]; /* compute the new solution value */ f_value += 0.5 * (t2 * t2) * scalar_product(z, np); A[i] = -i - 1; if (!add_constraint(R, J, d, iq, R_norm)) { // Equality constraints are linearly dependent throw std::runtime_error("Constraints are linearly dependent"); return f_value; } } /* set iai = K \ A */ for (i = 0; i < m; i++) iai[i] = i; l1: iter++; #ifdef TRACE_SOLVER print_vector("x", x); #endif /* step 1: choose a violated constraint */ for (i = p; i < iq; i++) { ip = A[i]; iai[ip] = -1; } /* compute s[x] = ci^T * x + ci0 for all elements of K \ A */ ss = 0.0; psi = 0.0; /* this value will contain the sum of all infeasibilities */ ip = 0; /* ip will be the index of the chosen violated constraint */ for (i = 0; i < m; i++) { iaexcl[i] = true; sum = 0.0; for (j = 0; j < n; j++) sum += CI[j][i] * x[j]; sum += ci0[i]; s[i] = sum; psi += std::min(0.0, sum); } #ifdef TRACE_SOLVER print_vector("s", s, m); #endif if (fabs(psi) <= m * std::numeric_limits<double>::epsilon() * c1 * c2* 100.0) { /* numerically there are not infeasibilities anymore */ q = iq; return f_value; } /* save old values for u and A */ for (i = 0; i < iq; i++) { u_old[i] = u[i]; A_old[i] = A[i]; } /* and for x */ for (i = 0; i < n; i++) x_old[i] = x[i]; l2: /* Step 2: check for feasibility and determine a new S-pair */ for (i = 0; i < m; i++) { if (s[i] < ss && iai[i] != -1 && iaexcl[i]) { ss = s[i]; ip = i; } } if (ss >= 0.0) { q = iq; return f_value; } /* set np = n[ip] */ for (i = 0; i < n; i++) np[i] = CI[i][ip]; /* set u = [u 0]^T */ u[iq] = 0.0; /* add ip to the active set A */ A[iq] = ip; #ifdef TRACE_SOLVER std::cout << "Trying with constraint " << ip << std::endl; print_vector("np", np); #endif l2a:/* Step 2a: determine step direction */ /* compute z = H np: the step direction in the primal space (through J, see the paper) */ compute_d(d, J, np); update_z(z, J, d, iq); /* compute N* np (if q > 0): the negative of the step direction in the dual space */ update_r(R, r, d, iq); #ifdef TRACE_SOLVER std::cout << "Step direction z" << std::endl; print_vector("z", z); print_vector("r", r, iq + 1); print_vector("u", u, iq + 1); print_vector("d", d); print_vector("A", A, iq + 1); #endif /* Step 2b: compute step length */ l = 0; /* Compute t1: partial step length (maximum step in dual space without violating dual feasibility */ t1 = inf; /* +inf */ /* find the index l s.t. it reaches the minimum of u+[x] / r */ for (k = p; k < iq; k++) { if (r[k] > 0.0) { if (u[k] / r[k] < t1) { t1 = u[k] / r[k]; l = A[k]; } } } /* Compute t2: full step length (minimum step in primal space such that the constraint ip becomes feasible */ if (fabs(scalar_product(z, z)) > std::numeric_limits<double>::epsilon()) // i.e. z != 0 t2 = -s[ip] / scalar_product(z, np); else t2 = inf; /* +inf */ /* the step is chosen as the minimum of t1 and t2 */ t = std::min(t1, t2); #ifdef TRACE_SOLVER std::cout << "Step sizes: " << t << " (t1 = " << t1 << ", t2 = " << t2 << ") "; #endif /* Step 2c: determine new S-pair and take step: */ /* case (i): no step in primal or dual space */ if (t >= inf) { /* QPP is infeasible */ // FIXME: unbounded to raise q = iq; return inf; } /* case (ii): step in dual space */ if (t2 >= inf) { /* set u = u + t * [-r 1] and drop constraint l from the active set A */ for (k = 0; k < iq; k++) u[k] -= t * r[k]; u[iq] += t; iai[l] = l; delete_constraint(R, J, A, u, n, p, iq, l); #ifdef TRACE_SOLVER std::cout << " in dual space: " << f_value << std::endl; print_vector("x", x); print_vector("z", z); print_vector("A", A, iq + 1); #endif goto l2a; } /* case (iii): step in primal and dual space */ /* set x = x + t * z */ for (k = 0; k < n; k++) x[k] += t * z[k]; /* update the solution value */ f_value += t * scalar_product(z, np) * (0.5 * t + u[iq]); /* u = u + t * [-r 1] */ for (k = 0; k < iq; k++) u[k] -= t * r[k]; u[iq] += t; #ifdef TRACE_SOLVER std::cout << " in both spaces: " << f_value << std::endl; print_vector("x", x); print_vector("u", u, iq + 1); print_vector("r", r, iq + 1); print_vector("A", A, iq + 1); #endif if (fabs(t - t2) < std::numeric_limits<double>::epsilon()) { #ifdef TRACE_SOLVER std::cout << "Full step has taken " << t << std::endl; print_vector("x", x); #endif /* full step has taken */ /* add constraint ip to the active set*/ if (!add_constraint(R, J, d, iq, R_norm)) { iaexcl[ip] = false; delete_constraint(R, J, A, u, n, p, iq, ip); #ifdef TRACE_SOLVER print_matrix("R", R); print_vector("A", A, iq); print_vector("iai", iai); #endif for (i = 0; i < m; i++) iai[i] = i; for (i = p; i < iq; i++) { A[i] = A_old[i]; u[i] = u_old[i]; iai[A[i]] = -1; } for (i = 0; i < n; i++) x[i] = x_old[i]; goto l2; /* go to step 2 */ } else iai[ip] = -1; #ifdef TRACE_SOLVER print_matrix("R", R); print_vector("A", A, iq); print_vector("iai", iai); #endif goto l1; } /* a patial step has taken */ #ifdef TRACE_SOLVER std::cout << "Partial step has taken " << t << std::endl; print_vector("x", x); #endif /* drop constraint l */ iai[l] = l; delete_constraint(R, J, A, u, n, p, iq, l); #ifdef TRACE_SOLVER print_matrix("R", R); print_vector("A", A, iq); #endif /* update s[ip] = CI * x + ci0 */ sum = 0.0; for (k = 0; k < n; k++) sum += CI[k][ip] * x[k]; s[ip] = sum + ci0[ip]; #ifdef TRACE_SOLVER print_vector("s", s, m); #endif goto l2a; }
/* Solve the LP subproblem by calling lp_solve API */ int LLW_solve_lp(double **gradient, const struct TrainingCache *cache, const struct Model *model) { long i,k,l,ind_pattern,y_i; const long Q = model->Q; const double Qd = (double)Q; const long chunk_size = cache->chunk_size; const double *C = model->C; const int nRows = Q-1; const int nCols = chunk_size * Q; double *obj = (double*)malloc(sizeof(double) * (1+nCols)); double *row = (double*)malloc(sizeof(double) * (1+nCols)); double *rhs = (double*)malloc(sizeof(double) * Q); long **lp_sol_table = matrix_l(nCols, 2); long **lp_sol_table_inv = matrix_l(chunk_size, Q); double *sol = (double*)malloc(sizeof(double) * (1+nRows+nCols)); double epsel; // Make LP lprec *lp = make_lp(0, nCols); set_add_rowmode(lp, TRUE); // Make objective function int col = 1; for(i=1; i<=chunk_size; i++) { ind_pattern = cache->table_chunk[i]; for(k=1; k<=Q; k++) { obj[col] = gradient[ind_pattern][k]; lp_sol_table[col][1] = i; // keep a table of correspondance between lp_sol_table[col][2] = k; // LPSOLVE vector of variables and lp_sol matrix lp_sol_table_inv[i][k] = col++; // lp_sol[i][k] = the 'lp_solve_table_inv[i][k]'-th variable for LPSOLVE } } set_obj_fn(lp, obj); /* // Make RHS of constraints // -- complete computation -- for(k=1; k<Q; k++) { rhs[k] = 0.0; for(i=1; i<=nb_data; i++) if(cache->in_chunk[i] == 0) { for(l=1; l<=Q; l++) rhs[k] += model->alpha[i][l]; rhs[k] -= Qd * model->alpha[i][k]; } } */ // Make RHS of constraints // -- updates to cache->rhs are made in compute_new_alpha() // to keep track of rhs // we only need to remove the contribution of the examples in the chunk for(k=1; k<Q; k++) { rhs[k] = cache->lp_rhs[k]; for(i=1; i<=chunk_size; i++) { ind_pattern = cache->table_chunk[i]; for(l=1; l<=Q; l++) rhs[k] -= model->alpha[ind_pattern][l]; rhs[k] += Qd * model->alpha[ind_pattern][k]; } } // Make constraints for(k=1; k<Q; k++) { for(col = 1;col <=nCols; col++) row[col] = 0.0; for(i=1; i<=chunk_size; i++) { ind_pattern = cache->table_chunk[i]; y_i = model->y[ind_pattern]; for(l=1; l<=Q; l++) if(l != y_i) { row[lp_sol_table_inv[i][l]] = -1.0; if(l == k) row[lp_sol_table_inv[i][l]] += Qd; } } add_constraint(lp, row, EQ, rhs[k]); } // Upper bound constraints: alpha <= Cy_i for(col=1;col<=nCols;col++) set_upbo(lp, col, C[model->y[cache->table_chunk[lp_sol_table[col][1]]]]); /* for(i=1; i<=chunk_size; i++) { for(k=1; k<=Q; k++) if(k != model->y[cache->table_chunk[i]]) { col = (int)lp_sol_table_inv[i][k]; set_upbo(lp, col, C); } } */ // End of LP making set_add_rowmode(lp, FALSE); //print_lp(lp); // Solve LP int jump = false; set_outputfile(lp,""); if(solve(lp)) { printf("Problem with the LP... \n"); jump = true; } else { // Recover solution in the matrix lp_sol get_primal_solution(lp, sol); // sol: template for lp_solve solution format // sol=[obj, constraints, variables] epsel = get_epsel(lp); // tolerance in lp_solve // Put solution into lp_sol for(col=1; col<= nCols; col++) { // Check feasibility of the col-th variable if((sol[nRows+col] < -epsel) || (sol[nRows+col] > C[model->y[cache->table_chunk[lp_sol_table[col][1]]]] + epsel)) { jump = true; break; } // Round off tolerance if(fabs(sol[nRows+col]) < epsel) sol[nRows+col] = 0.0; else if(fabs(sol[nRows+col] - C[model->y[cache->table_chunk[lp_sol_table[col][1]]]]) < epsel) sol[nRows+col] = C[model->y[cache->table_chunk[lp_sol_table[col][1]]]]; // Set the value in lp_sol matrix cache->lp_sol[lp_sol_table[col][1]][lp_sol_table[col][2]] = sol[nRows+col]; } } delete_lp(lp); free(obj); free(row); free(rhs); free(lp_sol_table[1]);free(lp_sol_table); free(lp_sol_table_inv[1]);free(lp_sol_table_inv); free(sol); return jump; }
static void create_constraints (Constraint **constraints, GList *windows) { GList *tmp; tmp = windows; while (tmp != NULL) { MetaWindow *w = tmp->data; if (!WINDOW_IN_STACK (w)) { meta_topic (META_DEBUG_STACK, "Window %s not in the stack, not constraining it\n", w->desc); tmp = tmp->next; continue; } if (WINDOW_TRANSIENT_FOR_WHOLE_GROUP (w)) { GSList *group_windows; GSList *tmp2; MetaGroup *group; group = meta_window_get_group (w); if (group != NULL) group_windows = meta_group_list_windows (group); else group_windows = NULL; tmp2 = group_windows; while (tmp2 != NULL) { MetaWindow *group_window = tmp2->data; if (!WINDOW_IN_STACK (group_window) || w->screen != group_window->screen || group_window->override_redirect) { tmp2 = tmp2->next; continue; } #if 0 /* old way of doing it */ if (!(meta_window_is_ancestor_of_transient (w, group_window)) && !WINDOW_TRANSIENT_FOR_WHOLE_GROUP (group_window)) /* note */;/*note*/ #else /* better way I think, so transient-for-group are constrained * only above non-transient-type windows in their group */ if (!WINDOW_HAS_TRANSIENT_TYPE (group_window)) #endif { meta_topic (META_DEBUG_STACK, "Constraining %s above %s as it's transient for its group\n", w->desc, group_window->desc); add_constraint (constraints, w, group_window); } tmp2 = tmp2->next; } g_slist_free (group_windows); } else if (w->transient_for != NULL) { MetaWindow *parent; parent = w->transient_for; if (parent && WINDOW_IN_STACK (parent)) { meta_topic (META_DEBUG_STACK, "Constraining %s above %s due to transiency\n", w->desc, parent->desc); add_constraint (constraints, w, parent); } } tmp = tmp->next; } }