<commit_before>// Copyright 2010-2012 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This model implements a simple jobshop problem with
// earlyness-tardiness costs.
//
// A earlyness-tardinessjobshop is a standard scheduling problem where
// you must schedule a set of jobs on a set of machines.  Each job is
// a sequence of tasks (a task can only start when the preceding task
// finished), each of which occupies a single specific machine during
// a specific duration. Therefore, a job is a sequence of pairs
// (machine id, duration), along with a release data (minimum start
// date of the first task of the job, and due data (end time of the
// last job) with a tardiness linear penalty.

// The objective is to minimize the sum of early-tardy penalties for each job.
//
// This will be modelled by sets of intervals variables (see class
// IntervalVar in constraint_solver/constraint_solver.h), one per
// task, representing the [start_time, end_time] of the task.  Tasks
// in the same job will be linked by precedence constraints.  Tasks on
// the same machine will be covered by Sequence constraints.

#include <cstdio>
#include <cstdlib>

#include <vector>

#include "base/commandlineflags.h"
#include "base/commandlineflags.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/stringprintf.h"
#include "constraint_solver/constraint_solver.h"
#include "linear_solver/linear_solver.h"
#include "util/string_array.h"
#include "cpp/jobshop_earlytardy.h"

DEFINE_string(
    jet_file,
    "",
    "Required: input file description the scheduling problem to solve, "
    "in our jet format:\n"
    "  - the first line is \"<number of jobs> <number of machines>\"\n"
    "  - then one line per job, with a single space-separated "
    "list of \"<machine index> <duration>\", ended by due_date, early_cost,"
    "late_cost\n"
    "note: jobs with one task are not supported");
DEFINE_int32(machine_count, 10, "Machine count");
DEFINE_int32(job_count, 10, "Job count");
DEFINE_int32(max_release_date, 0, "Max release date");
DEFINE_int32(max_early_cost, 0, "Max earlyness weight");
DEFINE_int32(max_tardy_cost, 3, "Max tardiness weight");
DEFINE_int32(max_duration, 10, "Max duration of a task");
DEFINE_int32(scale_factor, 130, "Scale factor (in percent)");
DEFINE_int32(seed, 1, "Random seed");
DEFINE_int32(time_limit_in_ms, 0, "Time limit in ms, 0 means no limit.");
DEFINE_bool(time_placement, false, "Use MIP based time placement");
DECLARE_bool(log_prefix);

namespace operations_research {
class TimePlacement : public DecisionBuilder {
 public:
  TimePlacement(const EtJobShopData& data,
                const std::vector<SequenceVar*>& all_sequences,
                const std::vector<std::vector<IntervalVar*> >& jobs_to_tasks)
      : data_(data),
        all_sequences_(all_sequences),
        jobs_to_tasks_(jobs_to_tasks),
        horizon_(data_.horizon()),
        mp_solver_("TimePlacement", MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING),
        num_tasks_(0) {
    for (int i = 0; i < jobs_to_tasks_.size(); ++i) {
      num_tasks_ += jobs_to_tasks_[i].size();
    }
  }

  virtual ~TimePlacement() {}

  virtual Decision* Next(Solver* const solver) {
    mp_solver_.Clear();
    std::vector<std::vector<MPVariable*> > all_vars;
    hash_map<IntervalVar*, MPVariable*> mapping;
    const double infinity = mp_solver_.infinity();
    all_vars.resize(all_sequences_.size());

    // Creates the MP Variables.
    for (int s = 0; s < jobs_to_tasks_.size(); ++s) {
      for (int t = 0; t < jobs_to_tasks_[s].size(); ++t) {
        IntervalVar* const task = jobs_to_tasks_[s][t];
        const string name = StringPrintf("J%dT%d", s, t);
        MPVariable* const var =
            mp_solver_.MakeIntVar(task->StartMin(), task->StartMax(), name);
        mapping[task] = var;
      }
    }

      // Adds the jobs precedence constraints.
    for (int j = 0; j < jobs_to_tasks_.size(); ++j) {
      for (int t = 0; t < jobs_to_tasks_[j].size() - 1; ++t) {
        IntervalVar* const first_task = jobs_to_tasks_[j][t];
        const int duration = first_task->DurationMax();
        IntervalVar* const second_task = jobs_to_tasks_[j][t + 1];
        MPVariable* const first_var = mapping[first_task];
        MPVariable* const second_var = mapping[second_task];
        MPConstraint* const ct =
            mp_solver_.MakeRowConstraint(duration, infinity);
        ct->SetCoefficient(second_var, 1.0);
        ct->SetCoefficient(first_var, -1.0);
      }
    }

    // Adds the ranked machines constraints.
    for (int s = 0; s < all_sequences_.size(); ++s) {
      SequenceVar* const sequence = all_sequences_[s];
      std::vector<int> rank_firsts;
      std::vector<int> rank_lasts;
      std::vector<int> unperformed;
      sequence->FillSequence(&rank_firsts, &rank_lasts, &unperformed);
      CHECK_EQ(0, rank_lasts.size());
      CHECK_EQ(0, unperformed.size());
      for (int i = 0; i < rank_firsts.size() - 1; ++i) {
        IntervalVar* const first_task = sequence->Interval(rank_firsts[i]);
        const int duration = first_task->DurationMax();
        IntervalVar* const second_task = sequence->Interval(rank_firsts[i + 1]);
        MPVariable* const first_var = mapping[first_task];
        MPVariable* const second_var = mapping[second_task];
        MPConstraint* const ct =
            mp_solver_.MakeRowConstraint(duration, infinity);
        ct->SetCoefficient(second_var, 1.0);
        ct->SetCoefficient(first_var, -1.0);
      }
    }

    // Creates penalty terms and objective.
    std::vector<MPVariable*> terms;
    mp_solver_.MakeIntVarArray(jobs_to_tasks_.size(),
                               0,
                               infinity,
                               "terms",
                               &terms);
    for (int j = 0; j < jobs_to_tasks_.size(); ++j) {
      mp_solver_.MutableObjective()->SetCoefficient(terms[j], 1.0);
    }
    mp_solver_.MutableObjective()->SetMinimization();

    // Forces penalty terms to be above late and early costs.
    for (int j = 0; j < jobs_to_tasks_.size(); ++j) {
      IntervalVar* const last_task = jobs_to_tasks_[j].back();
      const int duration = last_task->DurationMin();
      MPVariable* const mp_start = mapping[last_task];
      const Job& job = data_.GetJob(j);
      const int ideal_start = job.due_date - duration;
      const int early_offset = job.early_cost * ideal_start;
      MPConstraint* const early_ct =
          mp_solver_.MakeRowConstraint(early_offset, infinity);
      early_ct->SetCoefficient(terms[j], 1);
      early_ct->SetCoefficient(mp_start, job.early_cost);

      const int tardy_offset = job.tardy_cost * ideal_start;
      MPConstraint* const tardy_ct =
          mp_solver_.MakeRowConstraint(-tardy_offset, infinity);
      tardy_ct->SetCoefficient(terms[j], 1);
      tardy_ct->SetCoefficient(mp_start, -job.tardy_cost);
    }

    // Solve.
    CHECK_EQ(MPSolver::OPTIMAL, mp_solver_.Solve());

    // Inject MIP solution into the CP part.
    LOG(INFO) << "MP cost = " << mp_solver_.objective_value();
    for (int j = 0; j < jobs_to_tasks_.size(); ++j) {
      for (int t = 0; t < jobs_to_tasks_[j].size(); ++t) {
        IntervalVar* const first_task = jobs_to_tasks_[j][t];
        MPVariable* const first_var = mapping[first_task];
        const int date = first_var->solution_value();
        first_task->SetStartRange(date, date);
      }
    }
    return NULL;
  }

  virtual string DebugString() const {
    return "TimePlacement";
  }

 private:
  const EtJobShopData& data_;
  const std::vector<SequenceVar*>& all_sequences_;
  const std::vector<std::vector<IntervalVar*> >& jobs_to_tasks_;
  const int horizon_;
  MPSolver mp_solver_;
  int num_tasks_;
};

void EtJobShop(const EtJobShopData& data) {
  Solver solver("et_jobshop");
  const int machine_count = data.machine_count();
  const int job_count = data.job_count();
  const int horizon = data.horizon();

  // ----- Creates all Intervals and vars -----

  // Stores all tasks attached interval variables per job.
  std::vector<std::vector<IntervalVar*> > jobs_to_tasks(job_count);
  // machines_to_tasks stores the same interval variables as above, but
  // grouped my machines instead of grouped by jobs.
  std::vector<std::vector<IntervalVar*> > machines_to_tasks(machine_count);

  // Creates all individual interval variables.
  for (int job_id = 0; job_id < job_count; ++job_id) {
    const Job& job = data.GetJob(job_id);
    const std::vector<Task>& tasks = job.all_tasks;
    for (int task_index = 0; task_index < tasks.size(); ++task_index) {
      const Task& task = tasks[task_index];
      CHECK_EQ(job_id, task.job_id);
      const string name = StringPrintf("J%dM%dI%dD%d",
                                       task.job_id,
                                       task.machine_id,
                                       task_index,
                                       task.duration);
      IntervalVar* const one_task =
          solver.MakeFixedDurationIntervalVar(0,
                                              horizon,
                                              task.duration,
                                              false,
                                              name);
      jobs_to_tasks[task.job_id].push_back(one_task);
      machines_to_tasks[task.machine_id].push_back(one_task);
    }
  }

  // ----- Creates model -----

  // Creates precedences inside jobs.
  for (int job_id = 0; job_id < job_count; ++job_id) {
    const int task_count = jobs_to_tasks[job_id].size();
    for (int task_index = 0; task_index < task_count - 1; ++task_index) {
      IntervalVar* const t1 = jobs_to_tasks[job_id][task_index];
      IntervalVar* const t2 = jobs_to_tasks[job_id][task_index + 1];
      Constraint* const prec =
          solver.MakeIntervalVarRelation(t2, Solver::STARTS_AFTER_END, t1);
      solver.AddConstraint(prec);
    }
  }

  // Add release date.
  for (int job_id = 0; job_id < job_count; ++job_id) {
    const Job& job = data.GetJob(job_id);
    IntervalVar* const t = jobs_to_tasks[job_id][0];
    Constraint* const prec =
        solver.MakeIntervalVarRelation(t,
                                       Solver::STARTS_AFTER,
                                       job.release_date);
    solver.AddConstraint(prec);
  }

  std::vector<IntVar*> penalties;
  for (int job_id = 0; job_id < job_count; ++job_id) {
    const Job& job = data.GetJob(job_id);
    IntervalVar* const t = jobs_to_tasks[job_id][machine_count - 1];
    IntVar* const penalty =
        solver.MakeConvexPiecewiseExpr(t->EndExpr(),
                                       job.early_cost,
                                       job.due_date,
                                       job.due_date,
                                       job.tardy_cost)->Var();
    penalties.push_back(penalty);
  }

  // Adds disjunctive constraints on unary resources.
  for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
    solver.AddConstraint(
        solver.MakeDisjunctiveConstraint(machines_to_tasks[machine_id]));
  }

  // Creates sequences variables on machines. A sequence variable is a
  // dedicated variable whose job is to sequence interval variables.
  std::vector<SequenceVar*> all_sequences;
  for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
    const string name = StringPrintf("Machine_%d", machine_id);
    SequenceVar* const sequence =
        solver.MakeSequenceVar(machines_to_tasks[machine_id], name);
    all_sequences.push_back(sequence);
  }

  // Objective: minimize the weighted penalties.
  IntVar* const objective_var = solver.MakeSum(penalties)->Var();
  OptimizeVar* const objective_monitor = solver.MakeMinimize(objective_var, 1);

  // ----- Search monitors and decision builder -----

  // This decision builder will rank all tasks on all machines.
  DecisionBuilder* const sequence_phase =
      solver.MakePhase(all_sequences, Solver::SEQUENCE_DEFAULT);

  // After the ranking of tasks, the schedule is still loose and any
  // task can be postponed at will. But, because the problem is now a PERT
  // (http://en.wikipedia.org/wiki/Program_Evaluation_and_Review_Technique),
  // we can schedule each task at its earliest start time. This is
  // conveniently done by fixing the objective variable to its
  // minimum value.
  DecisionBuilder* const obj_phase =
      FLAGS_time_placement ?
      solver.RevAlloc(new TimePlacement(data, all_sequences, jobs_to_tasks)) :
      solver.MakePhase(objective_var,
                       Solver::CHOOSE_FIRST_UNBOUND,
                       Solver::ASSIGN_MIN_VALUE);

  // The main decision builder (ranks all tasks, then fixes the
  // objective_variable).
  DecisionBuilder* const main_phase =
      solver.Compose(sequence_phase, obj_phase);

  // Search log.
  const int kLogFrequency = 1000000;
  SearchMonitor* const search_log =
      solver.MakeSearchLog(kLogFrequency, objective_monitor);

  SearchLimit* limit = NULL;
  if (FLAGS_time_limit_in_ms > 0) {
    limit = solver.MakeTimeLimit(FLAGS_time_limit_in_ms);
  }

  // Search.
  solver.Solve(main_phase, search_log, objective_monitor, limit);
}
}  // namespace operations_research

static const char kUsage[] =
    "Usage: see flags.\nThis program runs a simple job shop optimization "
    "output besides the debug LOGs of the solver.";

int main(int argc, char **argv) {
  FLAGS_log_prefix = false;
  google::SetUsageMessage(kUsage);
  google::ParseCommandLineFlags(&argc, &argv, true);
  operations_research::EtJobShopData data;
  if (!FLAGS_jet_file.empty()) {
    data.LoadJetFile(FLAGS_jet_file);
  } else {
    data.GenerateRandomData(FLAGS_machine_count,
                            FLAGS_job_count,
                            FLAGS_max_release_date,
                            FLAGS_max_early_cost,
                            FLAGS_max_tardy_cost,
                            FLAGS_max_duration,
                            FLAGS_scale_factor,
                            FLAGS_seed);
  }
  operations_research::EtJobShop(data);
  return 0;
}
<commit_msg>implement time placement code for early tardy<commit_after>// Copyright 2010-2012 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This model implements a simple jobshop problem with
// earlyness-tardiness costs.
//
// A earlyness-tardinessjobshop is a standard scheduling problem where
// you must schedule a set of jobs on a set of machines.  Each job is
// a sequence of tasks (a task can only start when the preceding task
// finished), each of which occupies a single specific machine during
// a specific duration. Therefore, a job is a sequence of pairs
// (machine id, duration), along with a release data (minimum start
// date of the first task of the job, and due data (end time of the
// last job) with a tardiness linear penalty.

// The objective is to minimize the sum of early-tardy penalties for each job.
//
// This will be modelled by sets of intervals variables (see class
// IntervalVar in constraint_solver/constraint_solver.h), one per
// task, representing the [start_time, end_time] of the task.  Tasks
// in the same job will be linked by precedence constraints.  Tasks on
// the same machine will be covered by Sequence constraints.

#include <cstdio>
#include <cstdlib>

#include <vector>

#include "base/commandlineflags.h"
#include "base/commandlineflags.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/stringprintf.h"
#include "constraint_solver/constraint_solver.h"
#include "linear_solver/linear_solver.h"
#include "util/string_array.h"
#include "cpp/jobshop_earlytardy.h"

DEFINE_string(
    jet_file,
    "",
    "Required: input file description the scheduling problem to solve, "
    "in our jet format:\n"
    "  - the first line is \"<number of jobs> <number of machines>\"\n"
    "  - then one line per job, with a single space-separated "
    "list of \"<machine index> <duration>\", ended by due_date, early_cost,"
    "late_cost\n"
    "note: jobs with one task are not supported");
DEFINE_int32(machine_count, 10, "Machine count");
DEFINE_int32(job_count, 10, "Job count");
DEFINE_int32(max_release_date, 0, "Max release date");
DEFINE_int32(max_early_cost, 0, "Max earlyness weight");
DEFINE_int32(max_tardy_cost, 3, "Max tardiness weight");
DEFINE_int32(max_duration, 10, "Max duration of a task");
DEFINE_int32(scale_factor, 130, "Scale factor (in percent)");
DEFINE_int32(seed, 1, "Random seed");
DEFINE_int32(time_limit_in_ms, 0, "Time limit in ms, 0 means no limit.");
DEFINE_bool(time_placement, false, "Use MIP based time placement");
DECLARE_bool(log_prefix);

namespace operations_research {
class TimePlacement : public DecisionBuilder {
 public:
  TimePlacement(const EtJobShopData& data,
                const std::vector<SequenceVar*>& all_sequences,
                const std::vector<std::vector<IntervalVar*> >& jobs_to_tasks)
      : data_(data),
        all_sequences_(all_sequences),
        jobs_to_tasks_(jobs_to_tasks),
        mp_solver_("TimePlacement", MPSolver::GLPK_MIXED_INTEGER_PROGRAMMING),
        num_tasks_(0) {
    for (int i = 0; i < jobs_to_tasks_.size(); ++i) {
      num_tasks_ += jobs_to_tasks_[i].size();
    }
  }

  virtual ~TimePlacement() {}

  virtual Decision* Next(Solver* const solver) {
    mp_solver_.Clear();
    std::vector<std::vector<MPVariable*> > all_vars;
    hash_map<IntervalVar*, MPVariable*> mapping;
    const double infinity = mp_solver_.infinity();
    all_vars.resize(all_sequences_.size());

    // Creates the MP Variables.
    for (int s = 0; s < jobs_to_tasks_.size(); ++s) {
      for (int t = 0; t < jobs_to_tasks_[s].size(); ++t) {
        IntervalVar* const task = jobs_to_tasks_[s][t];
        const string name = StringPrintf("J%dT%d", s, t);
        MPVariable* const var =
            mp_solver_.MakeIntVar(task->StartMin(), task->StartMax(), name);
        mapping[task] = var;
      }
    }

      // Adds the jobs precedence constraints.
    for (int j = 0; j < jobs_to_tasks_.size(); ++j) {
      for (int t = 0; t < jobs_to_tasks_[j].size() - 1; ++t) {
        IntervalVar* const first_task = jobs_to_tasks_[j][t];
        const int duration = first_task->DurationMax();
        IntervalVar* const second_task = jobs_to_tasks_[j][t + 1];
        MPVariable* const first_var = mapping[first_task];
        MPVariable* const second_var = mapping[second_task];
        MPConstraint* const ct =
            mp_solver_.MakeRowConstraint(duration, infinity);
        ct->SetCoefficient(second_var, 1.0);
        ct->SetCoefficient(first_var, -1.0);
      }
    }

    // Adds the ranked machines constraints.
    for (int s = 0; s < all_sequences_.size(); ++s) {
      SequenceVar* const sequence = all_sequences_[s];
      std::vector<int> rank_firsts;
      std::vector<int> rank_lasts;
      std::vector<int> unperformed;
      sequence->FillSequence(&rank_firsts, &rank_lasts, &unperformed);
      CHECK_EQ(0, rank_lasts.size());
      CHECK_EQ(0, unperformed.size());
      for (int i = 0; i < rank_firsts.size() - 1; ++i) {
        IntervalVar* const first_task = sequence->Interval(rank_firsts[i]);
        const int duration = first_task->DurationMax();
        IntervalVar* const second_task = sequence->Interval(rank_firsts[i + 1]);
        MPVariable* const first_var = mapping[first_task];
        MPVariable* const second_var = mapping[second_task];
        MPConstraint* const ct =
            mp_solver_.MakeRowConstraint(duration, infinity);
        ct->SetCoefficient(second_var, 1.0);
        ct->SetCoefficient(first_var, -1.0);
      }
    }

    // Creates penalty terms and objective.
    std::vector<MPVariable*> terms;
    mp_solver_.MakeIntVarArray(jobs_to_tasks_.size(),
                               0,
                               infinity,
                               "terms",
                               &terms);
    for (int j = 0; j < jobs_to_tasks_.size(); ++j) {
      mp_solver_.MutableObjective()->SetCoefficient(terms[j], 1.0);
    }
    mp_solver_.MutableObjective()->SetMinimization();

    // Forces penalty terms to be above late and early costs.
    for (int j = 0; j < jobs_to_tasks_.size(); ++j) {
      IntervalVar* const last_task = jobs_to_tasks_[j].back();
      const int duration = last_task->DurationMin();
      MPVariable* const mp_start = mapping[last_task];
      const Job& job = data_.GetJob(j);
      const int ideal_start = job.due_date - duration;
      const int early_offset = job.early_cost * ideal_start;
      MPConstraint* const early_ct =
          mp_solver_.MakeRowConstraint(early_offset, infinity);
      early_ct->SetCoefficient(terms[j], 1);
      early_ct->SetCoefficient(mp_start, job.early_cost);

      const int tardy_offset = job.tardy_cost * ideal_start;
      MPConstraint* const tardy_ct =
          mp_solver_.MakeRowConstraint(-tardy_offset, infinity);
      tardy_ct->SetCoefficient(terms[j], 1);
      tardy_ct->SetCoefficient(mp_start, -job.tardy_cost);
    }

    // Solve.
    CHECK_EQ(MPSolver::OPTIMAL, mp_solver_.Solve());

    // Inject MIP solution into the CP part.
    LOG(INFO) << "MP cost = " << mp_solver_.objective_value();
    for (int j = 0; j < jobs_to_tasks_.size(); ++j) {
      for (int t = 0; t < jobs_to_tasks_[j].size(); ++t) {
        IntervalVar* const first_task = jobs_to_tasks_[j][t];
        MPVariable* const first_var = mapping[first_task];
        const int date = first_var->solution_value();
        first_task->SetStartRange(date, date);
      }
    }
    return NULL;
  }

  virtual string DebugString() const {
    return "TimePlacement";
  }

 private:
  const EtJobShopData& data_;
  const std::vector<SequenceVar*>& all_sequences_;
  const std::vector<std::vector<IntervalVar*> >& jobs_to_tasks_;
  MPSolver mp_solver_;
  int num_tasks_;
};

void EtJobShop(const EtJobShopData& data) {
  Solver solver("et_jobshop");
  const int machine_count = data.machine_count();
  const int job_count = data.job_count();
  const int horizon = data.horizon();

  // ----- Creates all Intervals and vars -----

  // Stores all tasks attached interval variables per job.
  std::vector<std::vector<IntervalVar*> > jobs_to_tasks(job_count);
  // machines_to_tasks stores the same interval variables as above, but
  // grouped my machines instead of grouped by jobs.
  std::vector<std::vector<IntervalVar*> > machines_to_tasks(machine_count);

  // Creates all individual interval variables.
  for (int job_id = 0; job_id < job_count; ++job_id) {
    const Job& job = data.GetJob(job_id);
    const std::vector<Task>& tasks = job.all_tasks;
    for (int task_index = 0; task_index < tasks.size(); ++task_index) {
      const Task& task = tasks[task_index];
      CHECK_EQ(job_id, task.job_id);
      const string name = StringPrintf("J%dM%dI%dD%d",
                                       task.job_id,
                                       task.machine_id,
                                       task_index,
                                       task.duration);
      IntervalVar* const one_task =
          solver.MakeFixedDurationIntervalVar(0,
                                              horizon,
                                              task.duration,
                                              false,
                                              name);
      jobs_to_tasks[task.job_id].push_back(one_task);
      machines_to_tasks[task.machine_id].push_back(one_task);
    }
  }

  // ----- Creates model -----

  // Creates precedences inside jobs.
  for (int job_id = 0; job_id < job_count; ++job_id) {
    const int task_count = jobs_to_tasks[job_id].size();
    for (int task_index = 0; task_index < task_count - 1; ++task_index) {
      IntervalVar* const t1 = jobs_to_tasks[job_id][task_index];
      IntervalVar* const t2 = jobs_to_tasks[job_id][task_index + 1];
      Constraint* const prec =
          solver.MakeIntervalVarRelation(t2, Solver::STARTS_AFTER_END, t1);
      solver.AddConstraint(prec);
    }
  }

  // Add release date.
  for (int job_id = 0; job_id < job_count; ++job_id) {
    const Job& job = data.GetJob(job_id);
    IntervalVar* const t = jobs_to_tasks[job_id][0];
    Constraint* const prec =
        solver.MakeIntervalVarRelation(t,
                                       Solver::STARTS_AFTER,
                                       job.release_date);
    solver.AddConstraint(prec);
  }

  std::vector<IntVar*> penalties;
  for (int job_id = 0; job_id < job_count; ++job_id) {
    const Job& job = data.GetJob(job_id);
    IntervalVar* const t = jobs_to_tasks[job_id][machine_count - 1];
    IntVar* const penalty =
        solver.MakeConvexPiecewiseExpr(t->EndExpr(),
                                       job.early_cost,
                                       job.due_date,
                                       job.due_date,
                                       job.tardy_cost)->Var();
    penalties.push_back(penalty);
  }

  // Adds disjunctive constraints on unary resources.
  for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
    solver.AddConstraint(
        solver.MakeDisjunctiveConstraint(machines_to_tasks[machine_id]));
  }

  // Creates sequences variables on machines. A sequence variable is a
  // dedicated variable whose job is to sequence interval variables.
  std::vector<SequenceVar*> all_sequences;
  for (int machine_id = 0; machine_id < machine_count; ++machine_id) {
    const string name = StringPrintf("Machine_%d", machine_id);
    SequenceVar* const sequence =
        solver.MakeSequenceVar(machines_to_tasks[machine_id], name);
    all_sequences.push_back(sequence);
  }

  // Objective: minimize the weighted penalties.
  IntVar* const objective_var = solver.MakeSum(penalties)->Var();
  OptimizeVar* const objective_monitor = solver.MakeMinimize(objective_var, 1);

  // ----- Search monitors and decision builder -----

  // This decision builder will rank all tasks on all machines.
  DecisionBuilder* const sequence_phase =
      solver.MakePhase(all_sequences, Solver::SEQUENCE_DEFAULT);

  // After the ranking of tasks, the schedule is still loose and any
  // task can be postponed at will. But, because the problem is now a PERT
  // (http://en.wikipedia.org/wiki/Program_Evaluation_and_Review_Technique),
  // we can schedule each task at its earliest start time. This is
  // conveniently done by fixing the objective variable to its
  // minimum value.
  DecisionBuilder* const obj_phase =
      FLAGS_time_placement ?
      solver.RevAlloc(new TimePlacement(data, all_sequences, jobs_to_tasks)) :
      solver.MakePhase(objective_var,
                       Solver::CHOOSE_FIRST_UNBOUND,
                       Solver::ASSIGN_MIN_VALUE);

  // The main decision builder (ranks all tasks, then fixes the
  // objective_variable).
  DecisionBuilder* const main_phase =
      solver.Compose(sequence_phase, obj_phase);

  // Search log.
  const int kLogFrequency = 1000000;
  SearchMonitor* const search_log =
      solver.MakeSearchLog(kLogFrequency, objective_monitor);

  SearchLimit* limit = NULL;
  if (FLAGS_time_limit_in_ms > 0) {
    limit = solver.MakeTimeLimit(FLAGS_time_limit_in_ms);
  }

  // Search.
  solver.Solve(main_phase, search_log, objective_monitor, limit);
}
}  // namespace operations_research

static const char kUsage[] =
    "Usage: see flags.\nThis program runs a simple job shop optimization "
    "output besides the debug LOGs of the solver.";

int main(int argc, char **argv) {
  FLAGS_log_prefix = false;
  google::SetUsageMessage(kUsage);
  google::ParseCommandLineFlags(&argc, &argv, true);
  operations_research::EtJobShopData data;
  if (!FLAGS_jet_file.empty()) {
    data.LoadJetFile(FLAGS_jet_file);
  } else {
    data.GenerateRandomData(FLAGS_machine_count,
                            FLAGS_job_count,
                            FLAGS_max_release_date,
                            FLAGS_max_early_cost,
                            FLAGS_max_tardy_cost,
                            FLAGS_max_duration,
                            FLAGS_scale_factor,
                            FLAGS_seed);
  }
  operations_research::EtJobShop(data);
  return 0;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>

#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <signal.h>

extern "C" {
#include <lirc/lirc_client.h>
}

namespace {

const std::size_t UNIX_PATH_MAX = 108;
const std::size_t buffer_size = 4096;

// Configuration (this should be in a configuration file)
const char* server_socket_path = "/tmp/asgard_socket";
const char* client_socket_path = "/tmp/asgard_ir_socket";

//Buffers
char write_buffer[buffer_size + 1];
char receive_buffer[buffer_size + 1];

// The socket file descriptor
int socket_fd;

// The socket addresses
struct sockaddr_un client_address;
struct sockaddr_un server_address;

// The remote IDs
int source_id = -1;
int button_actuator_id = -1;

void stop(){
    std::cout << "asgard:ir: stop the driver" << std::endl;

    //Closes LIRC
    lirc_deinit();

    // Unregister the button actuator, if necessary
    if(button_actuator_id >= 0){
        auto nbytes = snprintf(write_buffer, buffer_size, "UNREG_ACTUATOR %d %d", source_id, button_actuator_id);
        sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr *) &server_address, sizeof(struct sockaddr_un));
    }

    // Unregister the source, if necessary
    if(source_id >= 0){
        auto nbytes = snprintf(write_buffer, buffer_size, "UNREG_SOURCE %d", source_id);
        sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr *) &server_address, sizeof(struct sockaddr_un));
    }

    // Unlink the client socket
    unlink(client_socket_path);

    // Close the socket
    close(socket_fd);
}

void terminate(int){
    stop();

    std::exit(0);
}

void ir_received(char* raw_code){
    std::string full_code(raw_code);

    auto code_end = full_code.find(' ');
    std::string code(full_code.begin(), full_code.begin() + code_end);

    auto repeat_end = full_code.find(' ', code_end + 1);
    std::string repeat(full_code.begin() + code_end + 1, full_code.begin() + repeat_end);

    auto key_end = full_code.find(' ', repeat_end + 1);
    std::string key(full_code.begin() + repeat_end + 1, full_code.begin() + key_end);

    std::cout << "asgard:ir: Received: " << code << ":" << repeat << ":" << key << std::endl;

    //Send the event to the server
    auto nbytes = snprintf(write_buffer, buffer_size, "EVENT %d %d %s", source_id, button_actuator_id, key.c_str());
    sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr *) &server_address, sizeof(struct sockaddr_un));
}

} //End of anonymous namespace

int main(){
    //Initiate LIRC. Exit on failure
    char lirc_name[] = "lirc";
    if(lirc_init(lirc_name, 1) == -1){
        std::cout << "asgard:ir: Failed to init LIRC" << std::endl;
        return 1;
    }

    // Open the socket
    socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if(socket_fd < 0){
        std::cerr << "asgard:ir: socket() failed" << std::endl;
        return 1;
    }

    // Init the client address
    memset(&client_address, 0, sizeof(struct sockaddr_un));
    client_address.sun_family = AF_UNIX;
    snprintf(client_address.sun_path, UNIX_PATH_MAX, client_socket_path);

    // Unlink the client socket
    unlink(client_socket_path);

    // Bind to client socket
    if(bind(socket_fd, (const struct sockaddr *) &client_address, sizeof(struct sockaddr_un)) < 0){
        std::cerr << "asgard:ir: bind() failed" << std::endl;
        return 1;
    }

    //Register signals for "proper" shutdown
    signal(SIGTERM, terminate);
    signal(SIGINT, terminate);

    // Init the server address
    memset(&server_address, 0, sizeof(struct sockaddr_un));
    server_address.sun_family = AF_UNIX;
    snprintf(server_address.sun_path, UNIX_PATH_MAX, server_socket_path);

    socklen_t address_length = sizeof(struct sockaddr_un);

    // Register the source
    auto nbytes = snprintf(write_buffer, buffer_size, "REG_SOURCE ir");
    sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr *) &server_address, sizeof(struct sockaddr_un));

    auto bytes_received = recvfrom(socket_fd, receive_buffer, buffer_size, 0, (struct sockaddr *) &(server_address), &address_length);
    receive_buffer[bytes_received] = '\0';

    source_id = atoi(receive_buffer);

    std::cout << "asgard:ir: remote source: " << source_id << std::endl;

    // Register the button actuator
    nbytes = snprintf(write_buffer, buffer_size, "REG_ACTUATOR %d %s", source_id, "ir_button_1");
    sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr *) &server_address, sizeof(struct sockaddr_un));

    bytes_received = recvfrom(socket_fd, receive_buffer, buffer_size, 0, (struct sockaddr *) &(server_address), &address_length);
    receive_buffer[bytes_received] = '\0';

    button_actuator_id = atoi(receive_buffer);

    std::cout << "asgard:ir: remote button actuator: " << button_actuator_id << std::endl;

    //Read the default LIRC config
    struct lirc_config* config;
    if(lirc_readconfig(NULL,&config,NULL)==0){
        char* code;

        //Do stuff while LIRC socket is open  0=open  -1=closed.
        while(lirc_nextcode(&code)==0){
            //If code = NULL, nothing was returned from LIRC socket
            if(code){
                //Send code further
                ir_received(code);

                //Need to free up code before the next loop
                free(code);
            }
        }

        //Frees the data structures associated with config.
        lirc_freeconfig(config);
    } else {
        std::cout << "asgard:ir: Failed to read LIRC config" << std::endl;
    }

    stop();

    return 0;
}
<commit_msg>Update copyright<commit_after>//=======================================================================
// Copyright (c) 2015-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>

#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <signal.h>

extern "C" {
#include <lirc/lirc_client.h>
}

namespace {

const std::size_t UNIX_PATH_MAX = 108;
const std::size_t buffer_size = 4096;

// Configuration (this should be in a configuration file)
const char* server_socket_path = "/tmp/asgard_socket";
const char* client_socket_path = "/tmp/asgard_ir_socket";

//Buffers
char write_buffer[buffer_size + 1];
char receive_buffer[buffer_size + 1];

// The socket file descriptor
int socket_fd;

// The socket addresses
struct sockaddr_un client_address;
struct sockaddr_un server_address;

// The remote IDs
int source_id = -1;
int button_actuator_id = -1;

void stop(){
    std::cout << "asgard:ir: stop the driver" << std::endl;

    //Closes LIRC
    lirc_deinit();

    // Unregister the button actuator, if necessary
    if(button_actuator_id >= 0){
        auto nbytes = snprintf(write_buffer, buffer_size, "UNREG_ACTUATOR %d %d", source_id, button_actuator_id);
        sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr *) &server_address, sizeof(struct sockaddr_un));
    }

    // Unregister the source, if necessary
    if(source_id >= 0){
        auto nbytes = snprintf(write_buffer, buffer_size, "UNREG_SOURCE %d", source_id);
        sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr *) &server_address, sizeof(struct sockaddr_un));
    }

    // Unlink the client socket
    unlink(client_socket_path);

    // Close the socket
    close(socket_fd);
}

void terminate(int){
    stop();

    std::exit(0);
}

void ir_received(char* raw_code){
    std::string full_code(raw_code);

    auto code_end = full_code.find(' ');
    std::string code(full_code.begin(), full_code.begin() + code_end);

    auto repeat_end = full_code.find(' ', code_end + 1);
    std::string repeat(full_code.begin() + code_end + 1, full_code.begin() + repeat_end);

    auto key_end = full_code.find(' ', repeat_end + 1);
    std::string key(full_code.begin() + repeat_end + 1, full_code.begin() + key_end);

    std::cout << "asgard:ir: Received: " << code << ":" << repeat << ":" << key << std::endl;

    //Send the event to the server
    auto nbytes = snprintf(write_buffer, buffer_size, "EVENT %d %d %s", source_id, button_actuator_id, key.c_str());
    sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr *) &server_address, sizeof(struct sockaddr_un));
}

} //End of anonymous namespace

int main(){
    //Initiate LIRC. Exit on failure
    char lirc_name[] = "lirc";
    if(lirc_init(lirc_name, 1) == -1){
        std::cout << "asgard:ir: Failed to init LIRC" << std::endl;
        return 1;
    }

    // Open the socket
    socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if(socket_fd < 0){
        std::cerr << "asgard:ir: socket() failed" << std::endl;
        return 1;
    }

    // Init the client address
    memset(&client_address, 0, sizeof(struct sockaddr_un));
    client_address.sun_family = AF_UNIX;
    snprintf(client_address.sun_path, UNIX_PATH_MAX, client_socket_path);

    // Unlink the client socket
    unlink(client_socket_path);

    // Bind to client socket
    if(bind(socket_fd, (const struct sockaddr *) &client_address, sizeof(struct sockaddr_un)) < 0){
        std::cerr << "asgard:ir: bind() failed" << std::endl;
        return 1;
    }

    //Register signals for "proper" shutdown
    signal(SIGTERM, terminate);
    signal(SIGINT, terminate);

    // Init the server address
    memset(&server_address, 0, sizeof(struct sockaddr_un));
    server_address.sun_family = AF_UNIX;
    snprintf(server_address.sun_path, UNIX_PATH_MAX, server_socket_path);

    socklen_t address_length = sizeof(struct sockaddr_un);

    // Register the source
    auto nbytes = snprintf(write_buffer, buffer_size, "REG_SOURCE ir");
    sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr *) &server_address, sizeof(struct sockaddr_un));

    auto bytes_received = recvfrom(socket_fd, receive_buffer, buffer_size, 0, (struct sockaddr *) &(server_address), &address_length);
    receive_buffer[bytes_received] = '\0';

    source_id = atoi(receive_buffer);

    std::cout << "asgard:ir: remote source: " << source_id << std::endl;

    // Register the button actuator
    nbytes = snprintf(write_buffer, buffer_size, "REG_ACTUATOR %d %s", source_id, "ir_button_1");
    sendto(socket_fd, write_buffer, nbytes, 0, (struct sockaddr *) &server_address, sizeof(struct sockaddr_un));

    bytes_received = recvfrom(socket_fd, receive_buffer, buffer_size, 0, (struct sockaddr *) &(server_address), &address_length);
    receive_buffer[bytes_received] = '\0';

    button_actuator_id = atoi(receive_buffer);

    std::cout << "asgard:ir: remote button actuator: " << button_actuator_id << std::endl;

    //Read the default LIRC config
    struct lirc_config* config;
    if(lirc_readconfig(NULL,&config,NULL)==0){
        char* code;

        //Do stuff while LIRC socket is open  0=open  -1=closed.
        while(lirc_nextcode(&code)==0){
            //If code = NULL, nothing was returned from LIRC socket
            if(code){
                //Send code further
                ir_received(code);

                //Need to free up code before the next loop
                free(code);
            }
        }

        //Frees the data structures associated with config.
        lirc_freeconfig(config);
    } else {
        std::cout << "asgard:ir: Failed to read LIRC config" << std::endl;
    }

    stop();

    return 0;
}
<|endoftext|>


<commit_before>#define DEBUG 1
/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 6/14/2020, 3:53:32 AM
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
// ----- for C++17 -----
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- Solve -----

class Solve
{
  ll W, H, K;

public:
  Solve(ll W, ll H, ll K) : W{W}, H{H}, K{K} {}

  ll answer()
  {
    ll ans{0};
    for (auto s{0LL}; s < W - 1; ++s)
    {
      for (auto y{0LL}; y < H - 1; ++y)
      {
        ll tmp{calc(s, y)};
        if (s == 0)
        {
          ans += tmp;
        }
        else
        {
          ans += 2 * tmp;
        }
      }
    }
    return ans;
  }

private:
  ll rhs(ll s, ll y)
  {
    return 2 * K - s * (H - y) + gcd(s, H) - 2;
  }

  ll rhs_bound(ll s, ll y)
  {
    return 2 * K - s * (H - y) + H - 2;
  }

  ll lhs(ll x, ll s, ll y)
  {
    return H * x - gcd(H - y, x) - gcd(y, x + s);
  }

  ll calc(ll s, ll y)
  {
    ll R{rhs(s, y)};
    if (R < 0)
    {
      return 0;
    }
    ll ans{min(W - s - 1, R / H)};
    ll x{R / H + 1};
    if (x + s < W && lhs(x, s, y) <= R)
    {
      ++ans;
    }
    return ans;
  }
};

// ----- main() -----

int main()
{
  ll W, H, K;
  cin >> W >> H >> K;
  Solve solve(W, H, K), solve2(H, W, K);
  ll ans{2 * solve.answer() + 2 * solve2.answer()};
  cout << ans << endl;
}
<commit_msg>tried F.cpp to 'F'<commit_after>#define DEBUG 1
/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 6/14/2020, 3:53:32 AM
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
// ----- for C++17 -----
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- Solve -----

class Solve
{
  ll W, H, K;

public:
  Solve(ll W, ll H, ll K) : W{W}, H{H}, K{K} {}

  ll answer()
  {
    ll ans{0};
    for (auto s{0LL}; s < W - 1; ++s)
    {
      for (auto y{0LL}; rhs_bound(s, y) >= 0 && y < H - 1; ++y)
      {
        ll tmp{calc(s, y)};
        if (s == 0)
        {
          ans += tmp;
        }
        else
        {
          ans += 2 * tmp;
        }
      }
    }
    return ans;
  }

private:
  ll rhs(ll s, ll y)
  {
    return 2 * K - s * (H - y) + gcd(s, H) - 2;
  }

  ll rhs_bound(ll s, ll y)
  {
    return 2 * K - s * (H - y) + H - 2;
  }

  ll lhs(ll x, ll s, ll y)
  {
    return H * x - gcd(H - y, x) - gcd(y, x + s);
  }

  ll calc(ll s, ll y)
  {
    ll R{rhs(s, y)};
    if (R < 0)
    {
      return 0;
    }
    ll ans{min(W - s - 1, R / H)};
    ll x{R / H + 1};
    if (x + s < W && lhs(x, s, y) <= R)
    {
      ++ans;
    }
    return ans;
  }
};

// ----- main() -----

int main()
{
  ll W, H, K;
  cin >> W >> H >> K;
  Solve solve(W, H, K), solve2(H, W, K);
  ll ans{2 * solve.answer() + 2 * solve2.answer()};
  cout << ans << endl;
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "image.h"
#include "benchmark.h"

#include <random>
#include <iostream>

using namespace nda;

template <typename Input, typename Filter, typename Output>
void conv2d(const Input& input, const Filter& filter, const Output& output) {
  for (index_t y : output.y()) {
    for (index_t x : output.x()) {
      for (index_t c : output.c()) {
        output(x, y, c) = 0;
      }
      for (index_t dy : filter.y()) {
        for (index_t dx : filter.x()) {
          for (index_t c : output.c()) {
            output(x, y, c) += input(x + dx, y + dy, c) * filter(dx, dy, c);
          }
        }
      }
    }
  }
}

// TODO: This is slow, fix it. The C version below is fast :(
template <typename Input, typename Filter, typename Output>
void conv2d_tiled(const Input& input, const Filter& filter, const Output& output) {
  using T = typename Output::value_type;

  // Adjust this depending on the target architecture. For AVX2,
  // vectors are 256-bit.
  constexpr index_t vector_size = 32 / sizeof(T);

  // The strategy used here is:
  // - vectorize the channel dimension (assume it has stride 1)
  // - tile x and y to get some re-use of the stencil, and to
  //   get ILP for the accumulators.
  constexpr index_t unroll_x = 2;
  constexpr index_t unroll_y = 4;

  for (auto yo : split<unroll_y>(output.y())) {
    for (auto xo : split<unroll_x>(output.x())) {
      for (auto co : split<vector_size>(output.c())) {
        auto output_tile = output(xo, yo, co);
        T buffer[unroll_x * unroll_y * vector_size] = { static_cast<T>(0) };
        auto accumulator = make_array_ref(buffer, make_compact(output_tile.shape()));
        for (index_t dy : filter.y()) {
          for (index_t dx : filter.x()) {
            for (index_t y : accumulator.y()) {
              for (index_t x : accumulator.x()) {
                for (index_t c : accumulator.c()) {
                  accumulator(x, y, c) += input(x + dx, y + dy, c) * filter(dx, dy, c);
                }
              }
            }
          }
        }
        for (index_t y : output_tile.y()) {
          for (index_t x : output_tile.x()) {
            for (index_t c : output_tile.c()) {
              output_tile(x, y, c) = accumulator(x, y, c);
            }
          }
        }
      }
    }
  }
}

// This generates the following inner loop:
// LBB12_6:
//   vmovups -256(%r8,%r14), %ymm9
//   vfmadd231ps     -384(%rdi,%r15), %ymm9, %ymm1
//   vmovups -256(%rdi,%r15), %ymm10
//   vfmadd231ps     %ymm10, %ymm9, %ymm2
//   vfmadd231ps     -384(%r12,%r15), %ymm9, %ymm3
//   vmovups -256(%r12,%r15), %ymm11
//   vfmadd231ps     -384(%r10,%r15), %ymm9, %ymm5
//   vfmadd231ps     %ymm11, %ymm9, %ymm4
//   vmovups -256(%r10,%r15), %ymm12
//   vfmadd231ps     %ymm12, %ymm9, %ymm6
//   vfmadd231ps     -384(%r13,%r15), %ymm9, %ymm7
//   vmovups -256(%r13,%r15), %ymm13
//   vfmadd213ps     %ymm8, %ymm13, %ymm9
//   vmovups -128(%r8,%r14), %ymm8
//   vfmadd231ps     %ymm10, %ymm8, %ymm1
//   vmovups -128(%rdi,%r15), %ymm10
//   vfmadd231ps     %ymm11, %ymm8, %ymm3
//   vmovups -128(%r12,%r15), %ymm11
//   vfmadd231ps     %ymm12, %ymm8, %ymm5
//   vmovups -128(%r10,%r15), %ymm12
//   vfmadd231ps     %ymm13, %ymm8, %ymm7
//   vmovups -128(%r13,%r15), %ymm13
//   vfmadd231ps     %ymm10, %ymm8, %ymm2
//   vfmadd231ps     %ymm11, %ymm8, %ymm4
//   vfmadd231ps     %ymm12, %ymm8, %ymm6
//   vfmadd213ps     %ymm9, %ymm13, %ymm8
//   vmovups (%r8,%r14), %ymm9
//   vfmadd231ps     %ymm10, %ymm9, %ymm1
//   vfmadd231ps     %ymm11, %ymm9, %ymm3
//   vfmadd231ps     %ymm12, %ymm9, %ymm5
//   vfmadd231ps     (%rdi,%r15), %ymm9, %ymm2
//   vfmadd231ps     (%r12,%r15), %ymm9, %ymm4
//   vfmadd231ps     (%r10,%r15), %ymm9, %ymm6
//   vfmadd231ps     %ymm13, %ymm9, %ymm7
//   vfmadd231ps     (%r13,%r15), %ymm9, %ymm8
//   addq    $384, %r14
//   addq    %rsi, %r15
//   cmpq    $1408, %r14
//   jne     LBB12_6

template <index_t Channels, index_t DX, index_t DY>
void conv2d_tiled_c(
    const float* input, const float* filter, float* output,
    index_t width, index_t height, index_t input_stride, index_t output_stride) {
  // Adjust this depending on the target architecture. For AVX2,
  // vectors are 256-bit.
  constexpr index_t vector_size = 32 / sizeof(float);

  // The strategy used here is:
  // - vectorize the channel dimension (assume it has stride 1)
  // - tile x and y to get some re-use of the stencil, and to
  //   get ILP for the accumulators.
  constexpr index_t unroll_x = 2;
  constexpr index_t unroll_y = 4;

  for (index_t yo = 0; yo < height; yo += unroll_y) {
    for (index_t xo = 0; xo < width; xo += unroll_x) {
      for (index_t co = 0; co < Channels; co += vector_size) {
        float buffer[unroll_x * unroll_y * vector_size] = { 0.0f };
        for (index_t dy = 0; dy < DY; dy++) {
          for (index_t dx = 0; dx < DX; dx++) {
            #pragma unroll
            for (index_t yi = 0; yi < unroll_y; yi++) {
              #pragma unroll
              for (index_t xi = 0; xi < unroll_x; xi++) {
                for (index_t ci = 0; ci < vector_size; ci++) {
                  index_t x = xo + xi;
                  index_t y = yo + yi;
                  index_t c = co + ci;
                  buffer[xi * vector_size + yi * vector_size * unroll_x + ci] +=
                      input[(x + dx) * Channels + (y + dy) * input_stride + c] * filter[dy * DX * Channels + dx * Channels + c];
                }
              }
            }
          }
        }
        for (index_t yi = 0; yi < unroll_y; yi++) {
          for (index_t xi = 0; xi < unroll_x; xi++) {
            for (index_t ci = 0; ci < vector_size; ci++) {
              index_t x = xo + xi;
              index_t y = yo + yi;
              index_t c = co + ci;
              output[x * Channels + y * output_stride + c] = buffer[xi * vector_size + yi * vector_size * unroll_x + ci];
            }
          }
        }
      }
    }
  }
}

int main(int, const char**) {
  constexpr int C = 32;
  constexpr int W = 100;
  constexpr int H = 80;
  constexpr int DX = 3;
  constexpr int DY = 3;

  auto input = make_array<float>(chunky_image_shape<C, nda::dynamic>(W + DX, H + DY, {}));
  auto filter = make_array<float>(shape<dim<0, DX, C>, dim<0, DY, C*DX>, dense_dim<0, C>>());

  // 'for_each_value' calls the given function with a reference to
  // each value in the array. Use this to randomly initialize the
  // matrices with random values.
  std::mt19937_64 rng;
  std::uniform_real_distribution<float> uniform(0, 1);
  generate(input, [&]() { return uniform(rng); });
  generate(filter, [&]() { return uniform(rng); });

  auto naive_output = make_array<float>(chunky_image_shape<C, nda::dynamic>(W, H, {}));
  double naive_time = benchmark([&]() {
    conv2d(input.cref(), filter.cref(), naive_output.ref());
  });
  std::cout << "naive time: " << naive_time * 1e3 << " ms" << std::endl;

  auto tiled_output = make_array<float>(chunky_image_shape<C, nda::dynamic>(W, H, {}));
  double tiled_time = benchmark([&]() {
    conv2d_tiled(input.cref(), filter.cref(), tiled_output.ref());
  });
  std::cout << "tiled time: " << tiled_time * 1e3 << " ms" << std::endl;

  auto tiled_output_c = make_array<float>(chunky_image_shape<C, nda::dynamic>(W, H, {}));
  double tiled_time_c = benchmark([&]() {
    conv2d_tiled_c<C, DX, DY>(
        input.data(), filter.data(), tiled_output_c.data(),
        tiled_output_c.width(), tiled_output_c.height(),
        input.y().stride(), tiled_output_c.y().stride());
  });
  std::cout << "tiled time (C): " << tiled_time_c * 1e3 << " ms" << std::endl;

  const float epsilon = 1e-4f;
  for_each_index(naive_output.shape(), [&](const index_of_rank<3>& i) {
    if (std::abs(naive_output(i) - tiled_output(i)) > epsilon) {
      std::cout
        << "naive_output(i) = " << naive_output(i)
        << " != tiled_output(i) = " << tiled_output(i) << std::endl;
    }
    if (std::abs(naive_output(i) - tiled_output_c(i)) > epsilon) {
      std::cout
        << "naive_output(i) = " << naive_output(i)
        << " != tiled_output_c(i) = " << tiled_output_c(i) << std::endl;
    }
  });

  return 0;
}

<commit_msg>The naive one wasn't actually fully naive.<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "image.h"
#include "benchmark.h"

#include <random>
#include <iostream>

using namespace nda;

template <typename Input, typename Filter, typename Output>
void conv2d(const Input& input, const Filter& filter, const Output& output) {
  for (index_t y : output.y()) {
    for (index_t x : output.x()) {
      for (index_t c : output.c()) {
        output(x, y, c) = 0;
        for (index_t dy : filter.y()) {
          for (index_t dx : filter.x()) {
            output(x, y, c) += input(x + dx, y + dy, c) * filter(dx, dy, c);
          }
        }
      }
    }
  }
}

// TODO: This is slow, fix it. The C version below is fast :(
template <typename Input, typename Filter, typename Output>
void conv2d_tiled(const Input& input, const Filter& filter, const Output& output) {
  using T = typename Output::value_type;

  // Adjust this depending on the target architecture. For AVX2,
  // vectors are 256-bit.
  constexpr index_t vector_size = 32 / sizeof(T);

  // The strategy used here is:
  // - vectorize the channel dimension (assume it has stride 1)
  // - tile x and y to get some re-use of the stencil, and to
  //   get ILP for the accumulators.
  constexpr index_t unroll_x = 2;
  constexpr index_t unroll_y = 4;

  for (auto yo : split<unroll_y>(output.y())) {
    for (auto xo : split<unroll_x>(output.x())) {
      for (auto co : split<vector_size>(output.c())) {
        auto output_tile = output(xo, yo, co);
        T buffer[unroll_x * unroll_y * vector_size] = { static_cast<T>(0) };
        auto accumulator = make_array_ref(buffer, make_compact(output_tile.shape()));
        for (index_t dy : filter.y()) {
          for (index_t dx : filter.x()) {
            #pragma unroll
            for (index_t y : accumulator.y()) {
              #pragma unroll
              for (index_t x : accumulator.x()) {
                for (index_t c : accumulator.c()) {
                  accumulator(x, y, c) += input(x + dx, y + dy, c) * filter(dx, dy, c);
                }
              }
            }
          }
        }
        for (index_t y : output_tile.y()) {
          for (index_t x : output_tile.x()) {
            for (index_t c : output_tile.c()) {
              output_tile(x, y, c) = accumulator(x, y, c);
            }
          }
        }
      }
    }
  }
}

// This generates the following inner loop:
// LBB12_6:
//   vmovups -256(%r8,%r14), %ymm9
//   vfmadd231ps     -384(%rdi,%r15), %ymm9, %ymm1
//   vmovups -256(%rdi,%r15), %ymm10
//   vfmadd231ps     %ymm10, %ymm9, %ymm2
//   vfmadd231ps     -384(%r12,%r15), %ymm9, %ymm3
//   vmovups -256(%r12,%r15), %ymm11
//   vfmadd231ps     -384(%r10,%r15), %ymm9, %ymm5
//   vfmadd231ps     %ymm11, %ymm9, %ymm4
//   vmovups -256(%r10,%r15), %ymm12
//   vfmadd231ps     %ymm12, %ymm9, %ymm6
//   vfmadd231ps     -384(%r13,%r15), %ymm9, %ymm7
//   vmovups -256(%r13,%r15), %ymm13
//   vfmadd213ps     %ymm8, %ymm13, %ymm9
//   vmovups -128(%r8,%r14), %ymm8
//   vfmadd231ps     %ymm10, %ymm8, %ymm1
//   vmovups -128(%rdi,%r15), %ymm10
//   vfmadd231ps     %ymm11, %ymm8, %ymm3
//   vmovups -128(%r12,%r15), %ymm11
//   vfmadd231ps     %ymm12, %ymm8, %ymm5
//   vmovups -128(%r10,%r15), %ymm12
//   vfmadd231ps     %ymm13, %ymm8, %ymm7
//   vmovups -128(%r13,%r15), %ymm13
//   vfmadd231ps     %ymm10, %ymm8, %ymm2
//   vfmadd231ps     %ymm11, %ymm8, %ymm4
//   vfmadd231ps     %ymm12, %ymm8, %ymm6
//   vfmadd213ps     %ymm9, %ymm13, %ymm8
//   vmovups (%r8,%r14), %ymm9
//   vfmadd231ps     %ymm10, %ymm9, %ymm1
//   vfmadd231ps     %ymm11, %ymm9, %ymm3
//   vfmadd231ps     %ymm12, %ymm9, %ymm5
//   vfmadd231ps     (%rdi,%r15), %ymm9, %ymm2
//   vfmadd231ps     (%r12,%r15), %ymm9, %ymm4
//   vfmadd231ps     (%r10,%r15), %ymm9, %ymm6
//   vfmadd231ps     %ymm13, %ymm9, %ymm7
//   vfmadd231ps     (%r13,%r15), %ymm9, %ymm8
//   addq    $384, %r14
//   addq    %rsi, %r15
//   cmpq    $1408, %r14
//   jne     LBB12_6

template <index_t Channels, index_t DX, index_t DY>
void conv2d_tiled_c(
    const float* input, const float* filter, float* output,
    index_t width, index_t height, index_t input_stride, index_t output_stride) {
  // Adjust this depending on the target architecture. For AVX2,
  // vectors are 256-bit.
  constexpr index_t vector_size = 32 / sizeof(float);

  // The strategy used here is:
  // - vectorize the channel dimension (assume it has stride 1)
  // - tile x and y to get some re-use of the stencil, and to
  //   get ILP for the accumulators.
  constexpr index_t unroll_x = 2;
  constexpr index_t unroll_y = 4;

  for (index_t yo = 0; yo < height; yo += unroll_y) {
    for (index_t xo = 0; xo < width; xo += unroll_x) {
      for (index_t co = 0; co < Channels; co += vector_size) {
        float buffer[unroll_x * unroll_y * vector_size] = { 0.0f };
        for (index_t dy = 0; dy < DY; dy++) {
          for (index_t dx = 0; dx < DX; dx++) {
            #pragma unroll
            for (index_t yi = 0; yi < unroll_y; yi++) {
              #pragma unroll
              for (index_t xi = 0; xi < unroll_x; xi++) {
                for (index_t ci = 0; ci < vector_size; ci++) {
                  index_t x = xo + xi;
                  index_t y = yo + yi;
                  index_t c = co + ci;
                  buffer[xi * vector_size + yi * vector_size * unroll_x + ci] +=
                      input[(x + dx) * Channels + (y + dy) * input_stride + c] * filter[dy * DX * Channels + dx * Channels + c];
                }
              }
            }
          }
        }
        for (index_t yi = 0; yi < unroll_y; yi++) {
          for (index_t xi = 0; xi < unroll_x; xi++) {
            for (index_t ci = 0; ci < vector_size; ci++) {
              index_t x = xo + xi;
              index_t y = yo + yi;
              index_t c = co + ci;
              output[x * Channels + y * output_stride + c] = buffer[xi * vector_size + yi * vector_size * unroll_x + ci];
            }
          }
        }
      }
    }
  }
}

int main(int, const char**) {
  constexpr int C = 32;
  constexpr int W = 100;
  constexpr int H = 80;
  constexpr int DX = 3;
  constexpr int DY = 3;

  auto input = make_array<float>(chunky_image_shape<C, nda::dynamic>(W + DX, H + DY, {}));
  auto filter = make_array<float>(shape<dim<0, DX, C>, dim<0, DY, C*DX>, dense_dim<0, C>>());

  // 'for_each_value' calls the given function with a reference to
  // each value in the array. Use this to randomly initialize the
  // matrices with random values.
  std::mt19937_64 rng;
  std::uniform_real_distribution<float> uniform(0, 1);
  generate(input, [&]() { return uniform(rng); });
  generate(filter, [&]() { return uniform(rng); });

  auto naive_output = make_array<float>(chunky_image_shape<C, nda::dynamic>(W, H, {}));
  double naive_time = benchmark([&]() {
    conv2d(input.cref(), filter.cref(), naive_output.ref());
  });
  std::cout << "naive time: " << naive_time * 1e3 << " ms" << std::endl;

  auto tiled_output = make_array<float>(chunky_image_shape<C, nda::dynamic>(W, H, {}));
  double tiled_time = benchmark([&]() {
    conv2d_tiled(input.cref(), filter.cref(), tiled_output.ref());
  });
  std::cout << "tiled time: " << tiled_time * 1e3 << " ms" << std::endl;

  auto tiled_output_c = make_array<float>(chunky_image_shape<C, nda::dynamic>(W, H, {}));
  double tiled_time_c = benchmark([&]() {
    conv2d_tiled_c<C, DX, DY>(
        input.data(), filter.data(), tiled_output_c.data(),
        tiled_output_c.width(), tiled_output_c.height(),
        input.y().stride(), tiled_output_c.y().stride());
  });
  std::cout << "tiled time (C): " << tiled_time_c * 1e3 << " ms" << std::endl;

  const float epsilon = 1e-4f;
  for_each_index(naive_output.shape(), [&](const index_of_rank<3>& i) {
    if (std::abs(naive_output(i) - tiled_output(i)) > epsilon) {
      std::cout
        << "naive_output(i) = " << naive_output(i)
        << " != tiled_output(i) = " << tiled_output(i) << std::endl;
    }
    if (std::abs(naive_output(i) - tiled_output_c(i)) > epsilon) {
      std::cout
        << "naive_output(i) = " << naive_output(i)
        << " != tiled_output_c(i) = " << tiled_output_c(i) << std::endl;
    }
  });

  return 0;
}

<|endoftext|>


<commit_before>#define DEBUG 1
/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 6/14/2020, 3:53:32 AM
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
// ----- for C++17 -----
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- Solve -----

class Solve
{
  ll W, H, K;

public:
  Solve(ll W, ll H, ll K) : W{W}, H{H}, K{K} {}

  ll answer()
  {
#if DEBUG == 1
    cerr << "W = " << W << ", H = " << H << endl;
#endif
    ll ans{0};
    for (auto s{0LL}; s < W - 1; ++s)
    {
      for (auto y{1LL}; (H - y) * s <= 2 * K + H - 2 && y < H; ++y)
      {
        ll tmp{calc(s, y)};
        if (s == 0)
        {
          ans += tmp;
        }
        else
        {
          ans += 2 * tmp;
        }
      }
    }
    return ans;
  }

private:
  ll calc(ll s, ll y)
  {
    ll R{2 * K - (H - y) * s + gcd(H, s) - 2};
    if (R < 0)
    {
      return 0;
    }
    ll ans{min(W - s - 1, R / H)};
    ll x{R / H + 1};
#if DEBUG == 1
    if (H < 10)
    {
      cerr << "ans = " << ans << endl;
      cerr << "x = " << x << endl;
    }
#endif
    if (x + s < W && H * x - gcd(H - y, x) + gcd(y, x + s) <= R)
    {
      ++ans;
    }
#if DEBUG == 1
    if (H < 10)
    {
      cerr << "calc(" << s << ", " << y << ") = " << ans << endl;
    }
#endif
    return ans;
  }
};

// ----- main() -----

int main()
{
  ll W, H, K;
  cin >> W >> H >> K;
  Solve solve(W, H, K), solve2(H, W, K);
  ll ans{2 * solve.answer() + 2 * solve2.answer()};
  cout << ans << endl;
}
<commit_msg>tried F.cpp to 'F'<commit_after>#define DEBUG 1
/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 6/14/2020, 3:53:32 AM
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::multiprecision::cpp_int;
using ll = long long;
using ld = long double;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1'000'000'007LL};
// constexpr ll MOD{998'244'353LL}; // be careful
constexpr ll MAX_SIZE{3'000'010LL};
// constexpr ll MAX_SIZE{30'000'010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(Mint const &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(Mint const &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(Mint const &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(Mint const &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(Mint const &a) const { return Mint(*this) += a; }
  Mint operator-(Mint const &a) const { return Mint(*this) -= a; }
  Mint operator*(Mint const &a) const { return Mint(*this) *= a; }
  Mint operator/(Mint const &a) const { return Mint(*this) /= a; }
  bool operator<(Mint const &a) const { return x < a.x; }
  bool operator<=(Mint const &a) const { return x <= a.x; }
  bool operator>(Mint const &a) const { return x > a.x; }
  bool operator>=(Mint const &a) const { return x >= a.x; }
  bool operator==(Mint const &a) const { return x == a.x; }
  bool operator!=(Mint const &a) const { return !(*this == a); }
  Mint power(ll N) const
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, Mint<MOD> const &rhs) { return rhs + lhs; }
template <ll MOD>
Mint<MOD> operator-(ll lhs, Mint<MOD> const &rhs) { return -rhs + lhs; }
template <ll MOD>
Mint<MOD> operator*(ll lhs, Mint<MOD> const &rhs) { return rhs * lhs; }
template <ll MOD>
Mint<MOD> operator/(ll lhs, Mint<MOD> const &rhs) { return Mint<MOD>{lhs} / rhs; }
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a) { return stream >> a.x; }
template <ll MOD>
ostream &operator<<(ostream &stream, Mint<MOD> const &a) { return stream << a.x; }
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i{2LL}; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i{1LL}; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
// ----- for C++17 -----
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- Infty -----
template <typename T>
constexpr T Infty() { return numeric_limits<T>::max(); }
template <typename T>
constexpr T mInfty() { return numeric_limits<T>::min(); }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1'000'000'000'000'010LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- Solve -----

class Solve
{
  ll W, H, K;

public:
  Solve(ll W, ll H, ll K) : W{W}, H{H}, K{K} {}

  ll answer()
  {
#if DEBUG == 1
    cerr << "W = " << W << ", H = " << H << endl;
#endif
    ll ans{0};
    for (auto s{0LL}; s < W - 1; ++s)
    {
      for (auto y{1LL}; (H - y) * s <= 2 * K + H - 2 && y < H; ++y)
      {
        ll tmp{calc(s, y)};
        if (s == 0)
        {
          ans += tmp;
        }
        else
        {
          ans += 2 * tmp;
        }
      }
    }
    return ans;
  }

private:
  ll calc(ll s, ll y)
  {
    ll R{2 * K - (H - y) * s + gcd(H, s) - 2};
    if (R < 0)
    {
      return 0;
    }
    ll ans{min(W - s - 1, R / H)};
    ll x{R / H + 1};
#if DEBUG == 1
    if (H < 10)
    {
      cerr << "ans = " << ans << endl;
      cerr << "x = " << x << endl;
      cerr << "R = " << R << endl;
    }
#endif
    if (x + s < W && H * x - gcd(H - y, x) + gcd(y, x + s) <= R)
    {
      ++ans;
    }
#if DEBUG == 1
    if (H < 10)
    {
      cerr << "calc(" << s << ", " << y << ") = " << ans << endl;
    }
#endif
    return ans;
  }
};

// ----- main() -----

int main()
{
  ll W, H, K;
  cin >> W >> H >> K;
  Solve solve(W, H, K), solve2(H, W, K);
  ll ans{2 * solve.answer() + 2 * solve2.answer()};
  cout << ans << endl;
}
<|endoftext|>