📄 aiphighhope.cpp
字号:
//**********************************************************************
// aipHighHope.cpp - function bodies for aipHighHope.h
//
// Copyright (c) 1999, 2005, 2008 Brian Marshall
//
// See the license at end of this file.
//
// Developers/Contributers:
// [BRM] Brian Marshall - Calgary - bmarshal@agt.net
//
// 08/06/16 [BRM] added decision is_decided(),
// removed decision groups, modified deciding,
// new next_decision(), added aipHHImportance,
// decisions may be decided more than once,
// removed dcsn.m_opt_prev; small changes
// 05/11/18 [BRM] added decision groups
// worst decision optionally has extra weight
// a failed decision gets increase in fear
// moved call disable_slowly_degrade() to aipHHHope
// fixed minor bug re: problem members: m_is_many_xxx
// fixed minor bug re: m_tries_since_change_count
// 05/11/12 [BRM] moved logic from problem to hope aspects
// 05/11/07 [BRM] moved random_num() to class aipBase
// 05/11/01 [BRM] count tries to get to best try
// 05/10/20 [BRM] fixed bug re: count since improvement
// disabled hope emotions slowly degrading
// modified how decision and option hopes change
// 05/10/02 [BRM] split out from aipProblem and aipDecision
// 05/09/26 [BRM] development began
//
//----------------------------------------------------------------------
// The key functions are...
//
// aipG aipHHProblem::solve()
// implements the High-Hope problem-solving technique
//
// void aipHHDecision::take_msg (aipMsg *m)
// void aipHHOption::take_msg (aipMsg *m)
// void aipHHFearAspect::take_msg (aipMsg *m)
// void aipHHGreedAspect::take_msg (aipMsg *m)
// void aipHHCuriosityAspect::take_msg (aipMsg *m)
// decisions and options are affected by a received message
//
// Maybe:
// void aipHHProblem::normalize_option_goodnesses()
// something like this might be used in some kinds of problems
// in which (some) options have a constant goodness that should
// affect which option is chosen.
//
// Note that shortest-path-from-A-to-B problems, for example,
// do not use normalize_option_goodnesses() - a short step is
// not favored over a long step - people like non-stop flights.
//
//----------------------------------------------------------------------
#include "aipHighHope.h"
#include <string.h>
#include <iostream>
using namespace std;
//======================================================================
// aipHHImportance - importance for choosing decisions
//
//----------------------------------------------------------------------
// take_msg - take a message and maybe do something because of it
void aipHHImportance::take_msg (aipMsg *mm) {
aipHHMsg *m = (aipHHMsg *)mm;
if (m->typ() == HH_Try_Has_Ended) {
if (m->is_the_failure()) m_been_prob += 16;
long imp_val = val();
if (imp_val > 64) {
m_been_prob -= 12;
} else if (imp_val > 16) {
m_been_prob -= 4;
}
} else if (m->typ() == HH_No_Recent_Improve) {
m_been_prob /= 2;
}
aipImportance::take_msg(mm);
}
//======================================================================
// aipHHHope - Hope with High-Hope aspects
//
//----------------------------------------------------------------------
// Constructor
aipHHHope::aipHHHope () {
aipHHFearAspect *fear_aspect = new aipHHFearAspect;
aipHHGreedAspect *greed_aspect = new aipHHGreedAspect;
aipHHCuriosityAspect *curiosity_aspect = new aipHHCuriosityAspect;
if (fear_aspect && greed_aspect && curiosity_aspect) {
if (fear()) fear()->add_aspect(fear_aspect);
if (greed()) greed()->add_aspect(greed_aspect);
if (curiosity()) curiosity()->add_aspect(curiosity_aspect);
}
disable_slowly_degrade();
}
//======================================================================
// aipHHFearAspect - how messages affect fear in hope
//
//----------------------------------------------------------------------
// take_msg
void aipHHFearAspect::take_msg (aipMsg *mm) {
aipHHMsg *m = (aipHHMsg *)mm;
aipHHSolveStat *ss = m->solve_stat();
if (!fear() || !ss) return;
if (m->typ() == HH_Starting_Solve) {
fear()->set_g(aipNeutral);
} else if (m->typ() == HH_No_Recent_Change) {
} else if (m->typ() == HH_No_Recent_Improve) {
fear()->weaken(aipIntensity_A_Little);
} else if (m->typ() == HH_No_Recent_Best_So_Far) {
fear()->weaken(aipIntensity_Somewhat);
} else if (m->typ() == HH_Try_Has_Ended) {
if ( ss->try_result() == HH_Try_Has_Failed ) {
if (m->is_in_cur_solution()) {
fear()->strengthen(aipIntensity_Slightly);
} else if (m->is_the_failure()) {
fear()->strengthen(aipIntensity_A_Little);
}
} else { // a complete solution was found
if (m->is_in_cur_solution()) {
fear()->weaken(aipIntensity_A_Little);
}
} // end of block for when a complete solution was found
}
aipAspect::take_msg(mm);
}
//======================================================================
// aipHHGreedAspect - how messages affect greed in hope
//
//----------------------------------------------------------------------
// take_msg
void aipHHGreedAspect::take_msg (aipMsg *mm) {
aipHHMsg *m = (aipHHMsg *)mm;
aipHHSolveStat *ss = m->solve_stat();
if (m->typ() == HH_Starting_Solve) {
greed()->set_g(aipNeutral);
} else if (m->typ() == HH_Try_Has_Ended) {
if ( ss->try_result() == HH_Try_Is_New_Best ) {
if (greed()->g() >= Greed_For_Best) {
greed()->set_g(Greed_For_Was_Best);
}
}
if ( ss->try_result() == HH_Try_Is_Improved ) {
if (greed()->g() == Greed_For_Improved) {
greed()->set_g(Greed_For_Changed);
}
}
if ( ss->try_result() == HH_Try_Is_Changed ) {
if (greed()->g() == Greed_For_Changed) {
greed()->set_g(Greed_For_Complete);
}
}
if ( ss->try_result() == HH_Try_Has_Failed ) {
} else { // a complete solution was found
if (m->is_in_cur_solution()) {
if ( ss->try_result() == HH_Try_Is_New_Best ) {
greed()->set_g(Greed_For_New_Best);
} else if ( ss->try_result() == HH_Try_Is_A_Best ) {
greed()->set_g(Greed_For_Best);
} else if ( ss->try_result() == HH_Try_Is_Improved &&
greed()->g() < Greed_For_Improved ) {
greed()->set_g(Greed_For_Improved);
} else if ( ss->try_result() == HH_Try_Is_Changed &&
greed()->g() < Greed_For_Changed ) {
greed()->set_g(Greed_For_Changed);
} else if ( ss->try_result() == HH_Try_Is_Complete &&
greed()->g() < Greed_For_Complete ) {
greed()->set_g(Greed_For_Complete);
}
} // end of block for decision in current solution
} // end of block for when a complete solution was found
}
aipAspect::take_msg(mm);
}
//======================================================================
// aipHHCuriosityAspect - how messages affect curiosityin hope
//
//----------------------------------------------------------------------
// take_msg
void aipHHCuriosityAspect::take_msg (aipMsg *mm) {
aipHHMsg *m = (aipHHMsg *)mm;
aipHHSolveStat *ss = m->solve_stat();
if (m->typ() == HH_Starting_Solve) {
curiosity()->set_g(Curiosity_Starting);
} else if (m->typ() == HH_No_Recent_Change) {
if ( ! m->is_in_cur_solution() ) {
curiosity()->set_g(Curiosity_Starting);
}
} else if (m->typ() == HH_No_Recent_Improve) {
curiosity()->set_g(Curiosity_Starting);
} else if (m->typ() == HH_No_Recent_Best_So_Far) {
curiosity()->set_g(Curiosity_Starting);
curiosity()->strengthen(aipIntensity_Somewhat);
} else if (m->typ() == HH_Try_Has_Ended) {
if ( ss->try_result() == HH_Try_Has_Failed ) {
if (m->is_in_cur_solution()) {
curiosity()->weaken(aipIntensity_A_Little);
}
} else { // a complete solution was found
if (m->is_in_cur_solution()) {
curiosity()->weaken(aipIntensity_Somewhat);
if ( ss->try_result() == HH_Try_Is_New_Best ) {
// Greed will go up, curiosity comes down...
curiosity()->weaken(aipIntensity_Somewhat); // more
}
} // end of block for decision in current solution
} // end of block for when a complete solution was found
}
aipAspect::take_msg(mm);
}
//======================================================================
// aipHHProblem
//
//----------------------------------------------------------------------
// Constructor
aipHHProblem::aipHHProblem () {
m_num_try = 1000;
m_dcsn_is_progress = m_worst_is_extra_bad = 0;
m_should_log_tries = 1; // default to: write to log about tries
m_solve_stat = new aipHHSolveStat (this);
}
//----------------------------------------------------------------------
// Destructor
aipHHProblem::~aipHHProblem () {
if (m_solve_stat) delete m_solve_stat;
}
//----------------------------------------------------------------------
// add_hh_decision
void aipHHProblem::add_hh_decision (aipHHDecision *x) {
aipProblem::add_decision(x);
}
//----------------------------------------------------------------------
// hh_decision_iterator
aipHHDecisionItr aipHHProblem::hh_decision_iterator() const {
aipHHDecisionItr i(decision_pandemonium());
return i;
}
//----------------------------------------------------------------------
// return the number of decisions to be made
long aipHHProblem::num_decisions() const {
long num_dcsn = 0;
aipHHDecisionItr itr = hh_decision_iterator();
aipHHDecision *d;
for ( d = itr.first(); d; d = itr.next() ) {
num_dcsn += d->num_to_decide();
}
return num_dcsn;
}
//----------------------------------------------------------------------
// g - goodness meaningful to user
aipG aipHHProblem::g() {
return solve_stat()->g_usr_bsf();
}
//----------------------------------------------------------------------
// normalize_option_goodnesses - sample - for some problems
//
// A function like this SAMPLE might be used in some types of
// problems, in which the goodness of an option (to the user)
// should be considered in picking options.
//
// This function is used to convert values meaningful to the user
// (ex. miles, dollars, minutes) to goodness values that can be
// combined and compared with other goodness values.
//
// A normalize_option_goodnesses() function (that might or might not
// look like this sample) might be used in staff-scheduling, where
// a supervisor could work a shift as a clerk, but only if it was
// absolutely necessary.
//
// A normalize_option_goodnesses() function would not generally
// be used in a find-the-shortest-path-from-A-to-B problem, where
// a short step is not favored over a longer step; taking a short
// step can simply mean another longer step is required.
//
// Option goodness m_g_constant is initially set to m_g_user_constant.
// If these values are normal goodnesses, this function is not used.
//
// Note that m_g_constant and m_g_user_constant may contain negative
// values because:
// - they are values the user considers to be negative, or,
// - they are value that the user wants solve() to minimize.
//
// This can really be improved, but for a first version...
//
// Calculate a divisor as: max-absolute-value / 16, and then:
// - for positive values: x = (x / divisor) + 1
// - for negative values: x = (x / divisor) - 1
//
// This could work ok. It will work very poorly if most of the
// values are between, say, 1 and 100, and there are a few values
// that are greater than 100000; all the smaller values will be
// normalized to 1.
void aipHHProblem::normalize_option_goodnesses () {
aipHHDecisionItr d_itr = hh_decision_iterator();
aipHHDecision *dec; // used with the decision-iterator
aipHHOption *opt; // used with the option-iterator
aipG g_min = aipManditory; // Find min and max
aipG g_max = aipForbidden;
for ( dec = d_itr.first(); dec; dec = d_itr.next() ) {
aipHHOptionItr o_itr = dec->hh_option_iterator();
for ( opt = o_itr.first(); opt; opt = o_itr.next() ) {
if (opt->g_user_constant() < g_min)
g_min = opt->g_user_constant();
if (opt->g_user_constant() > g_max)
g_max = opt->g_user_constant();
} // end of loop through options in the decision
} // end of loop through decisions
long max_abs_val = g_min.absolute_value();
if (g_max.numeric_value() > max_abs_val) {
max_abs_val = g_max.numeric_value();
}
if (max_abs_val < 20) return;
long divisor = max_abs_val / 16;
for ( dec = d_itr.first(); dec; dec = d_itr.next() ) {
aipHHOptionItr o_itr = dec->hh_option_iterator();
for ( opt = o_itr.first(); opt; opt = o_itr.next() ) {
long val = opt->g_user_constant().numeric_value();
if (val > 0) {
val = (val / divisor) + 1;
} else if (val < 0) {
val = (val / divisor) - 1;
}
if (val) opt->set_norm_g_constant(val);
}
}
}
//----------------------------------------------------------------------
// solve
//
// Return a goodness that is meaningful to the user - this might
// be a goodness, or it might be dollars, miles, hours, etc.
//
// This function, plus the take_msg() function on decisions and
// options, are the implementation of the High-Hope technique.
//
// It would seem that it would be appropriate to have a separate
// try() function, but it would be only a small proportion of this
// function, and it would change variables set in this function.
// Having it all in this function is the clearest way.
aipG aipHHProblem::solve() {
aipHHSolveStat * ss = solve_stat();
aipHHMsg msg_starting_solve (this, HH_Starting_Solve);
aipHHMsg msg_solve_has_ended (this, HH_Solve_Has_Ended);
aipHHMsg msg_starting_try (this, HH_Starting_New_Try);
aipHHMsg msg_try_has_ended (this, HH_Try_Has_Ended);
aipHHMsg msg_this_is_bsf (this, HH_This_Is_Best_So_Far);
aipHHMsg msg_no_recent_bsf (this, HH_No_Recent_Best_So_Far);
aipHHMsg msg_no_recent_improve (this, HH_No_Recent_Improve);
aipHHMsg msg_no_recent_change (this, HH_No_Recent_Change);
take_msg(&msg_starting_solve);
ss->m_g_cmp_cur = ss->m_g_cmp_bsf = ss->m_g_usr_bsf = aipForbidden;
for (ss->m_i_try=0; ss->m_i_try<m_num_try; ss->m_i_try++) {
ss->m_g_cmp_prev = ss->m_g_cmp_cur;
ss->m_g_cmp_cur = aipNeutral;
ss->m_num_decisions_prev = ss->m_num_decisions_made;
ss->m_num_decisions_made = 0;
ss->m_failed_decision = 0;
ss->m_worst_decision = 0;
ss->m_worst_decision_g_cmp = aipForbidden;
take_msg(&msg_starting_try);
try_to_find_solution(); // try
take_msg(&msg_try_has_ended);
if (ss->try_is_new_best()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -