IncrementalScoringFunction::Data IncrementalScoringFunction::create_data(
    ParticleIndex pi, RestraintsTemp cr,
    const boost::unordered_map<Restraint *, int> &all,
    const Restraints &dummies) const {
  IMP_LOG_TERSE("Dependent restraints for particle "
                << get_model()->get_particle_name(pi) << " are " << cr
                << std::endl);
  Data ret;
  for (unsigned int j = 0; j < cr.size(); ++j) {
    if (all.find(cr[j]) != all.end()) {
      int index = all.find(cr[j])->second;
      IMP_INTERNAL_CHECK(
          std::find(ret.indexes.begin(), ret.indexes.end(), index) ==
              ret.indexes.end(),
          "Found duplicate restraint " << Showable(cr[j]) << " in list " << cr);
      ret.indexes.push_back(index);
    }
  }
  cr += RestraintsTemp(dummies.begin(), dummies.end());
  ret.sf = new IncrementalRestraintsScoringFunction(
      cr, 1.0, NO_MAX, get_model()->get_particle_name(pi) + " restraints");
  return ret;
}
SubsetGraph get_restraint_graph(ScoringFunctionAdaptor in,
                                const ParticleStatesTable *pst) {
  RestraintsTemp rs =
      IMP::create_decomposition(in->create_restraints());
  // ScoreStatesTemp ss= get_required_score_states(rs);
  SubsetGraph ret(rs.size());  // + ss.size());
  IMP_LOG_TERSE("Creating restraint graph on " << rs.size() << " restraints."
                                               << std::endl);
  boost::unordered_map<Particle *, int> map;
  SubsetGraphVertexName pm = boost::get(boost::vertex_name, ret);
  DependencyGraph dg = get_dependency_graph(rs[0]->get_model());
  DependencyGraphVertexIndex index = IMP::get_vertex_index(dg);
  /*IMP_IF_LOG(VERBOSE) {
    IMP_LOG_VERBOSE( "dependency graph is \n");
    IMP::internal::show_as_graphviz(dg, std::cout);
    }*/
  Subset ps = pst->get_subset();
  for (unsigned int i = 0; i < ps.size(); ++i) {
    ParticlesTemp t = get_dependent_particles(
        ps[i], ParticlesTemp(ps.begin(), ps.end()), dg, index);
    for (unsigned int j = 0; j < t.size(); ++j) {
      IMP_USAGE_CHECK(map.find(t[j]) == map.end(),
                      "Currently particles which depend on more "
                          << "than one particle "
                          << "from the input set are not supported."
                          << "  Particle \"" << t[j]->get_name()
                          << "\" depends on \"" << ps[i]->get_name()
                          << "\" and \""
                          << ps[map.find(t[j])->second]->get_name() << "\"");
      map[t[j]] = i;
    }
    IMP_IF_LOG(VERBOSE) {
      IMP_LOG_VERBOSE("Particle \"" << ps[i]->get_name() << "\" controls ");
      for (unsigned int i = 0; i < t.size(); ++i) {
        IMP_LOG_VERBOSE("\"" << t[i]->get_name() << "\" ");
      }
      IMP_LOG_VERBOSE(std::endl);
    }
  }
  for (unsigned int i = 0; i < rs.size(); ++i) {
    ParticlesTemp pl = IMP::get_input_particles(rs[i]->get_inputs());
    std::sort(pl.begin(), pl.end());
    pl.erase(std::unique(pl.begin(), pl.end()), pl.end());
    Subset os(pl);
    for (unsigned int j = 0; j < pl.size(); ++j) {
      pl[j] = ps[map[pl[j]]];
    }
    std::sort(pl.begin(), pl.end());
    pl.erase(std::unique(pl.begin(), pl.end()), pl.end());
    Subset s(pl);
    IMP_LOG_VERBOSE("Subset for restraint " << rs[i]->get_name() << " is " << s
                                            << " from " << os << std::endl);
    pm[i] = s;
  }
  /*ScoreStatesTemp ss= get_required_score_states(rs);
    for (ScoreStatesTemp::const_iterator it= ss.begin();
    it != ss.end(); ++it) {
    ParticlesTemp pl= (*it)->get_input_particles();
    add_edges(ps, pl, map, *it, ret);
    ParticlesTemp opl= (*it)->get_output_particles();
    add_edges(ps, opl, map, *it, ret);
    }
    IMP_INTERNAL_CHECK(boost::num_vertices(ret) == ps.size(),
    "Wrong number of vertices "
    << boost::num_vertices(ret)
    << " vs " << ps.size());*/
  for (unsigned int i = 0; i < boost::num_vertices(ret); ++i) {
    for (unsigned int j = 0; j < i; ++j) {
      if (get_intersection(pm[i], pm[j]).size() > 0) {
        boost::add_edge(i, j, ret);
        IMP_LOG_VERBOSE("Connecting " << rs[i]->get_name() << " with "
                                      << rs[j]->get_name() << std::endl);
      }
    }
  }
  return ret;
}
double
get_slack_estimate(const ParticlesTemp& ps,
                   double upper_bound,
                   double step,
                   const RestraintsTemp &restraints,
                   bool derivatives,
                   Optimizer *opt,
                   ClosePairContainer *cpc) {
  std::vector<Data> datas;
  for (double slack=0; slack< upper_bound; slack+= step) {
    IMP_LOG(VERBOSE, "Computing for " << slack << std::endl);
    datas.push_back(Data());
    datas.back().slack=slack;
    {
      boost::timer imp_timer;
      int count=0;
      base::SetLogState sl(opt->get_model(), SILENT);
      do {
        cpc->set_slack(slack);
        cpc->update();
        ++count;
      } while (imp_timer.elapsed()==0);
      datas.back().ccost= imp_timer.elapsed()/count;
      IMP_LOG(VERBOSE, "Close pair finding cost "
              << datas.back().ccost << std::endl);
    }
    {
      boost::timer imp_timer;
      double score=0;
      int count=0;
      int iters=1;
      base::SetLogState sl(opt->get_model(), SILENT);
      do {
        for ( int j=0; j< iters; ++j) {
          for (unsigned int i=0; i< restraints.size(); ++i) {
            score+=restraints[i]->evaluate(derivatives);
            // should restore
          }
        }
        count += iters;
        iters*=2;
      } while (imp_timer.elapsed()==0);
      datas.back().rcost= imp_timer.elapsed()/count;
      IMP_LOG(VERBOSE, "Restraint evaluation cost "
              << datas.back().rcost << std::endl);
    }
  }
  int ns=100;
  int last_ns=1;
  int opt_i=-1;
  std::vector<Floats > dists(1, Floats(1,0.0));
  std::vector< std::vector<algebra::Vector3D> >
    pos(1, std::vector<algebra::Vector3D>(ps.size()));
  for (unsigned int j=0; j< ps.size(); ++j) {
    pos[0][j]=core::XYZ(ps[j]).get_coordinates();
  }
  do {
    IMP_LOG(VERBOSE, "Stepping from " << last_ns << " to " << ns << std::endl);
    dists.resize(ns, Floats(ns, 0.0));
    for ( int i=0; i< last_ns; ++i) {
      dists[i].resize(ns, 0.0);
    }
    pos.resize(ns,  std::vector<algebra::Vector3D>(ps.size()));
    base::SetLogState sl(opt->get_model(), SILENT);
    for ( int i=last_ns; i< ns; ++i) {
      opt->optimize(1);
      for (unsigned int j=0; j< ps.size(); ++j) {
        pos[i][j]=core::XYZ(ps[j]).get_coordinates();
      }
    }
    for ( int i=last_ns; i< ns; ++i) {
      for ( int j=0; j< i; ++j) {
        double md=0;
        for (unsigned int k=0; k< ps.size(); ++k) {
          md= std::max(md, algebra::get_distance(pos[i][k], pos[j][k]));
        }
        dists[i][j]=md;
        dists[j][i]=md;
      }
    }
    // estimate lifetimes from slack
    for (unsigned int i=0; i< datas.size(); ++i) {
      Ints deaths;
      for ( int j=0; j< ns; ++j) {
        for ( int k=j+1; k < ns; ++k) {
          if (dists[j][k]> datas[i].slack) {
            deaths.push_back(k-j);
            break;
          }
        }
      }
      std::sort(deaths.begin(), deaths.end());
      // kaplan meier estimator
      double ml=0;
      if (deaths.empty()) {
        ml= ns;
      } else {
        //double l=1;
        IMP_INTERNAL_CHECK(deaths.size() < static_cast<unsigned int>(ns),
                           "Too much death");
        double S=1;
        for (unsigned int j=0; j< deaths.size(); ++j) {
          double n= ns-j;
          double t=(n-1.0)/n;
          ml+=(S-t*S)*deaths[j];
          S*=t;
        }
      }
      datas[i].lifetime=ml;
      IMP_LOG(VERBOSE, "Expected life of " << datas[i].slack
              << " is " << datas[i].lifetime << std::endl);
    }

    /**
       C(s) is cost to compute
       R(s) is const to eval restraints
       L(s) is lifetime of slack
       minimize C(s)/L(s)+R(s)
    */
    // smooth
    for (unsigned int i=1; i< datas.size()-1; ++i) {
      datas[i].rcost=(datas[i].rcost+ datas[i-1].rcost+datas[i+1].rcost)/3.0;
      datas[i].ccost=(datas[i].ccost+ datas[i-1].ccost+datas[i+1].ccost)/3.0;
      datas[i].lifetime=(datas[i].lifetime
                      + datas[i-1].lifetime+datas[i+1].lifetime)/3.0;
    }
    double min= std::numeric_limits<double>::max();
    for (unsigned int i=0; i< datas.size(); ++i) {
      double v= datas[i].rcost+ datas[i].ccost/datas[i].lifetime;
      IMP_LOG(VERBOSE, "Cost of " << datas[i].slack << " is " << v
              << " from " << datas[i].rcost
              << " " << datas[i].ccost << " " << datas[i].lifetime
              << std::endl);
      if (v < min) {
        min=v;
        opt_i=i;
      }
    }
    last_ns=ns;
    ns*=2;
    IMP_LOG(VERBOSE, "Opt is " << datas[opt_i].slack << std::endl);
    // 2 for the value, 2 for the doubling
    // if it more than 1000, just decide that is enough
  } while (datas[opt_i].lifetime > ns/4.0 && ns <1000);
  return datas[opt_i].slack;
}