📄 rrproj_solv.h
字号:
//**********************************************************************
// 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 {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -