Home Page Downloads Contact Us

Free Open Source Artificial Intelligence C++ Parts

aiParts Open Source Project  

Home Page
Open Source
Contact
Free Downloads
Releases and Credits
Software Status
License
v0.9.3 README File
About rrproj
assigning people and/or equipment to projects
High-Hope Technique
History of the AI
View Source Files
and how they are organized
Making Programs
Development Notes
Using aiParts
Your Application
Support and Services

aiParts Source File

//**********************************************************************
//  rrproj_solv.cpp  -  function bodies for rrproj_solv.h
//
//  Copyright (c)  2008  Brian Marshall
//
//  See the license at end of this file.
//
//  Developers/Contributers:
//    [BRM] Brian Marshall - Calgary - bmarshal@agt.net
//
//  07/11/21  [BRM] began development
//
//----------------------------------------------------------------------

#include "rrproj_solv.h"

#include <string.h>
#include <iostream>
using namespace std;

//======================================================================
//  rpsProblem
//
//----------------------------------------------------------------------
//  Constructor

rpsProblem::rpsProblem () {

  aipTime tmp("Jan 1 1900");
  m_start_day = m_end_day = tmp;

}

//----------------------------------------------------------------------
//  Destructor

rpsProblem::~rpsProblem () {}

//----------------------------------------------------------------------
//  add_position

void rpsProblem::add_position (rpsPosition *x) {

  add_requirement(x);

}

//----------------------------------------------------------------------
//  add_employee

void rpsProblem::add_employee (rpsEmployee *x) {

  add_resource(x);

}

//----------------------------------------------------------------------
//  set_day_range

void rpsProblem::set_day_range (long start_yyyymmdd, 
                                long end_yyyymmdd) {

  m_start_day = aipTime(start_yyyymmdd);
  m_end_day   = aipTime(end_yyyymmdd);

}

//----------------------------------------------------------------------
//  position_iterator - return an iterator: positions in the problem

rpsPositionItr rpsProblem::position_iterator() const {

  rpsPositionItr i(requirement_pandemonium());

  return i;

}

//----------------------------------------------------------------------
//  employee_iterator  - return an iterator: employees in the problem

rpsEmployeeItr rpsProblem::employee_iterator() const {

  rpsEmployeeItr i(resource_pandemonium());

  return i;

}

//----------------------------------------------------------------------
//  decision_iterator - return an iterator: decisions in the problem

rpsDecisionItr rpsProblem::decision_iterator() const {

  rpsDecisionItr i(decision_pandemonium());

  return i;

}

//----------------------------------------------------------------------
//  take_msg 

void rpsProblem::take_msg (aipMsg *mm) {

  aiprrProblem::take_msg(mm);

}

//----------------------------------------------------------------------
//  Note that a decision has decided or failed to decide

void rpsProblem::note_decide (aipHHDecision *dd, aipHHOption *oo) {

  if (!dd) return;

  aiprrProblem::note_decide (dd, oo);

  rpsDecision *d = (rpsDecision*)dd;
  rpsOption   *o = (rpsOption*)oo;

  if (should_log_options()) log_decide (d, o);

  if (o) apply_emp_aspects (d, o);

}

//----------------------------------------------------------------------
//  A decision has just chosen an option - apply some aspects to
//  some other unchosen options (by changing their dynamic goodness).
//  The aspects, here, are related to the employee of the chosen option.

void rpsProblem::apply_emp_aspects (rpsDecision *d1, rpsOption *o1) {

        // regarding the emp, dcsn and chosen opt
  rpsPosDay   * pd1   = d1->posday();
  rpsPosition * p1    = pd1->pos();
  rpsEmpDay   * ed1   = o1->empday();
  rpsEmployee * e1    = ed1->emp();

        // regarding other dcsns and opts for this emp
  rpsDecision * d2;
  rpsOption   * o2;
  rpsPosDay   * pd2;
  rpsEmpDay   * ed2;

        // good for an emp to work if has not worked for a while
           // but now emp has worked
  if ( e1->g_last_work() > aipNeutral) e1->reset_g_last_work();

  rpsEmpDayItr editr = e1->empday_iterator();              // emp
  for ( ed2 = editr.first(); ed2; ed2 = editr.next() ) {   // empday
    if (e1->g_last_work() == aipNeutral) {
      long day_diff = ed2->day().days_since(pd1->day());
      if ( day_diff < -1 || day_diff > 2 ) continue;
    }
    rpsOptItr oitr = ed2->opt_iterator();
    for ( o2 = oitr.first(); o2; o2 = oitr.next() ) {      // opt
      if ( o2->is_chosen() ) continue;
      if ( o2->g_opt().is_forbidden() ) continue;
      d2 = (rpsDecision*)(o2->owner());                    // dcsn
      if ( d2->is_decided() ) continue;
      pd2 = d2->posday();                                  // posday

        // emp cannot work overlapping posdays
      if ( pd2->end_time()   > pd1->start_time() &&
           pd2->start_time() < pd1->end_time() )  {
        o2->set_g_dynamic(aipForbidden);
        continue;
      }

        // good for an emp to work same pos as previous day
      if ( pd2->pos()->pos_id() ==  p1->pos_id() &&
           pd2->proj_id()       == pd1->proj_id() &&
           pd2->day().days_since(pd1->day()) == 1 ) {
        o2->add_g_dynamic(aipGood);
      }

    }  // end of loop through options in ed2
  }   // end of loop through empdays ed2 for the emp e1

}

//----------------------------------------------------------------------
//  Write about a decision being decided if enable_log_options
//  has been called

void rpsProblem::log_decide (rpsDecision *d, rpsOption *o) {

  cout << "log: Decision for: "
       << " proj " << d->posday()->proj_id()
       << " pos "  << d->posday()->pos_id()
       << " on "   << d->posday()->yyyymmdd();

  if (o) {
    cout << " emp: " << o->emp()->emp_id()
         << "  g: " << o->g_opt_cmp().numeric_value();
  } else {
    cout << "  Failed";
  }

  cout << "\n";

}

//----------------------------------------------------------------------
//  Write about the try to cout if enable_log_tries() has been called

void rpsProblem::log_this_try () {

  aipHHSolveStat * ss = solve_stat();

  long g_val     = ss->g_usr_cur().numeric_value();
  long g_val_bsf = ss->g_usr_bsf().numeric_value();

  cout << "\n  +++ A Try has ended  -  Goodness: " << g_val 
       << "   (Best-so-far: " << g_val_bsf << ")\n"
       << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";

}

//======================================================================
//  rpsDecision
//
//----------------------------------------------------------------------
//  constructor

rpsDecision::rpsDecision (rpsPosDay *a_posday, long a_num_to_decide) 
                            : aiprrDecision(a_posday,a_num_to_decide) {}

//----------------------------------------------------------------------
//  destructor

rpsDecision::~rpsDecision() {}

//----------------------------------------------------------------------
//  add_rps_option

void rpsDecision::add_rps_option (rpsOption *x) { 

  add_aiprr_option(x); 

}

//----------------------------------------------------------------------
//  take_msg  - take and react to a message

void rpsDecision::take_msg (aipMsg *mm) {

  aiprrDecision::take_msg(mm);

//  rpsMsg *m = (rpsMsg *)mm;

//  if (m->typ() == HH_Starting_New_Try) {
//  }

}

//======================================================================
//  rpsOption  -  an employee working a position on a day
//
//----------------------------------------------------------------------
//  constructor

rpsOption::rpsOption(rpsEmpDay *a_empday, aipG g_constant)
                             : aiprrOption(a_empday, g_constant) {}

//----------------------------------------------------------------------
//  destructor

rpsOption::~rpsOption () {}

//----------------------------------------------------------------------
//  return emp, pos, day

rpsEmployee * rpsOption::emp () const { return empday()->emp(); }

rpsPosition * rpsOption::pos () const { return posday()->pos(); }

aipTime       rpsOption::day () const { return empday()->day(); }

//----------------------------------------------------------------------
//  take_msg  - take and react to a message

void rpsOption::take_msg (aipMsg *mm) {

  aiprrOption::take_msg(mm);

//  rpsMsg *m = (rpsMsg *)mm;

//  if (m->typ() == HH_Starting_New_Try) {

//  }

}

//----------------------------------------------------------------------
//  g_opt  -  for making decisions

aipG rpsOption::g_opt() {

  return ( aiprrOption::g_opt() + emp()->g_last_work() );

}

//----------------------------------------------------------------------
//  g_opt_cmp  -  for comparing solutions

aipG rpsOption::g_opt_cmp() {

  return ( aiprrOption::g_opt_cmp() + emp()->g_last_work() );

}

//----------------------------------------------------------------------
//  g_opt_usr  -  for reporting to the user

aipG rpsOption::g_opt_usr() {    // for reporting to the user

  return ( aiprrOption::g_opt_usr() + emp()->g_last_work() );

}

//======================================================================
//  rpsPosition
//
//----------------------------------------------------------------------
//  constructor

rpsPosition::rpsPosition (long a_pos_id, rpsProblem *a_prob)
                                 : aiprrRequirement(a_pos_id, a_prob) {

}

//----------------------------------------------------------------------
//  add_posday

void rpsPosition::add_posday (rpsPosDay *x) { 

  add_reqday(x); 

}

//----------------------------------------------------------------------
//  take_msg  - take and react to a message

void rpsPosition::take_msg (aipMsg *mm) {

  aiprrRequirement::take_msg(mm);

//  rpsMsg *m = (rpsMsg *)mm;

}

//----------------------------------------------------------------------
//  Note that a decision for this position has been decided

// void rpsPosition::note_rps_decide (rpsDecision *d, rpsOption *o) {}

//----------------------------------------------------------------------
//  return an iterator: position-days for the position

rpsPosDayItr  rpsPosition::posday_iterator() const {

  rpsPosDayItr i(reqday_pandemonium());

  return i;

}

//======================================================================
//  rpsPosDay
//
//----------------------------------------------------------------------
//  constructor
//
//  set_dcsn() must be called after the decision is created.

rpsPosDay::rpsPosDay(rpsPosition *a_pos, long a_yyyymmdd, 
                     long a_proj_id,
                     long a_start_hhmm, long a_end_hhmm)
                               : aiprrReqDay(a_pos, a_yyyymmdd) {

  m_proj_id = a_proj_id;

  m_start_time = aipTime(a_yyyymmdd, a_start_hhmm);
  m_end_time   = aipTime(a_yyyymmdd, a_end_hhmm);

  m_yyyymmdd = a_yyyymmdd;

                   // if posday crosses midnight...
  if (m_end_time < m_start_time) m_end_time.add_days(1);

}

//----------------------------------------------------------------------
//  Destructor

rpsPosDay::~rpsPosDay() {}

//----------------------------------------------------------------------
//  take_msg  - take and react to a message

void rpsPosDay::take_msg (aipMsg *mm) {

  aiprrReqDay::take_msg(mm);

//  rpsMsg *m = (rpsMsg *)mm;

}

//----------------------------------------------------------------------
//  Note that a decision for this position-day has been decided

// void rpsPosDay::note_rps_decide (rpsDecision *d, rpsOption *o) { }

//======================================================================
//  rpsEmployee
//
//----------------------------------------------------------------------
//  constructor

rpsEmployee::rpsEmployee(long a_id, rpsProblem *a_prob)
                                : aiprrResource(a_id, a_prob) {

  m_g_last_work = aipNeutral;
  m_start_last_work = aipTime(20010203);

}

//----------------------------------------------------------------------
//  destructor

rpsEmployee::~rpsEmployee() {}

//----------------------------------------------------------------------
//  set_start_last_work

void rpsEmployee::set_start_last_work (aipTime x) { 

  m_start_last_work = x; 

}

//----------------------------------------------------------------------
//  add_empday

void rpsEmployee::add_empday (rpsEmpDay *x) {

 add_resday(x);

}

//----------------------------------------------------------------------
//  take_msg  - take and react to a message

void rpsEmployee::take_msg (aipMsg *mm) {

  aiprrResource::take_msg(mm);

  rpsMsg *m = (rpsMsg *)mm;

  if (m->typ() == HH_Starting_New_Try) {

    aipTime limit_day(20020101);
    if (m_start_last_work < limit_day) {
      m_start_last_work = prob()->start_day();
    }

    long days_since_work = 
          prob()->start_day().days_since(m_start_last_work);
    if (days_since_work > 64) {
      m_g_last_work = aipGood;
    } else if (days_since_work > 32) {
      m_g_last_work = aipQuiteGood;
    } else if (days_since_work > 16) {
      m_g_last_work = aipPrettyGood;
    } else if (days_since_work >  8) {
      m_g_last_work = aipFairlyGood;
    } else if (days_since_work >  4) {
      m_g_last_work = aipSomewhatGood;
    } else if (days_since_work >  2) {
      m_g_last_work = aipSlightlyGood;
    }
  }

}

//----------------------------------------------------------------------
//  Note that a decision involving this employee has been decided

// void rpsEmployee::note_rps_decide (rpsDecision *d, rpsOption *o) { }

//----------------------------------------------------------------------
//  empday_iterator

rpsEmpDayItr  rpsEmployee::empday_iterator() const {

  rpsEmpDayItr i(resday_pandemonium());

  return i;

}

//======================================================================
//  rpsEmpDay
//
//----------------------------------------------------------------------
//  constructor

rpsEmpDay::rpsEmpDay(rpsEmployee *a_emp, long a_yyyymmdd,
                     long a_start_hhmm, long a_end_hhmm)
                                        : aiprrResDay(a_emp, a_yyyymmdd) {

  m_start_time = aipTime(a_yyyymmdd, a_start_hhmm);
  m_end_time   = aipTime(a_yyyymmdd, a_end_hhmm);

  m_yyyymmdd = a_yyyymmdd;

                   // if empday crosses midnight...
  if (m_end_time < m_start_time) m_end_time.add_days(1);

}

//----------------------------------------------------------------------
//  take_msg  - take and react to a message

void rpsEmpDay::take_msg (aipMsg *mm) {

  aiprrResDay::take_msg(mm);

//  rpsMsg *m = (rpsMsg *)mm;

//  if (m->typ() == HH_Starting_New_Try) {
//  }

}

//----------------------------------------------------------------------
//  Note that a decision involving this empday has been decided

// void rpsEmpDay::note_rps_decide (rpsDecision *d, rpsOption *o) { }

//----------------------------------------------------------------------
//  opt_iterator - return an iterator: options for an EmpDay

rpsOptItr rpsEmpDay::opt_iterator() const {

  rpsOptItr i(opt_pandemonium());

  return i;

}

//======================================================================
//  Iterators
//
//  All function bodies in header file.
//
//======================================================================
//                           License
//
//   Permission is hereby granted, free of charge, to any
//   person obtaining a copy of this software and associated
//   documentation files (the "Software"), to deal in the Software
//   without restriction, including without limitation the rights
//   to use, copy, modify, merge, publish, distribute, sublicense,
//   and/or sell copies of the Software, and to permit persons to
//   whom the Software is furnished to do so, subject to the
//   following conditions:
//
//   The copyright notice and this license shall be included in all
//   copies or substantial portions of the Software.
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//   NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//   OTHER DEALINGS IN THE SOFTWARE.
//
//======================================================================