void WP::maximize_hourly_pattern(){
   const Mat &count(suf()->count());
   const Mat &exposure(suf()->exposure());
   const Vec &delta(day_of_week_pattern());
   double lambda = average_daily_rate();
   Vec eta_weekend(24, 0.0);
   Vec eta_weekday(24, 0.0);
   for(int h = 0; h < 24; ++h){
     double total_count_weekday = 0;
     double total_exposure_weekday = 0;
     double total_count_weekend = 0;
     double total_exposure_weekend = 0;
     double *total_count;
     double *total_exposure;
     for(int d = 0; d < 7; ++d){
       if(d==Sat || d==Sun){
         total_exposure = &total_exposure_weekend;
         total_count = &total_count_weekend;
       }else{
         total_exposure = &total_exposure_weekday;
         total_count = &total_count_weekday;
       }
       *total_count += count(d, h);
       *total_exposure += exposure(d, h) * lambda * delta[d];
     }
     eta_weekend[h] = total_count_weekend / total_exposure_weekend;
     eta_weekday[h] = total_count_weekday / total_exposure_weekday;
   }
   set_weekday_hourly_pattern(eta_weekday);
   set_weekend_hourly_pattern(eta_weekend);
 }
  double WP::expected_number_of_events(const DateTime &t0,
                                       const DateTime &t1)const{
    double duration = t1 - t0;
    int weeks = lround(floor(duration / 7));
    double lambda = average_daily_rate();
    double ans = 7 * weeks * lambda;
    duration -= 7*weeks;

    const double one_hour = DateTime::hours_to_days(1.0);
    double time_to_next_hour = t0.time_to_next_hour();
    if(time_to_next_hour == 0) time_to_next_hour = one_hour;
    DayNames day = t0.date().day_of_week();
    int hour = t0.hour();
    double dt = std::min<double>(time_to_next_hour, duration);
    while(duration > 0){
      ans += dt * event_rate(day, hour);
      duration -= dt;
      ++hour;
      if(hour == 24){
        hour = 0;
        day = next(day);
      }
      dt = std::min<double>(one_hour, duration);
    }
    return ans;
  }
 void WP::mle() {
   double old_loglike = loglike(
       concatenate_params(average_daily_rate(), day_of_week_pattern(),
                          weekday_hourly_pattern(), weekend_hourly_pattern()));
   double dloglike = 1.0;
   while (dloglike > 1e-5) {
     maximize_average_daily_rate();
     maximize_daily_pattern();
     maximize_hourly_pattern();
     double new_loglike = loglike(concatenate_params(
         average_daily_rate(), day_of_week_pattern(), weekday_hourly_pattern(),
         weekend_hourly_pattern()));
     dloglike = new_loglike - old_loglike;
     old_loglike = new_loglike;
   }
 }
 void WP::maximize_daily_pattern(){
   const Mat &count(suf()->count());
   const Mat &exposure(suf()->exposure());
   Vec delta(7);
   double lambda = average_daily_rate();
   for(int d = 0; d < 7; ++d){
     const Vec &eta(hourly_pattern(d));
     double total_count = 0;
     double total_exposure = 0;
     for(int h = 0; h < 24; ++h){
       total_count += count(d, h);
       total_exposure += exposure(d, h) * lambda * eta[h];
     }
     delta[d] = total_count / total_exposure;
   }
   set_day_of_week_pattern(delta);
   // TODO(stevescott):  check that this enforces sum(delta) == 7
 }
 double WP::event_rate(const DayNames day, int hour)const{
   return average_daily_rate() *
       day_of_week_pattern()[day] *
       hourly_pattern(day)[hour];
 }