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
//**********************************************************************
// rrproj_solv.h - Find a solution to an rrproj problem.
//
// An application should not directly include this file;
// an application should include: rrproj_prob.h
//
// Copyright (c) 2008 Brian Marshall
//
// See the license at end of this file.
//
// An rrproj problem is the problem of assigning staff
// and/or equipment to projects.
//
// Developers/Contributers:
// [BRM] Brian Marshall - Calgary - bmarshal@agt.net
//
// 07/11/21 [BRM] began development
//
//----------------------------------------------------------------------
// About some of the classes...
//
// An rpsProblem is a subclass of aiprrProblem - it is a
// specialization of assigning resources to requirements:
// - a Position is a Requirement; a PosDay is a ReqDay
// - an Employee is a Resource; an EmpDay is a ResDay
// aiprrProblem is a subclass of aipHHProblem, and as such,
// knows how to solve itself using the High-Hope technique.
// See aipReqRes.h and aipHighHope.h
//
// A rpsProblem has a set of decisions, each of which has a set of
// options. A Decision is associated with a Position-Day.
// An Option refers to an Employee that can work the Position-Day.
//
//----------------------------------------------------------------------
// About the status...
//
// This is a very early version. The existing techniques can be
// improved - mostly by improving how messages and calls to
// problem.note_decide are handled.
//
// This software is currently very slow. It does loops within
// loops where a match-merge techinique would be much faster.
// This software will be made faster after enough alpha testing
// has been done.
//
//----------------------------------------------------------------------
// A Note
//
// The program will frequently find the same solution a number of
// times, one after another. This is a normal. Each try affects
// object attributes provided by the aiParts artificial intelligence
// software.
//
//----------------------------------------------------------------------
// Future Development
//
// If required...
// repalce rpsEmployee.set_start_last_work () with a class of
// stats about the current state of the employee
//
//----------------------------------------------------------------------
// Data Model
//
// Note that, except for the Problem, all the objects in the diagram
// below are pandemoniums (ie. lists of objects).
//
// The Problem-owning-Decisions-owning-Options is implemented in
// the Open Source aiParts software. See aipHighHope.h/cpp for
// the general technique and aipReqRes.h/cpp which implements the
// high-hope technique for requirement-resource problems.
// The pandemonium of decisions in a problem is in aipProblem.h/cpp.
// The pandemonium of options in a decision is in aipDecision.h/cpp.
//
// The objects in pandemoniums in this file do not have keys,
// although they are ordered when created by rrproj_fctry.h/cpp.
// The reason for this approach is that the pandemoniums of options
// and decisions are defined in great-grandparent classes.
//
// A PosDay is associated with a Decision. If the PosDay requires
// multiple employees, the Decision will be decided multiple times.
//
// [Employee]<<---[Problem]--->>[Position]
// | | |
// | v v
// | v v
// | [Decision]<-----[PosDay]<<---{Project}
// | |
// v v
// v v
// [EmpDay]----->>[Option]
//
// {Project} is only in the logical model - there is no project
// object; we use proj_id as an optional attribute of Position.
//
//----------------------------------------------------------------------
#ifndef rrproj_solv_h_guard
#define rrproj_solv_h_guard
#include "aipReqRes.h"
//----------------------------------------------------------------------
// Classes. Sub-classing is shown by indentation.
// class aipG is a typedef for aipGoodness
// class aipBase; ( in aipBase.h )
// class aipProblem; ( in aipProblem.h )
// class aipHHProblem; ( in aipHighHope.h )
// class aiprrProblem; ( in aipReqRes.h )
class rpsProblem; // rrproj solver problem
// class aipDemon; ( in aipPandemonium.h )
// class aipDecision; ( in aipDecision.h )
// class aipHHDecision; ( in aipHighHope.h )
// class aiprrDecision; ( in aipReqRes.h )
class rpsDecision; // decision: emp to work position-day
// class aipOption; ( in aipDecision.h )
// class aipHHOption; ( in aipHighHope.h )
// class aiprrOption; ( in aipReqRes.h )
class rpsOption; // option: an emp on a day
// class aiprrRequirement; ( in aipReqRes.h )
class rpsPosition; // position requiring employees
// class aiprrReqDay; ( in aipReqRes.h )
class rpsPosDay; // position on a day
// class aiprrResource; ( in aipReqRes.h )
class rpsEmployee; // employee that can work positions
// class aiprrResDay; ( in aipReqRes.h )
class rpsEmpDay; // employee on a day
// class aipDemonItr; ( in aipPandemonium.h )
class rpsPositionItr; // position iterator
class rpsPosDayItr; // posday iterator
class rpsEmployeeItr; // employee iterator
class rpsEmpDayItr; // empday iterator
class rpsDecisionItr; // decision iterator
class rpsOptItr; // opt iterator for empday
// class aipMsg ( in aipBase.h )
// class aiprrMsg; ( in aipReqRes.h )
class rpsMsg; // message for rrproj solving
//======================================================================
// rpsProblem - rrproj solver problem that can solve itself
//
// Parent classes provide: decisions
//
// solve_rr_problem () returns 1 (true) if a solution is found,
// zero otherwise.
//
// aiprrProblem provides:
// void set_num_try (long x);
// int should_log_options () const;
// void add_decision (aiprrDecision *x);
//
// m_start_day and m_end_day are set by the factory to
// the range of days of the set of positions.
class rpsProblem : public aiprrProblem {
aipTime m_start_day;
aipTime m_end_day;
protected:
virtual void apply_emp_aspects (rpsDecision *d, rpsOption *o);
virtual void log_decide (rpsDecision *d, rpsOption *o);
virtual void log_this_try ();
public:
rpsProblem ();
virtual ~rpsProblem ();
void add_position (rpsPosition *x);
void add_employee (rpsEmployee *x);
void set_day_range (long start_yyyymmdd, long end_yyyymmdd);
aipTime start_day () const { return m_start_day; }
aipTime end_day () const { return m_end_day; }
rpsPositionItr position_iterator() const;
rpsEmployeeItr employee_iterator() const;
rpsDecisionItr decision_iterator() const;
virtual void take_msg (aipMsg *m);
virtual void note_decide (aipHHDecision *d, aipHHOption *o);
virtual int solve_rr_problem () {
return aiprrProblem::solve_rr_problem(); // 1 on success
}
};
//======================================================================
// rpsDecision - choosing an emp for a posday
//
// Parent classes provide: options, hope, importance
class rpsDecision : public aiprrDecision {
public:
rpsDecision (rpsPosDay *a_posday, long num_to_decide =1);
virtual ~rpsDecision();
void add_rps_option (rpsOption *x);
virtual void take_msg (aipMsg *m);
rpsProblem * prob () const { return (rpsProblem*)owner(); }
rpsPosDay * posday () const { return (rpsPosDay*)reqday(); }
rpsOption * rps_opt_cur () const {
return (rpsOption*)aiprr_opt_cur();
}
rpsOption * rps_opt_bsf () const {
return (rpsOption*)aiprr_opt_bsf();
}
};
//======================================================================
// rpsOption - an employee working a position on a day
//
// Parent classes provide: hope, importance, goodness variables
class rpsOption : public aiprrOption {
public:
rpsOption(rpsEmpDay *a_empday, aipG g_constant);
virtual ~rpsOption ();
rpsDecision * rps_chooser () const {
return (rpsDecision*)aiprr_chooser();
}
virtual void take_msg (aipMsg *m);
rpsEmpDay * empday () const { return (rpsEmpDay*)resday(); }
rpsPosDay * posday () const {
// we use owner instead of chooser, so an opt is always
// for a posday. This depends on, in this file, options
// are not shared between decisions.
rpsDecision *d = (rpsDecision*)(hh_opt_owner());
return d ? d->posday() : 0;
}
rpsPosDay * bsf_posday () const {
rpsDecision *d = (rpsDecision*)(aipHHOption::hh_bsf_chooser());
return d ? d->posday() : 0;
}
rpsEmployee * emp () const;
rpsPosition * pos () const;
aipTime day () const;
virtual aipG g_opt(); // for making decisions
virtual aipG g_opt_cmp(); // for comparing solutions
virtual aipG g_opt_usr(); // for reporting to the user
};
//======================================================================
// rpsPosition - a position requiring employees
//
// A position is owned by a problem; it owns position-days.
//
// Parent classes provide: id()
//
// A position is identified by: pos_id()
class rpsPosition : public aiprrRequirement {
public:
rpsPosition(long a_pos_id, rpsProblem *a_prob);
virtual ~rpsPosition() {}
virtual long num_keys (void) const { return 1; }
virtual long key1 (void) const { return aiprrRequirement::id(); }
void add_posday (rpsPosDay *x);
virtual void take_msg (aipMsg *m);
// virtual void note_rps_decide (rpsDecision *d, rpsOption *o);
rpsProblem * prob () const {
return (rpsProblem*)(aiprrRequirement::prob());
}
long pos_id () const {
return aiprrRequirement::id();
}
rpsPosDayItr posday_iterator() const;
};
//======================================================================
// rpsPosDay - a position on a day (requiring one or more employees)
//
// Parent classes provide day()
//
// The proj_id is optional - if the solver is to pay attention
// to it, it should be greater than zero.
class rpsPosDay : public aiprrReqDay {
long m_proj_id;
aipTime m_start_time;
aipTime m_end_time;
long m_yyyymmdd;
public:
rpsPosDay(rpsPosition *a_pos, long a_yyyymmdd, long a_proj_id,
long a_start_hhmm =800, long a_end_hhmm =1700);
virtual ~rpsPosDay();
virtual long num_keys (void) const { return 3; }
virtual long key1 (void) const { return aiprrReqDay::req()->id(); }
virtual long key2 (void) const { return m_yyyymmdd; }
virtual long key3 (void) const { return m_proj_id; }
virtual void take_msg (aipMsg *m);
// virtual void note_rps_decide (rpsDecision *d, rpsOption *o);
rpsPosition * pos () const {
return (rpsPosition*)(aiprrReqDay::req());
}
long pos_id () const {
return ( aiprrReqDay::req()->id() );
}
long proj_id () const {
return m_proj_id;
}
rpsDecision * dcsn () const {
return (rpsDecision*)(aiprrReqDay::dcsn());
}
aipTime start_time () const { return m_start_time; }
aipTime end_time () const { return m_end_time; }
long yyyymmdd () const { return m_yyyymmdd; }
};
//======================================================================
// rpsEmployee - an employee that can work positions
//
// Parent classes provide id()
class rpsEmployee : public aiprrResource {
// this last-work logic is adequate for event-scheduling
aipG m_g_last_work;
aipTime m_start_last_work; // on first day of problem
public:
rpsEmployee(long a_id, rpsProblem *a_prob);
virtual ~rpsEmployee();
virtual long num_keys (void) const { return 1; }
virtual long key1 (void) const { return aiprrResource::id(); }
void add_empday (rpsEmpDay *x);
void set_start_last_work (aipTime x);
void reset_g_last_work () { m_g_last_work = aipNeutral; }
virtual void take_msg (aipMsg *m);
// virtual void note_rps_decide (rpsDecision *d, rpsOption *o);
rpsProblem * prob () const {
return (rpsProblem*)(aiprrResource::prob());
}
long emp_id () const {
return aiprrResource::id();
}
aipG g_last_work () const { return m_g_last_work; }
rpsEmpDayItr empday_iterator() const;
};
//======================================================================
// rpsEmpDay - an employee on a day
//
// Parent classes provide day()
class rpsEmpDay : public aiprrResDay {
aipTime m_start_time;
aipTime m_end_time;
long m_yyyymmdd;
public:
rpsEmpDay(rpsEmployee *a_emp, long a_yyyymmdd,
long a_start_hhmm =800, long a_end_hhmm =2200);
virtual ~rpsEmpDay() {}
virtual long num_keys (void) const { return 2; }
virtual long key1 (void) const { return aiprrResDay::res()->id(); }
virtual long key2 (void) const { return m_yyyymmdd; }
virtual void take_msg (aipMsg *m);
// virtual void note_rps_decide (rpsDecision *d, rpsOption *o);
rpsEmployee * emp () const {
return (rpsEmployee*)(aiprrResDay::res());
}
long emp_id () const {
return (aiprrResDay::res()->id());
}
aipTime start_time () const { return m_start_time; }
aipTime end_time () const { return m_end_time; }
long yyyymmdd () const { return m_yyyymmdd; }
rpsOptItr opt_iterator() const;
};
//======================================================================
// rpsPositionItr - Iterator for Positions in a Problem
class rpsPositionItr : public aipDemonItr {
public:
rpsPositionItr (aipPandemonium *p) {
set_demon_itr(p,0);
}
rpsPositionItr (const rpsPositionItr& x) {
set_demon_itr (x.pandemonium(), x.current());
}
virtual ~rpsPositionItr () {}
rpsPositionItr& operator = (const rpsPositionItr& x) {
set_demon_itr(x.pandemonium(), x.current());
return *this;
}
rpsPosition * first () {
return (rpsPosition*)aipDemonItr::first();
}
rpsPosition * next () {
return (rpsPosition*)aipDemonItr::next();
}
};
//======================================================================
// rpsPosDayItr - Iterator for PosDays of a Position
class rpsPosDayItr : public aipDemonItr {
public:
rpsPosDayItr (aipPandemonium *p) {
set_demon_itr(p,0);
}
rpsPosDayItr (const rpsPosDayItr& x) {
set_demon_itr (x.pandemonium(), x.current());
}
virtual ~rpsPosDayItr () {}
rpsPosDayItr& operator = (const rpsPosDayItr& x) {
set_demon_itr(x.pandemonium(), x.current());
return *this;
}
rpsPosDay * first () {
return (rpsPosDay*)aipDemonItr::first();
}
rpsPosDay * next () {
return (rpsPosDay*)aipDemonItr::next();
}
};
//======================================================================
// rpsEmployeeItr - Iterator for Employees in a Problem
class rpsEmployeeItr : public aipDemonItr {
public:
rpsEmployeeItr (aipPandemonium *p) {
set_demon_itr(p,0);
}
rpsEmployeeItr (const rpsEmployeeItr& x) {
set_demon_itr (x.pandemonium(), x.current());
}
virtual ~rpsEmployeeItr () {}
rpsEmployeeItr& operator = (const rpsEmployeeItr& x) {
set_demon_itr(x.pandemonium(), x.current());
return *this;
}
rpsEmployee * first () {
return (rpsEmployee*)aipDemonItr::first();
}
rpsEmployee * next () {
return (rpsEmployee*)aipDemonItr::next();
}
};
//======================================================================
// rpsEmpDayItr - Iterator for EmpDays of an Employee
class rpsEmpDayItr : public aipDemonItr {
public:
rpsEmpDayItr (aipPandemonium *p) {
set_demon_itr(p,0);
}
rpsEmpDayItr (const rpsEmpDayItr& x) {
set_demon_itr (x.pandemonium(), x.current());
}
virtual ~rpsEmpDayItr () {}
rpsEmpDayItr& operator = (const rpsEmpDayItr& x) {
set_demon_itr(x.pandemonium(), x.current());
return *this;
}
rpsEmpDay * first () {
return (rpsEmpDay*)aipDemonItr::first();
}
rpsEmpDay * next () {
return (rpsEmpDay*)aipDemonItr::next();
}
};
//======================================================================
// rpsDecisionItr - Iterator for Decisions in a Problem
class rpsDecisionItr : public aipDemonItr {
public:
rpsDecisionItr (aipPandemonium *p) {
set_demon_itr(p,0);
}
rpsDecisionItr (const rpsDecisionItr& x) {
set_demon_itr (x.pandemonium(), x.current());
}
virtual ~rpsDecisionItr () {}
rpsDecisionItr& operator = (const rpsDecisionItr& x) {
set_demon_itr(x.pandemonium(), x.current());
return *this;
}
rpsDecision * first () {
return (rpsDecision*)aipDemonItr::first();
}
rpsDecision * next () {
return (rpsDecision*)aipDemonItr::next();
}
};
//======================================================================
// rpsOptItr - Iterator for Opts for an EmpDay
class rpsOptItr : public aipDemonItr {
public:
rpsOptItr (aipPandemonium *p) {
set_demon_itr(p,0);
}
rpsOptItr (const rpsOptItr& x) {
set_demon_itr (x.pandemonium(), x.current());
}
virtual ~rpsOptItr () {}
rpsOptItr& operator = (const rpsOptItr& x) {
set_demon_itr(x.pandemonium(), x.current());
return *this;
}
rpsOption * first () {
return (rpsOption*)aipDemonItr::first();
}
rpsOption * next () {
return (rpsOption*)aipDemonItr::next();
}
};
//======================================================================
// rpsMsg - message for rrproj problem-solving
class rpsMsg : public aiprrMsg {
public:
rpsMsg (rpsProblem *p, short typ) : aiprrMsg(p,typ) {}
~rpsMsg() {}
};
//======================================================================
#endif
//======================================================================
// 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.
//
//**********************************************************************
|