aiParts |
Free Open Source Artificial Intelligence C++ Parts |
|
Home Page Open Source Contact Us Free Downloads Releases and Credits Software Status License 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
//**********************************************************************
// aipReqRes.cpp - function bodies for aipReqRes.h
//
// Copyright (c) 2008 Brian Marshall
//
// See the license at end of this file.
//
// Developers/Contributers:
// [BRM] Brian Marshall - Calgary - bmarshal@agt.net
//
// 08/01/21 [BRM] began development: split out layer from rr_solve
//
//----------------------------------------------------------------------
#include "aipReqRes.h"
#include <string.h>
#include <iostream>
using namespace std;
//======================================================================
// aiprrReqImp - importance of a requirement
//
//----------------------------------------------------------------------
// take_msg - take and react to a message
void aiprrReqImp::take_msg (aipMsg *mm) {
aipHHImportance::take_msg(mm);
aiprrMsg *m = (aiprrMsg *)mm;
if (m->typ() == HH_Starting_New_Try) {
m_left_bhnd = 0;
}
}
//----------------------------------------------------------------------
// Note that a decision for this requirement has been decided.
void aiprrReqImp::note_aiprr_decide (aiprrDecision *d, aiprrOption *o) {
// o (ptr to an option) may be null
if (d && o) {
m_left_bhnd -= 1;
}
}
//======================================================================
// aiprrProblem
//
//----------------------------------------------------------------------
// Constructor
aiprrProblem::aiprrProblem () {
m_requirements = new aipPandemonium;
m_resources = new aipPandemonium;
m_should_log_options = 0;
}
//----------------------------------------------------------------------
// Destructor
aiprrProblem::~aiprrProblem () {
if (m_requirements) delete m_requirements;
if (m_resources) delete m_resources;
}
//----------------------------------------------------------------------
// add_requirement
void aiprrProblem::add_requirement (aiprrRequirement *x) {
if (!x) return;
m_requirements->add (x);
}
//----------------------------------------------------------------------
// add_resource
void aiprrProblem::add_resource (aiprrResource *x) {
if (!x) return;
m_resources->add (x);
}
//----------------------------------------------------------------------
// add_decision
void aiprrProblem::add_decision (aiprrDecision *x) {
add_hh_decision(x);
}
//----------------------------------------------------------------------
// In a try, choose the next decision to decide.
aipHHDecision * aiprrProblem::next_decision() {
aiprrReqDay *rd;
// <<<<< can make dcsn trivial (I think) but have to call hh decide function
// rd = trivial_reqday();
//cout << "** found a trivial reqday - forced exit\n"; ?????
//exit(1);
// if (rd) return rd->dcsn();
aiprrDecision * best_dcsn = 0;
long best_dcsn_imp = -999999999;
aiprrRequirementItr itr = requirement_iterator();
for ( aiprrRequirement * req = itr.first(); req; req = itr.next() ) {
rd = req->first_unsatisfied_reqday();
if (rd) {
aiprrDecision *dcsn = rd->dcsn();
if (dcsn) {
long dcsn_imp = dcsn->imp();
if (!best_dcsn || dcsn_imp > best_dcsn_imp) {
best_dcsn = dcsn;
best_dcsn_imp = dcsn_imp;
}
}
}
}
return best_dcsn;
}
//----------------------------------------------------------------------
// requirement_iterator - return an iterator: requirements in the problem
aiprrRequirementItr aiprrProblem::requirement_iterator() const {
aiprrRequirementItr i(m_requirements);
return i;
}
//----------------------------------------------------------------------
// resource_iterator - return an iterator: resources in the problem
aiprrResourceItr aiprrProblem::resource_iterator() const {
aiprrResourceItr i(m_resources);
return i;
}
//----------------------------------------------------------------------
// decision_iterator - return an iterator: decisions in the problem
aiprrDecisionItr aiprrProblem::decision_iterator() const {
aiprrDecisionItr i(decision_pandemonium());
return i;
}
//----------------------------------------------------------------------
// too_bad_to_go_on
aipG aiprrProblem::too_bad_to_go_on() const {
// aipHHSolveStat *ss = solve_stat();
// return ss->g_cmp_bsf().calc_fraction(3,2); from samp_a_to_b
return aipForbidden; // default from aipHHProblem
}
//----------------------------------------------------------------------
// log_this_try - to cout - for debugging or watching the thing work
//
// This works best if decisions are stored in Req,Day order
void aiprrProblem::log_this_try () {
aipHHSolveStat *ss = solve_stat();
cout << "\n===== Try " << ss->i_try()+1 << "...\n";
aiprrRequirement *req_prev = 0;
aipTime day_prev = aipTime(19010101);
aiprrDecisionItr itr = decision_iterator();
for ( aiprrDecision * dcsn = itr.first(); dcsn; dcsn = itr.next() ) {
aiprrReqDay *reqday = dcsn->reqday();
aiprrRequirement *req = reqday->req();
aipTime day = reqday->day();
aiprrOption *opt = dcsn->aiprr_opt_cur();
aiprrResource *res = opt ? opt->resday()->res() : 0;
if (req != req_prev) {
cout << "\nReq: " << req->id();
req_prev = req;
}
if (day != day_prev) {
char cday[21];
day.dd_mon_yyyy(cday);
cout << " Day: " << cday;
day_prev = day;
}
if (res) cout << " " << res->id();
}
cout << "\n";
cout << "-- Goodness of this try: "
<< ss->g_usr_cur().numeric_value()
<< " ";
if (ss->try_result() == HH_Try_Has_Failed) {
if (ss->is_too_bad()) cout << "(quit)";
} else if (ss->try_result() == HH_Try_Is_New_Best) {
cout << "(New Best)";
} else if (ss->try_result() == HH_Try_Is_A_Best) {
cout << "(a best)";
} else if (ss->try_result() == HH_Try_Is_Improved) {
cout << "(improved)";
} else if (ss->try_result() == HH_Try_Is_Changed) {
cout << "(changed)";
}
cout << "\n";
if (ss->is_many_since_new_best()) {
cout << " ... many tries since new best ...\n";
}
if (ss->is_many_since_improve()) {
cout << " ... many tries since improve ...\n";
}
if (ss->is_many_since_change()) {
cout << " ... many tries since change ...\n";
}
}
//----------------------------------------------------------------------
// take_msg
void aiprrProblem::take_msg (aipMsg *mm) {
aipHHProblem::take_msg(mm); // pass message to parent class
m_requirements->take_msg(mm);
m_resources->take_msg(mm);
}
//----------------------------------------------------------------------
// Note that a decision has been decided
void aiprrProblem::note_decide (aipHHDecision *dd, aipHHOption *oo) {
if (!dd) return;
aipHHProblem::note_decide (dd, oo);
aiprrDecision *d = (aiprrDecision*)dd;
aiprrOption *o = (aiprrOption*)oo;
aiprrReqDay *reqd = d->reqday();
if (!reqd) return;
aiprrRequirement *req = reqd->req();
if (!req) return;
req->note_aiprr_decide (d, o);
reqd->note_aiprr_decide (d, o);
if (o) { // if an option was chosen
aiprrResDay *resd = o->resday();
if (!resd) return;
aiprrResource *res = resd->res();
if (!res) return;
res->note_aiprr_decide (d, o);
resd->note_aiprr_decide (d, o);
}
}
//----------------------------------------------------------------------
// Return a requirement-day that has just enough options left, so we
// can decide the decisions the remaining number of times and
// for each decide, take the first available option.
//aiprrReqDay * aiprrProblem::trivial_reqday () const {
// aiprrReqDay *rd;
// aiprrRequirementItr itr = requirement_iterator();
// for ( aiprrRequirement *req = itr.first(); req; req = itr.next() ) {
// rd = req->trivial_reqday();
// if (rd) return rd;
// }
// return 0;
//}
//----------------------------------------------------------------------
// solve_rr_problem - solve a staffwhen staff scheduling problem
//
// return 1 (true) if a schedule is found, zero otherwise
int aiprrProblem::solve_rr_problem () {
aipG g = solve(); // high-hope solve
if (g.is_forbidden()) return 0;
return 1;
}
//======================================================================
// aiprrDecision
//
//----------------------------------------------------------------------
// Constructor
aiprrDecision::aiprrDecision (aiprrReqDay *a_reqday, long num_to_decide)
: aipHHDecision(num_to_decide) {
m_reqday = a_reqday;
}
//----------------------------------------------------------------------
// Destructor
aiprrDecision::~aiprrDecision () {}
//----------------------------------------------------------------------
// add_aiprr_option
void aiprrDecision::add_aiprr_option (aiprrOption *o) {
add_hh_option(o);
if ( o && o->resday() ) o->resday()->add_opt(o);
}
//----------------------------------------------------------------------
// Return the importance of this decision
long aiprrDecision::imp () const {
if (!m_reqday) return -999999;
aiprrRequirement *req = m_reqday->req();
if (!req) return -999999;
return aipHHDecision::imp() + req->imp() + m_reqday->imp();
}
//----------------------------------------------------------------------
// take_msg - take and react to a message
void aiprrDecision::take_msg (aipMsg *mm) {
aipHHDecision::take_msg(mm); // pass message to parent class
// aiprrMsg *m = (aiprrMsg *)mm;
// if (m->typ() == HH_Starting_New_Try) {
// reset_is_trivial();
// }
}
//======================================================================
// aiprrOption - an resource working a requirement on a day
//
//----------------------------------------------------------------------
// Constructor
aiprrOption::aiprrOption(aiprrResDay *a_resday, aipG g_static)
: aipHHOption(g_static) {
m_resday = a_resday;
m_g_dynamic = aipNeutral;
}
//----------------------------------------------------------------------
// Destructor
aiprrOption::~aiprrOption() {}
//----------------------------------------------------------------------
// take_msg - take and react to a message
void aiprrOption::take_msg (aipMsg *mm) {
aipHHOption::take_msg(mm); // pass message to parent class
aiprrMsg *m = (aiprrMsg *)mm;
if (m->typ() == HH_Starting_New_Try) {
m_g_dynamic = aipNeutral;
}
}
//----------------------------------------------------------------------
// set_g_dynamic
void aiprrOption::set_g_dynamic (aipG x) { m_g_dynamic = x; }
//----------------------------------------------------------------------
// add_g_dynamic
void aiprrOption::add_g_dynamic (aipG x) { m_g_dynamic += x; }
//----------------------------------------------------------------------
// g_opt
aipG aiprrOption::g_opt() {
return aipHHOption::g_opt() + g_user_constant() + m_g_dynamic;
}
//----------------------------------------------------------------------
// g_opt_cmp
aipG aiprrOption::g_opt_cmp() { return g_user_constant() + m_g_dynamic; }
//----------------------------------------------------------------------
// g_opt_usr
aipG aiprrOption::g_opt_usr() { return g_user_constant() + m_g_dynamic; }
//======================================================================
// aiprrRequirement
//
//----------------------------------------------------------------------
// Constructor
aiprrRequirement::aiprrRequirement (long a_id, aiprrProblem *a_prob) {
m_id = a_id;
m_prob = a_prob;
m_reqdays = new aipPandemonium;
m_hope = new aipHHHope;
}
//----------------------------------------------------------------------
// Destructor
aiprrRequirement::~aiprrRequirement () {
if (m_reqdays) delete m_reqdays;
if (m_hope) delete m_hope;
}
//----------------------------------------------------------------------
// add_reqday
void aiprrRequirement::add_reqday (aiprrReqDay *x) {
if (!x) return;
m_reqdays->add (x);
}
//----------------------------------------------------------------------
// take_msg - take and react to a message
void aiprrRequirement::take_msg (aipMsg *mm) {
aiprrMsg *m = (aiprrMsg *)mm;
m->set_is_in_cur_solution(1);
m_hope->take_msg(mm);
m_importance.take_msg(mm);
m_reqdays->take_msg(mm);
}
//----------------------------------------------------------------------
// Note that a decision for this requirement has been decided
void aiprrRequirement::note_aiprr_decide (aiprrDecision *d, aiprrOption *o) {
// o (ptr to an option) may be null
m_importance.note_aiprr_decide(d, o);
}
//----------------------------------------------------------------------
// Return true if all req-days are satisfied
int aiprrRequirement::is_satisfied () const {
aiprrReqDay *rd = first_unsatisfied_reqday();
return rd ? 0 : 1;
}
//----------------------------------------------------------------------
// Return the first unsatisfied requirement-day
aiprrReqDay * aiprrRequirement::first_unsatisfied_reqday () const {
aiprrReqDayItr itr = reqday_iterator();
for ( aiprrReqDay *prd = itr.first(); prd; prd = itr.next() ) {
if ( ! prd->is_satisfied() ) return prd;
}
return 0;
}
//----------------------------------------------------------------------
// Return a requirement-day that has just enough options left, so we
// can decide the decisions the remaining number of times and
// for each decide, take the first available option.
//aiprrReqDay * aiprrRequirement::trivial_reqday () const {
// aiprrReqDayItr itr = reqday_iterator();
// for ( aiprrReqDay *rd = itr.first(); rd; rd = itr.next() ) {
// if ( !(rd->has_surplus_opts()) ) return rd;
// }
// return 0;
//}
//----------------------------------------------------------------------
// return an iterator: requirement-days for the requirement
aiprrReqDayItr aiprrRequirement::reqday_iterator() const {
aiprrReqDayItr i(m_reqdays);
return i;
}
//======================================================================
// aiprrReqDay
//
//----------------------------------------------------------------------
// Constructor
//
// set_dcsn() must be called after the decision is created
aiprrReqDay::aiprrReqDay (aiprrRequirement *a_req, long a_yyyymmdd) {
m_req = a_req;
m_day = aipTime(a_yyyymmdd);
m_dcsn = 0;
m_hope = new aipHHHope;
}
//----------------------------------------------------------------------
// Destructor
aiprrReqDay::~aiprrReqDay () {
if (m_hope) delete m_hope;
}
//----------------------------------------------------------------------
// take_msg - take and react to a message
void aiprrReqDay::take_msg (aipMsg *mm) {
aiprrMsg *m = (aiprrMsg *)mm;
m->set_is_in_cur_solution(1);
m_hope->take_msg(mm);
m_importance.take_msg(mm);
}
//----------------------------------------------------------------------
// Note that a decision for this requirement-day has been decided
void aiprrReqDay::note_aiprr_decide (aiprrDecision *d, aiprrOption *o) {
// o (ptr to an option) may be null
if (!d) {
if (o) {
log ("aiprrReqDay d is null");
} else {
log ("aiprrReqDay d,o are null");
}
}
}
//----------------------------------------------------------------------
// Return true if the reqday has all the resourcess it needs
int aiprrReqDay::is_satisfied () const {
if ( m_dcsn && m_dcsn->is_decided() ) return 1;
return 0;
}
//----------------------------------------------------------------------
// Return true if the reqday has more than enough options
int aiprrReqDay::has_surplus_opts () const {
if (!m_dcsn) return 0;
long remaining_to_decide = m_dcsn->num_to_decide() -
m_dcsn->num_decided();
if (m_dcsn->num_opt_remaining() > remaining_to_decide) return 1;
return 0;
}
//======================================================================
// aiprrResource
//
//----------------------------------------------------------------------
// Constructor
aiprrResource::aiprrResource (long a_id, aiprrProblem *a_prob) {
m_id = a_id;
m_prob = a_prob;
m_resdays = new aipPandemonium;
m_hope = new aipHHHope;
m_is_in_cur_solution = 0;
}
//----------------------------------------------------------------------
// Destructor
aiprrResource::~aiprrResource () {
if (m_resdays) delete m_resdays;
if (m_hope) delete m_hope;
}
//----------------------------------------------------------------------
// add_resday
void aiprrResource::add_resday (aiprrResDay *x) {
if (!x) return;
m_resdays->add (x);
}
//----------------------------------------------------------------------
// take_msg - take and react to a message
void aiprrResource::take_msg (aipMsg *mm) {
aiprrMsg *m = (aiprrMsg *)mm;
if (m->typ() == HH_Starting_New_Try) {
m_is_in_cur_solution = 0;
}
m->set_is_in_cur_solution(m_is_in_cur_solution);
m_hope->take_msg(mm);
m_resdays->take_msg(mm);
}
//----------------------------------------------------------------------
// Note that a decision involving this resource has been decided
void aiprrResource::note_aiprr_decide (aiprrDecision *d, aiprrOption *o) {
if (!d) log ("aiprrReqDay d is null");
// o (ptr to an option) may be null
if (o) m_is_in_cur_solution = 1;
}
//----------------------------------------------------------------------
// resday_iterator
aiprrResDayItr aiprrResource::resday_iterator() const {
aiprrResDayItr i(m_resdays);
return i;
}
//======================================================================
// aiprrResDay
//
//----------------------------------------------------------------------
// Constructor
aiprrResDay::aiprrResDay (aiprrResource *a_res, long a_yyyymmdd) {
m_res = a_res;
m_day = aipTime(a_yyyymmdd);
m_opts = new aipPandemonium;
m_hope = new aipHHHope;
}
//----------------------------------------------------------------------
// Destructor
aiprrResDay::~aiprrResDay () {
if (m_hope) delete m_hope;
if (m_opts) delete m_opts;
}
//----------------------------------------------------------------------
// take_msg - take and react to a message
void aiprrResDay::take_msg (aipMsg *mm) {
aiprrMsg *m = (aiprrMsg *)mm;
if (m->typ() == HH_Starting_New_Try) {
m_is_in_cur_solution = 0;
}
m->set_is_in_cur_solution(m_is_in_cur_solution);
m_hope->take_msg(mm);
}
//----------------------------------------------------------------------
// Note that a decision involving this resday has been decided
void aiprrResDay::note_aiprr_decide (aiprrDecision *d, aiprrOption *o) {
if (!d) log ("aiprrReqDay d is null");
// o (ptr to an option) may be null
if (o) m_is_in_cur_solution = 1;
}
//======================================================================
// 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.
//
//======================================================================
|