void SepInverse::separate(IntervalVector& xin, IntervalVector& xout){ assert(xin.size()==f.nb_var() && xout.size() == f.nb_var()); xin &= xout; Domain tmp=f.eval_domain(xin); yin.init(Interval::ALL_REALS); yout.init(Interval::ALL_REALS); id->backward(tmp, yin); id->backward(tmp, yout); s.separate(yin, yout); if( yin.is_empty()) xin.set_empty(); else tmp = id->eval_domain(yin); f.backward(tmp, xin); if( yout.is_empty()) xout.set_empty(); else tmp = id->eval_domain(yout); f.backward(tmp, xout); }
void InHC4Revise::ibwd(const Function& f, const Domain& y, IntervalVector& x, const IntervalVector& xin) { Eval e; if (!xin.is_empty()) { e.eval(f,xin); assert(!f.expr().deco.d->is_empty()); for (int i=0; i<f.nb_nodes(); i++) *f.node(i).deco.p = *f.node(i).deco.d; } else { for (int i=0; i<f.nb_nodes(); i++) f.node(i).deco.p->set_empty(); } e.eval(f,x); assert(!f.expr().deco.d->is_empty()); *f.expr().deco.d = y; try { f.backward<InHC4Revise>(*this); f.read_arg_domains(x); } catch(EmptyBoxException&) { x.set_empty(); } }
void gauss_seidel(const IntervalMatrix& A, const IntervalVector& b, IntervalVector& x, double ratio) { int n=(A.nb_rows()); assert(n == (A.nb_cols())); // throw NotSquareMatrixException(); assert(n == (x.size()) && n == (b.size())); double red; Interval old, proj, tmp; do { red = 0; for (int i=0; i<n; i++) { old = x[i]; proj = b[i]; for (int j=0; j<n; j++) if (j!=i) proj -= A[i][j]*x[j]; tmp=A[i][i]; bwd_mul(proj,tmp,x[i]); if (x[i].is_empty()) { x.set_empty(); return; } double gain=old.rel_distance(x[i]); if (gain>red) red=gain; } } while (red >= ratio); }
void InHC4Revise::iproj(const Function& f, const Domain& y, IntervalVector& x) { for (int i=0; i<f.nb_nodes(); i++) f.node(i).deco.p->set_empty(); Eval().eval(f,x); *f.expr().deco.d = y; try { f.backward<InHC4Revise>(*this); if (f.all_args_scalar()) { int j; for (int i=0; i<f.nb_used_vars; i++) { j=f.used_var[i]; x[j]=f.arg_domains[j].i(); } } else load(x,f.arg_domains,f.nb_used_vars,f.used_var); } catch(EmptyBoxException&) { x.set_empty(); } }
void CtcPolytopeHull::contract(IntervalVector& box) { if (!(limit_diam_box.contains(box.max_diam()))) return; // is it necessary? YES (BNE) Soplex can give false infeasible results with large numbers // cout << " box before LR " << box << endl; try { // Update the bounds the variables mylinearsolver->initBoundVar(box); //returns the number of constraints in the linearized system int cont = lr.linearization(box,mylinearsolver); if(cont<1) return; optimizer(box); // mylinearsolver->writeFile("LP.lp"); // system ("cat LP.lp"); // cout << " box after LR " << box << endl; mylinearsolver->cleanConst(); } catch(EmptyBoxException&) { box.set_empty(); // empty the box before exiting in case of EmptyBoxException mylinearsolver->cleanConst(); throw EmptyBoxException(); } }
//------------------------------------------------------------------------------------------------------------- void CtcPixelMap::grid_to_world(IntervalVector& box) { for(unsigned int i = 0; i < I.ndim; i++) { box[i] &= Interval(pixel_coords[2*i], pixel_coords[2*i+1]+1) * I.leaf_size_[i] + I.origin_[i]; if(box[i].is_empty()){ box.set_empty(); return; } } }
void CtcInteger::contract(IntervalVector& box) { for (int i=0; i<nb_var; i++) { if (!is_int[i]) continue; proj_integer(box[i]); if (box[i].is_empty()) { box.set_empty(); throw EmptyBoxException(); } } }
void CtcInteger::contract(IntervalVector& box, const BoolMask& impact) { for (int i=0; i<nb_var; i++) { if (is_int[i] && impact[i]) { proj_integer(box[i]); if (box[i].is_empty()) { box.set_empty(); throw EmptyBoxException(); } } } }
void CtcIn::contract(IntervalVector& box) { // it's simpler here to use direct computation, but // we could also have used CtcFwdBwd try { HC4Revise().proj(_f,_d,box); } catch (EmptyBoxException& e) { box.set_empty(); throw e; } }
void CtcSegment::contract(IntervalVector &box) { if (nb_var==6) { ctc_f->contract(box); if (box.is_empty()) return; ctc_g->contract(box); } else { X_with_params[0] = box[0]; X_with_params[1] = box[1]; // X_with_params=cart_prod(box,) ctc_f->contract(X_with_params); if (X_with_params.is_empty()) { box.set_empty(); return; } ctc_g->contract(X_with_params); if (X_with_params.is_empty()) { box.set_empty(); return; } // box = X_with_params.subvector(0,1); box[0] = X_with_params[0]; box[1] = X_with_params[1]; } }
void CtcFirstOrderTest::contract(IntervalVector& box, ContractContext& context) { if(box.size() == 2) { return; } BxpNodeData* node_data = (BxpNodeData*) context.prop[BxpNodeData::id]; if(node_data == nullptr) { ibex_error("CtcFirstOrderTest: BxpNodeData must be set"); } vector<IntervalVector> gradients; for (int i = 0; i < system_.normal_constraints_.size() - 1; ++i) { if (!system_.normal_constraints_[i].isSatisfied(box)) { gradients.push_back(system_.normal_constraints_[i].gradient(box)); } } for (int i = 0; i < system_.sic_constraints_.size(); ++i) { if (!system_.sic_constraints_[i].isSatisfied(box, node_data->sic_constraints_caches[i])) { gradients.push_back(system_.sic_constraints_[i].gradient(box, node_data->sic_constraints_caches[i])); } } // Without the goal variable IntervalMatrix matrix(nb_var - 1, gradients.size() + 1); matrix.set_col(0, system_.goal_function_->gradient(box.subvector(0, nb_var - 2))); for (int i = 0; i < gradients.size(); ++i) { matrix.set_col(i + 1, gradients[i].subvector(0, nb_var - 2)); } bool testfailed = true; if (matrix.nb_cols() == 1) { if (matrix.col(0).contains(Vector::zeros(nb_var - 2))) { testfailed = false; } } else { int* pr = new int[matrix.nb_rows()]; int* pc = new int[matrix.nb_cols()]; IntervalMatrix LU(matrix.nb_rows(), matrix.nb_cols()); testfailed = true; try { interval_LU(matrix, LU, pr, pc); } catch(SingularMatrixException&) { testfailed = false; } delete[] pr; delete[] pc; } if(testfailed) { box.set_empty(); } }
void hansen_bliek(const IntervalMatrix& A, const IntervalVector& B, IntervalVector& x) { int n=A.nb_rows(); assert(n == A.nb_cols()); // throw NotSquareMatrixException(); assert(n == x.size() && n == B.size()); Matrix Id(n,n); for (int i=0; i<n; i++) for (int j=0; j<n; j++) { Id[i][j] = i==j; } IntervalMatrix radA(A-Id); Matrix InfA(Id-abs(radA.lb())); Matrix M(n,n); real_inverse(InfA, M); // may throw SingularMatrixException... for (int i=0; i<n; i++) for (int j=0; j<n; j++) if (! (M[i][j]>=0.0)) throw NotInversePositiveMatrixException(); Vector b(B.mid()); Vector delta = (B.ub())-b; Vector xstar = M * (abs(b)+delta); double xtildek, xutildek, nuk, max, min; for (int k=0; k<n; k++) { xtildek = (b[k]>=0) ? xstar[k] : xstar[k] + 2*M[k][k]*b[k]; xutildek = (b[k]<=0) ? -xstar[k] : -xstar[k] + 2*M[k][k]*b[k]; nuk = 1/(2*M[k][k]-1); max = nuk*xutildek; if (max < 0) max = 0; min = nuk*xtildek; if (min > 0) min = 0; /* compute bounds of x(k) */ if (xtildek >= max) { if (xutildek <= min) x[k] = Interval(xutildek,xtildek); else x[k] = Interval(max,xtildek); } else { if (xutildek <= min) x[k] = Interval(xutildek,min); else { x.set_empty(); return; } } } }
void CtcEmpty::contract(IntervalVector& box) { BoolInterval t= pdc.test(box); switch (t) { case YES: box.set_empty(); set_flag(FIXPOINT); break; case NO: // The constraint is inactive only if // the test is monotonous w.r.t. inclusion // set_flag(INACTIVE); break; default: break; } }
void CtcNotIn::contract(IntervalVector& box) { // it's simpler here to use direct computation, but // we could also have used CtCunion of two CtcFwdBwd IntervalVector savebox(box); try { HC4Revise().proj(f,d1,box); } catch (EmptyBoxException& ) {box.set_empty(); } try { HC4Revise().proj(f,d2,savebox); } catch (EmptyBoxException& ) {savebox.set_empty(); } box |= savebox; if (box.is_empty()) throw EmptyBoxException(); }
bool HC4Revise::proj(const Domain& y, IntervalVector& x) { eval.eval(x); //std::cout << "forward:" << std::endl; f.cf.print(d); bool is_inner=false; try { is_inner = backward(y); d.read_arg_domains(x); return is_inner; } catch(EmptyBoxException&) { x.set_empty(); return false; } }
void InHC4Revise::ibwd(const Function& f, const Domain& y, IntervalVector& x) { for (int i=0; i<f.nb_nodes(); i++) f.node(i).deco.p->set_empty(); Eval().eval(f,x); *f.expr().deco.d = y; try { f.backward<InHC4Revise>(*this); f.read_arg_domains(x); } catch(EmptyBoxException&) { x.set_empty(); } }
void Gradient::gradient(const Array<Domain>& d2, IntervalVector& gbox) { assert(f.expr().dim.is_scalar()); _eval.eval(d2); // outside definition domain -> empty gradient if (d.top->is_empty()) { gbox.set_empty(); return; } gbox.clear(); g.write_arg_domains(gbox); f.forward<Gradient>(*this); g.top->i()=1.0; f.backward<Gradient>(*this); g.read_arg_domains(gbox); }
void CtcForAll::contract(IntervalVector& x) { assert(x.size()==nb_var); IntervalVector box(nb_var+_init.size()); IntervalVector * sub; bool mdiam; int iter =0; box.put(0, x); std::list<IntervalVector> l; l.push_back(_init); std::pair<IntervalVector,IntervalVector> cut(_init,_init); while ((!l.empty())&&(iter<_max_iter)) { cut = _bsc.bisect(l.front()); l.pop_front(); sub = &(cut.first); for (int j=1;j<=2;j++) { if (j==2) sub = &(cut.second); for(int i=0; i< _init.size(); i++) { box[i+nb_var] = (*sub)[i].mid(); } // it is enough to contract only with the middle, it is more precise and faster. try { _ctc.contract(box); } catch (EmptyBoxException& e) { x.set_empty(); throw e; } mdiam=true; for (int i=0;mdiam&&(i<_init.size()); i++) mdiam = mdiam&&((*sub)[i].diam()<= _prec); if (!mdiam) { l.push_back(*sub); iter++; } } } for(int i=0; i< nb_var; i++) x[i] &= box[i]; if (x.is_empty()) throw EmptyBoxException(); }
void CtcSegment::contract(IntervalVector &box) { if (nb_var==6) { ctc_f->contract(box); ctc_g->contract(box); } else { try { X_with_params[0] = box[0]; X_with_params[1] = box[1]; // X_with_params=cart_prod(box,) ctc_f->contract(X_with_params); ctc_g->contract(X_with_params); // box = X_with_params.subvector(0,1); box[0] = X_with_params[0]; box[1] = X_with_params[1]; } catch(EmptyBoxException& e) { box.set_empty(); throw e; } } }
void Gradient::gradient(const IntervalVector& box, IntervalVector& gbox) { if (!f.expr().dim.is_scalar()) { ibex_error("Cannot called \"gradient\" on a vector-valued function"); } if (_eval.eval(box).is_empty()) { // outside definition domain -> empty gradient gbox.set_empty(); return; } gbox.clear(); g.write_arg_domains(gbox); f.forward<Gradient>(*this); g.top->i()=1.0; f.backward<Gradient>(*this); g.read_arg_domains(gbox); }
//---------------------------------------------------------------------------------------------------------------- void CtcPixelMap::contract(IntervalVector& box) { assert(box.size() == I.ndim); if(box.is_empty()) return; // Convert world coordinates into pixel coordinates world_to_grid(box); // Contractor the box if( I.ndim == 2) { contract(pixel_coords[0],pixel_coords[1],pixel_coords[2],pixel_coords[3]); } else if ( I.ndim == 3){ contract(pixel_coords[0],pixel_coords[1],pixel_coords[2],pixel_coords[3],pixel_coords[4],pixel_coords[5]); } // Check the result if(pixel_coords[0] == -1) { box.set_empty(); return; } // Convert pixel coordinates into world coordinates grid_to_world(box); }
void Gradient::gradient(const Function& f, const IntervalVector& box, IntervalVector& g) const { assert(f.expr().dim.is_scalar()); assert(f.expr().deco.d); assert(f.expr().deco.g); f.eval_domain(box); g.clear(); f.write_arg_domains(g,true); try { f.forward<Gradient>(*this); } catch(EmptyBoxException&) { g.set_empty(); return; } f.expr().deco.g->i()=1.0; f.backward<Gradient>(*this); f.read_arg_domains(g,true); }
void CtcKhunTucker::contract(IntervalVector& box) { if (df==NULL) return; // if (sys.nb_ctr==0) { // if (box.is_strict_interior_subset(sys.box)) { // // for unconstrained optimization we benefit from a cheap // // contraction with gradient=0, before running Newton. // // if (nb_var==1) // df->backward(Interval::ZERO,box); // else // df->backward(IntervalVector(nb_var,Interval::ZERO),box); // } // } // // if (box.is_empty()) return; //if (box.max_diam()>1e-1) return; // do we need a threshold? // ========================================================================================= BitSet active=sys.active_ctrs(box); FncKhunTucker fjf(sys,df,dg,box,BitSet::all(sys.nb_ctr)); //active); // we consider that Newton will not succeed if there are more // than n active constraints. if ((fjf.eq.empty() && fjf.nb_mult > sys.nb_var+1) || (!fjf.eq.empty() && fjf.nb_mult > sys.nb_var)) { //cout << fjf.nb_mult << endl; too_many_active++; return; } IntervalVector lambda=fjf.multiplier_domain(); IntervalVector old_lambda(lambda); int *pr; int *pc=new int[fjf.nb_mult]; IntervalMatrix A(fjf.eq.empty() ? sys.nb_var+1 : sys.nb_var, fjf.nb_mult); if (fjf.eq.empty()) { A.put(0,0, fjf.gradients(box)); A.put(sys.nb_var, 0, Vector::ones(fjf.nb_mult), true); // normalization equation pr = new int[sys.nb_var+1]; // selected rows } else { A = fjf.gradients(box); pr = new int[sys.nb_var]; // selected rows } IntervalMatrix LU(A); bool preprocess_success=false; try { IntervalMatrix A2(fjf.nb_mult, fjf.nb_mult); // if (A.nb_rows()>A.nb_cols()) { //cout << "A=" << A << endl; interval_LU(A,LU,pr,pc); lu_OK++; //cout << "LU success\n"; // } else // cout << "bypass LU\n"; Vector b2=Vector::zeros(fjf.nb_mult); for (int i=0; i<fjf.nb_mult; i++) { A2.set_row(i, A.row(pr[i])); if (pr[i]==sys.nb_var) // right-hand side of normalization is 1 b2[i]=1; } //cout << "\n\nA2=" << A2 << endl; precond(A2); //cout << "precond success\n"; precond_OK++; gauss_seidel(A2,b2,lambda); double maxdiam=0; for (int i=0; i<A.nb_rows(); i++) { double d=A.row(i).max_diam(); if (d>maxdiam) maxdiam=d; } if (old_lambda.rel_distance(lambda)>0.1 //&& maxdiam<10 && lambda[1].lb()>0 ) { preprocess_success=true; } if (lambda.is_empty()) { box.set_empty(); return; } } catch(SingularMatrixException&) { } delete[] pr; delete[] pc; if (!preprocess_success) return; CtcNewton newton(fjf,1); IntervalVector full_box = cart_prod(box, lambda); // ========================================================================================= // CtcNewton newton(fjc.f,1); // // IntervalVector full_box = cart_prod(box, IntervalVector(fjc.M+fjc.R+fjc.K+1,Interval(0,1))); // // full_box.put(fjc.n+fjc.M+fjc.R+1,IntervalVector(fjc.K,Interval::ZERO)); // ========================================================================================= IntervalVector save(full_box); newton.contract(full_box); if (full_box.is_empty()) { if (preprocess_success) newton_OK_preproc_OK++; else newton_OK_preproc_KO++; box.set_empty(); } else { if (save.subvector(0,sys.nb_var-1)!=full_box.subvector(0,sys.nb_var-1)) { if (preprocess_success) newton_OK_preproc_OK++; else newton_OK_preproc_KO++; box = full_box.subvector(0,sys.nb_var-1); } else { if (preprocess_success) { newton_KO_preproc_OK++; } else newton_KO_preproc_KO++; } } // ========================================================================================= }
void CtcEmpty::contract(IntervalVector& box) { if (pdc.test(box)==YES) { box.set_empty(); throw EmptyBoxException(); } }
bool inflating_newton(const Fnc& f, const VarSet* vars, const IntervalVector& full_box, IntervalVector& box_existence, IntervalVector& box_unicity, int k_max, double mu_max, double delta, double chi) { int n=vars ? vars->nb_var : f.nb_var(); assert(f.image_dim()==n); assert(full_box.size()==f.nb_var()); if (full_box.is_empty()) { box_existence.set_empty(); box_unicity.set_empty(); return false; } int k=0; bool success=false; IntervalVector mid(n); // Midpoint of the current box IntervalVector Fmid(n); // Evaluation of f at the midpoint IntervalMatrix J(n, n); // Hansen matrix of f % variables // Following variables are introduced just to use a // centered-form on parameters when evaluating Fmid IntervalVector* p=NULL; // Parameter box IntervalVector* midp=NULL; // Parameter box midpoint // ------------------------------------------------- IntervalMatrix* Jp=NULL; // Jacobian % parameters // if (vars) { p=new IntervalVector(vars->param_box(full_box)); midp=new IntervalVector(p->mid()); Jp=new IntervalMatrix(n,vars->nb_param); } IntervalVector y(n); IntervalVector y1(n); IntervalVector box = vars ? vars->var_box(full_box) : full_box; IntervalVector& full_mid = vars ? *new IntervalVector(full_box) : mid; // Warning: box_existence is used to store the full box of the // current iteration (that is, param_box x box) // It will eventually (at return) be the // existence box in case of success. Nothing is proven inside // box_existence until success==true in the loop (note: inflation // stops when success is true and existence is thus preserved // until the end) box_existence = full_box; // Just to quickly initialize the domains of parameters box_unicity = full_box; y1 = box.mid(); while (k<k_max) { //cout << "current box=" << box << endl << endl; if (vars) f.hansen_matrix(box_existence, J, *Jp, *vars); else f.hansen_matrix(box_existence, J); if (J.is_empty()) break; mid = box.mid(); if (vars) vars->set_var_box(full_mid, mid); Fmid=f.eval_vector(full_mid); // Use the jacobian % parameters to calculate // a mean-value form for Fmid if (vars) { Fmid &= f.eval_vector(vars->full_box(mid,*midp))+(*Jp)*(*p-*midp); } y = mid-box; //if (y==y1) break; <--- allowed in Newton inflation y1=y; try { precond(J, Fmid); } catch(LinearException&) { break; // should be false } // Note: giving mu_max to gauss-seidel (GS) is slightly different from checking the condition "mu<mu_max" in the // Newton procedure itself. If GS transforms x0 to x1 in n iterations, and then x1 to x2 in n other iterations // it is possible that each of these 2n iterations satisfies mu<mu_max, whereas the two global Newton iterations // do not, i.e., d(x2,x1) > mu_max d(x1,x0). if (!inflating_gauss_seidel(J, Fmid, y, 1e-12, mu_max)) {// TODO: replace hardcoded value 1e-12 // when k~kmax, "divergence" may also mean "cannot contract more" (d/dold~1) break; } IntervalVector box2=mid-y; if (box2.is_subset(box)) { assert(!box2.is_empty()); if (!success) { // to get the largest unicity box, we do this // only when the first contraction occurs if (vars) vars->set_var_box(box_unicity,box); else box_unicity = box; //================================================= // We now try to enlarge the unicity box as possible // ================================================= // IntervalVector box2copy=box2; // // bool inflate_ok=true; // // while (inflate_ok) { // // box2copy.inflate(delta,0.0); // // // box_existence is also used inside this iteration // // to store the "full box" // if (vars) vars->set_var_box(box_existence,box2copy); // else box_existence = box2copy; // // newton(f,vars,box_existence,0.0,default_gauss_seidel_ratio); // // if (vars) { // if (vars->var_box(box_existence).is_interior_subset(box2)) // vars->set_var_box(box_unicity,box2copy); // else inflate_ok=false; // } else { // if (box_existence.is_interior_subset(box2)) // box_unicity = box2copy; // else inflate_ok=false; // } // } } success=true; // we don't return now, to let the box being contracted more } box = success? box2 : box2.inflate(delta,chi); k++; // we update box_existence inside the loop because // the Jacobian has to be recalculated on the current // full box at each iteration if (vars) vars->set_var_box(box_existence,box); else box_existence = box; } if (vars) { delete p; delete midp; delete Jp; delete &full_mid; } if (!success) { box_existence.set_empty(); box_unicity.set_empty(); } return success; }
bool newton(const Fnc& f, const VarSet* vars, IntervalVector& full_box, double prec, double ratio_gauss_seidel) { int n=vars? vars->nb_var : f.nb_var(); int m=f.image_dim(); assert(full_box.size()==f.nb_var()); IntervalMatrix J(m, n); IntervalVector* p=NULL; // Parameter box IntervalVector* midp=NULL; // Parameter box midpoint IntervalMatrix* Jp=NULL; // Jacobian % parameters if (vars) { p=new IntervalVector(vars->param_box(full_box)); midp=new IntervalVector(p->mid()); Jp=new IntervalMatrix(m,vars->nb_param); } IntervalVector y(n); IntervalVector y1(n); IntervalVector mid(n); IntervalVector Fmid(m); bool reducted=false; double gain; IntervalVector& box = vars ? *new IntervalVector(vars->var_box(full_box)) : full_box; IntervalVector& full_mid = vars ? *new IntervalVector(full_box) : mid; y1 = box.mid(); do { if (vars) f.hansen_matrix(full_box,J,*Jp,*vars); else f.hansen_matrix(full_box,J); // f.jacobian(box,J); if (J.is_empty() || (vars && Jp->is_empty())) break; /* remove this block * for (int i=0; i<m; i++) for (int j=0; j<n; j++) if (J[i][j].is_unbounded()) return false; */ mid = box.mid(); if (vars) vars->set_var_box(full_mid, mid); Fmid = f.eval_vector(full_mid); // Use the jacobian % parameters to calculate // a mean-value form for Fmid if (vars) { Fmid &= f.eval_vector(vars->full_box(mid,*midp))+(*Jp)*(*p-*midp); } y = mid-box; if (y==y1) break; y1=y; try { precond(J, Fmid); gauss_seidel(J, Fmid, y, ratio_gauss_seidel); if (y.is_empty()) { reducted=true; if (vars) full_box.set_empty(); else box.set_empty(); break; } } catch (LinearException& ) { assert(!reducted); break; } IntervalVector box2=mid-y; if ((box2 &= box).is_empty()) { reducted=true; if (vars) full_box.set_empty(); else box.set_empty(); break; } gain = box.maxdelta(box2); if (gain >= prec) reducted = true; box=box2; if (vars) vars->set_var_box(full_box, box); } while (gain >= prec); if (vars) { delete p; delete midp; delete Jp; delete &box; delete &full_mid; } return reducted; }