<commit_before>/*
 * opencog/atomspace/AttentionBank.cc
 *
 * Copyright (C) 2013 <NAME> <<EMAIL>>
 * All Rights Reserved
 *
 * Written by <NAME>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <boost/bind.hpp>
#include <opencog/util/Config.h>

#include <opencog/atoms/base/Handle.h>
#include "AttentionBank.h"
#include "AtomSpace.h"

using namespace opencog;

AttentionBank::AttentionBank(AtomSpace *asp, bool transient)
    : _as(asp)
    , _index_insert_queue(this, &AttentionBank::put_atom_into_index, transient?0:4)
    , _index_remove_queue(this, &AttentionBank::remove_atom_from_index, transient?0:4)
{
    /* Do not boether with initialization, if this is transient */
    if (transient) { _zombie = true; return; }
    _zombie = false;

    startingFundsSTI = fundsSTI = config().get_int("STARTING_STI_FUNDS", 100000);
    startingFundsLTI = fundsLTI = config().get_int("STARTING_LTI_FUNDS", 100000);
    stiFundsBuffer = config().get_int("STI_FUNDS_BUFFER", 10000);
    ltiFundsBuffer = config().get_int("LTI_FUNDS_BUFFER", 10000);
    targetLTI = config().get_int("TARGET_LTI_FUNDS", 10000);
    targetSTI = config().get_int("TARGET_STI_FUNDS", 10000);
    STIAtomWage = config().get_int("ECAN_STARTING_ATOM_STI_WAGE", 10);
    LTIAtomWage = config().get_int("ECAN_STARTING_ATOM_LTI_WAGE", 10);

    bool async = config().get_bool("ATTENTION_BANK_ASYNC",false);

    _attentionalFocusBoundary = 1;

    // Subscribe to my own changes. This is insane and hacky; must move
    // the AV stuf out of the Atom itself.  XXX FIXME.
    _AVChangedConnection =
        _AVChangedSignal.connect(
            boost::bind(&AttentionBank::AVChanged, this, _1, _2, _3));

    if (async) {
     _addAtomConnection =
        asp->addAtomSignal(
            boost::bind(&AttentionBank::add_atom_to_indexInsertQueue, this, _1));
    _removeAtomConnection =
        asp->removeAtomSignal(
            boost::bind(&AttentionBank::add_atom_to_indexRemoveQueue, this, _1));
    }
    else {
     _addAtomConnection =
        asp->addAtomSignal(
            boost::bind(&AttentionBank::put_atom_into_index, this, _1));
    _removeAtomConnection =
        asp->removeAtomSignal(
            boost::bind(&AttentionBank::remove_atom_from_index, this, _1));

    }
}

/// This must be called before the AtomTable is destroyed. Which
/// means that it cannot be in the destructor (since the AtomTable
/// is gone by then, leading to a crash.  XXX FIXME yes this is a
/// tacky hack to fix a design bug.
void AttentionBank::shutdown(void)
{
    if (_zombie) return;  /* no-op, if a zombie */
    _AVChangedConnection.disconnect();
    _addAtomConnection.disconnect();
    _removeAtomConnection.disconnect();
}

AttentionBank::~AttentionBank() {}


void AttentionBank::AVChanged(const Handle& h,
                              const AttentionValuePtr& old_av,
                              const AttentionValuePtr& new_av)
{
    AttentionValue::sti_t newSti = new_av->getSTI();
    
    // Add the old attention values to the AtomSpace funds and
    // subtract the new attention values from the AtomSpace funds
    updateSTIFunds(old_av->getSTI() - newSti);
    updateLTIFunds(old_av->getLTI() - new_av->getLTI());

    // Update MinMax STI values
   UnorderedHandleSet minbin = _importanceIndex.getMinBinContents();
    AttentionValue::sti_t minSTISeen = (*std::min_element(minbin.begin(),minbin.end(),
            [](const Handle& h1, const Handle& h2) {
            return h1->getAttentionValue()->getSTI() < h2->getAttentionValue()->getSTI();
            }))->getAttentionValue()->getSTI();

    UnorderedHandleSet maxbin = _importanceIndex.getMaxBinContents();
    AttentionValue::sti_t maxSTISeen = (*std::max_element(maxbin.begin(),maxbin.end(),
            [](const Handle& h1, const Handle& h2) {
            return h1->getAttentionValue()->getSTI() > h2->getAttentionValue()->getSTI();
            }))->getAttentionValue()->getSTI();

    if (minSTISeen > maxSTISeen) {
        minSTISeen = maxSTISeen;
    }

    _as->update_max_STI(maxSTISeen);
    _as->update_min_STI(minSTISeen);

    logger().fine("AVChanged: fundsSTI = %d, old_av: %d, new_av: %d",
                   fundsSTI.load(), old_av->getSTI(), new_av->getSTI());

    // Check if the atom crossed into or out of the AttentionalFocus
    // and notify any interested parties
    if (old_av->getSTI() < getAttentionalFocusBoundary() and
        new_av->getSTI() >= getAttentionalFocusBoundary())
    {
        AFCHSigl& afch = AddAFSignal();
        afch(h, old_av, new_av);
    }
    else if (new_av->getSTI() < getAttentionalFocusBoundary() and
             old_av->getSTI() >= getAttentionalFocusBoundary())
    {
        AFCHSigl& afch = RemoveAFSignal();
        afch(h, old_av, new_av);
    }
}

void AttentionBank::stimulate(Handle& h, double stimulus)
{
    // XXX This is not protected and made atomic in any way ...
    // If two different threads stiumlate the same atom at the same
    // time, then the calculations could get wonky. Does it matter?
    AttentionValue::sti_t sti   = h->getAttentionValue()->getSTI();
    AttentionValue::lti_t lti   = h->getAttentionValue()->getLTI();
    AttentionValue::vlti_t vlti = h->getAttentionValue()->getVLTI();

    int stiWage = calculateSTIWage() * stimulus;
    int ltiWage = calculateLTIWage() * stimulus;

    AttentionValuePtr new_av = createAV(sti + stiWage, lti + ltiWage, vlti);
    h->setAttentionValue(new_av);
}

void AttentionBank::updateMaxSTI(AttentionValue::sti_t m)
{
    std::lock_guard<std::mutex> lock(_lock_maxSTI);
    _maxSTI.update(m);
}

void AttentionBank::updateMinSTI(AttentionValue::sti_t m)
{
    std::lock_guard<std::mutex> lock(_lock_minSTI);
    _minSTI.update(m);
}

AttentionValue::sti_t AttentionBank::getMaxSTI(bool average) const
{
    std::lock_guard<std::mutex> lock(_lock_maxSTI);
    if (average) {
        return (AttentionValue::sti_t) _maxSTI.recent;
    } else {
        return _maxSTI.val;
    }
}

AttentionValue::sti_t AttentionBank::getMinSTI(bool average) const<commit_msg>Change type<commit_after>/*
 * opencog/atomspace/AttentionBank.cc
 *
 * Copyright (C) 2013 <NAME> <<EMAIL>>
 * All Rights Reserved
 *
 * Written by <NAME>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <boost/bind.hpp>
#include <opencog/util/Config.h>

#include <opencog/atoms/base/Handle.h>
#include "AttentionBank.h"
#include "AtomSpace.h"

using namespace opencog;

AttentionBank::AttentionBank(AtomSpace *asp, bool transient)
    : _as(asp)
    , _index_insert_queue(this, &AttentionBank::put_atom_into_index, transient?0:4)
    , _index_remove_queue(this, &AttentionBank::remove_atom_from_index, transient?0:4)
{
    /* Do not boether with initialization, if this is transient */
    if (transient) { _zombie = true; return; }
    _zombie = false;

    startingFundsSTI = fundsSTI = config().get_int("STARTING_STI_FUNDS", 100000);
    startingFundsLTI = fundsLTI = config().get_int("STARTING_LTI_FUNDS", 100000);
    stiFundsBuffer = config().get_int("STI_FUNDS_BUFFER", 10000);
    ltiFundsBuffer = config().get_int("LTI_FUNDS_BUFFER", 10000);
    targetLTI = config().get_int("TARGET_LTI_FUNDS", 10000);
    targetSTI = config().get_int("TARGET_STI_FUNDS", 10000);
    STIAtomWage = config().get_int("ECAN_STARTING_ATOM_STI_WAGE", 10);
    LTIAtomWage = config().get_int("ECAN_STARTING_ATOM_LTI_WAGE", 10);

    bool async = config().get_bool("ATTENTION_BANK_ASYNC",false);

    _attentionalFocusBoundary = 1;

    // Subscribe to my own changes. This is insane and hacky; must move
    // the AV stuf out of the Atom itself.  XXX FIXME.
    _AVChangedConnection =
        _AVChangedSignal.connect(
            boost::bind(&AttentionBank::AVChanged, this, _1, _2, _3));

    if (async) {
     _addAtomConnection =
        asp->addAtomSignal(
            boost::bind(&AttentionBank::add_atom_to_indexInsertQueue, this, _1));
    _removeAtomConnection =
        asp->removeAtomSignal(
            boost::bind(&AttentionBank::add_atom_to_indexRemoveQueue, this, _1));
    }
    else {
     _addAtomConnection =
        asp->addAtomSignal(
            boost::bind(&AttentionBank::put_atom_into_index, this, _1));
    _removeAtomConnection =
        asp->removeAtomSignal(
            boost::bind(&AttentionBank::remove_atom_from_index, this, _1));

    }
}

/// This must be called before the AtomTable is destroyed. Which
/// means that it cannot be in the destructor (since the AtomTable
/// is gone by then, leading to a crash.  XXX FIXME yes this is a
/// tacky hack to fix a design bug.
void AttentionBank::shutdown(void)
{
    if (_zombie) return;  /* no-op, if a zombie */
    _AVChangedConnection.disconnect();
    _addAtomConnection.disconnect();
    _removeAtomConnection.disconnect();
}

AttentionBank::~AttentionBank() {}


void AttentionBank::AVChanged(const Handle& h,
                              const AttentionValuePtr& old_av,
                              const AttentionValuePtr& new_av)
{
    AttentionValue::sti_t newSti = new_av->getSTI();
    
    // Add the old attention values to the AtomSpace funds and
    // subtract the new attention values from the AtomSpace funds
    updateSTIFunds(old_av->getSTI() - newSti);
    updateLTIFunds(old_av->getLTI() - new_av->getLTI());

    // Update MinMax STI values
   UnorderedHandleSet minbin = _importanceIndex.getMinBinContents();
    AttentionValue::sti_t minSTISeen = (*std::min_element(minbin.begin(),minbin.end(),
            [](const Handle& h1, const Handle& h2) {
            return h1->getAttentionValue()->getSTI() < h2->getAttentionValue()->getSTI();
            }))->getAttentionValue()->getSTI();

    UnorderedHandleSet maxbin = _importanceIndex.getMaxBinContents();
    AttentionValue::sti_t maxSTISeen = (*std::max_element(maxbin.begin(),maxbin.end(),
            [](const Handle& h1, const Handle& h2) {
            return h1->getAttentionValue()->getSTI() > h2->getAttentionValue()->getSTI();
            }))->getAttentionValue()->getSTI();

    if (minSTISeen > maxSTISeen) {
        minSTISeen = maxSTISeen;
    }

    _as->update_max_STI(maxSTISeen);
    _as->update_min_STI(minSTISeen);

    logger().fine("AVChanged: fundsSTI = %d, old_av: %d, new_av: %d",
                   fundsSTI.load(), old_av->getSTI(), new_av->getSTI());

    // Check if the atom crossed into or out of the AttentionalFocus
    // and notify any interested parties
    if (old_av->getSTI() < getAttentionalFocusBoundary() and
        new_av->getSTI() >= getAttentionalFocusBoundary())
    {
        AFCHSigl& afch = AddAFSignal();
        afch(h, old_av, new_av);
    }
    else if (new_av->getSTI() < getAttentionalFocusBoundary() and
             old_av->getSTI() >= getAttentionalFocusBoundary())
    {
        AFCHSigl& afch = RemoveAFSignal();
        afch(h, old_av, new_av);
    }
}

void AttentionBank::stimulate(Handle& h, double stimulus)
{
    // XXX This is not protected and made atomic in any way ...
    // If two different threads stiumlate the same atom at the same
    // time, then the calculations could get wonky. Does it matter?
    AttentionValue::sti_t sti   = h->getAttentionValue()->getSTI();
    AttentionValue::lti_t lti   = h->getAttentionValue()->getLTI();
    AttentionValue::vlti_t vlti = h->getAttentionValue()->getVLTI();

    AttentionValue::sti_t stiWage = calculateSTIWage() * stimulus;
    AttentionValue::lti_t ltiWage = calculateLTIWage() * stimulus;

    AttentionValuePtr new_av = createAV(sti + stiWage, lti + ltiWage, vlti);
    h->setAttentionValue(new_av);
}

void AttentionBank::updateMaxSTI(AttentionValue::sti_t m)
{
    std::lock_guard<std::mutex> lock(_lock_maxSTI);
    _maxSTI.update(m);
}

void AttentionBank::updateMinSTI(AttentionValue::sti_t m)
{
    std::lock_guard<std::mutex> lock(_lock_minSTI);
    _minSTI.update(m);
}

AttentionValue::sti_t AttentionBank::getMaxSTI(bool average) const
{
    std::lock_guard<std::mutex> lock(_lock_maxSTI);
    if (average) {
        return (AttentionValue::sti_t) _maxSTI.recent;
    } else {
        return _maxSTI.val;
    }
}

AttentionValue::sti_t AttentionBank::getMinSTI(bool average) const
{'fraction_non_alphanumeric': 0.11918173732582271, 'fraction_numerical': 0.010672991402312482, 'mean_word_length': 3.620890410958904, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 101, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5305544', 'n_tokens_mistral': 4606, 'n_tokens_neox': 4398, 'n_words': 1044}