Skip to content

Commit

Permalink
Merge pull request #3021 from linas/incoming-set-of
Browse files Browse the repository at this point in the history
Provide an IncomingSetOfLink
  • Loading branch information
linas authored Dec 16, 2022
2 parents eee7a61 + 4154254 commit 80bbde5
Show file tree
Hide file tree
Showing 15 changed files with 418 additions and 32 deletions.
50 changes: 32 additions & 18 deletions opencog/atoms/atom_types/atom_types.script
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,12 @@ ELEMENT_OF_LINK <- FUNCTION_LINK,NUMERIC_OUTPUT_LINK,BOOLEAN_OUTPUT_LINK
// TODO: perhaps create shift-left, shift-right and truncate operators?
// Someday, they will be needed; just not yet, I guess.

// Convert a FloatValue to a NumberNode. The argument is presumed to
// be some executable link that, when executed, returns a FloatValue
// (or some derived type, e.g. some stream) and now we want an
// actual NumberNode.
NUMBER_OF_LINK <- FUNCTION_LINK,NUMERIC_OUTPUT_LINK

// Return the current time.
TIME_LINK <- FUNCTION_LINK,NUMERIC_OUTPUT_LINK

Expand All @@ -960,13 +966,25 @@ COUNT_OF_LINK <- FLOAT_VALUE_OF_LINK
// or a Value, return the length of the underlying vector.
SIZE_OF_LINK <- FLOAT_VALUE_OF_LINK

// Inverse of the above; convert a FloatValue to a NumberNode
NUMBER_OF_LINK <- FUNCTION_LINK,NUMERIC_OUTPUT_LINK

// Return the type of the wrapped Atom
TYPE_OF_LINK <- VALUE_OF_LINK

// Like the above, but this returns a promise to return a Value
// Grab an IncomingSet of an Atom, and return it as a LinkValue.
INCOMING_OF_LINK <- VALUE_OF_LINK

// Convert a LinkValue to a SetLink. The argument is presumed to
// be some executable link that, when executed, returns a LinkValue
// (or some derived type, e.g. a QueueValue) and now we want an
// actual set.
COLLECTION_OF_LINK <- FUNCTION_LINK,COLLECTION_LINK

// Opposite of the ValueOfLink; attach a Value to an Atom.
// Verb: "to set", and not noun "a set (collection)"
SET_VALUE_LINK <- FUNCTION_LINK
SET_TV_LINK <- SET_VALUE_LINK,EVALUATABLE_LINK "SetTVLink"

// -----------
// Similar to ValueOfLink, but this returns a promise to return a Value
// sometime in the future. This is accomplished by returning a either
// a FutureStream or a FormulaStream when executed. This stream will
// then cough up the actual Value later on, when interrogated. Used to
Expand All @@ -992,9 +1010,16 @@ PROMISE_PREDICATE_LINK <- EVALUATABLE_LINK, PROMISE_LINK
// the variables.
FORMULA_PREDICATE_LINK <- SCOPE_LINK,EVALUATABLE_LINK

// Opposite of the above; attach a Value to an Atom.
SET_VALUE_LINK <- FUNCTION_LINK
SET_TV_LINK <- SET_VALUE_LINK,EVALUATABLE_LINK "SetTVLink"
// FilterLink was called MapLink (but this name was wrong) or
// FilterMapLink or UnPutLink. UnPut, because it undoes a beta-
// reduction, by extracting Values for a given set of variables.
// In many ways, it resembles a GetLink, except that it searches
// only its argument list, instead of the entire AtomSpace.
//
// MapLink, because it resembles the standard functional-programming
// concept of "map", except that it discard unmatchable entries, so
// it's really FilterMapLink. That's a mouthful, so we go with FilterLink.
FILTER_LINK <- FUNCTION_LINK

// --------------------
// Other kinds of functions.
Expand All @@ -1019,17 +1044,6 @@ COND_LINK <- FUNCTION_LINK
// Sleep link pauses execution for the indicated number of seconds.
SLEEP_LINK <- FUNCTION_LINK,NUMERIC_INPUT_LINK

// FilterLink was called MapLink (but this name was wrong) or
// FilterMapLink or UnPutLink. UnPut, because it undoes a beta-
// reduction, by extracting Values for a given set of variables.
// In many ways, it resembles a GetLink, except that it searches
// only its argument list, instead of the entire AtomSpace.
//
// MapLink, because it resembles the standard functional-programming
// concept of "map", except that it discard unmatchable entries, so
// it's really FilterMapLink. That's a mouthful, so we go with FilterLink.
FILTER_LINK <- FUNCTION_LINK

// ==============================================================
// Procedure and schema nodes.
//
Expand Down
4 changes: 4 additions & 0 deletions opencog/atoms/flow/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR})

ADD_LIBRARY (atomflow
CollectionOfLink.cc
FilterLink.cc
FormulaPredicateLink.cc
IncomingOfLink.cc
NumberOfLink.cc
PromiseLink.cc
SetTVLink.cc
Expand All @@ -30,8 +32,10 @@ INSTALL (TARGETS atomflow EXPORT AtomSpaceTargets
)

INSTALL (FILES
CollectionOfLink.h
FilterLink.h
FormulaPredicateLink.h
IncomingOfLink.h
NumberOfLink.h
PromiseLink.h
SetTVLink.h
Expand Down
84 changes: 84 additions & 0 deletions opencog/atoms/flow/CollectionOfLink.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* CollectionOfLink.cc
*
* Copyright (C) 2015, 2022 Linas Vepstas
*
* Author: Linas Vepstas <[email protected]> January 2009
*
* 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 <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/value/LinkValue.h>

#include "CollectionOfLink.h"

using namespace opencog;

CollectionOfLink::CollectionOfLink(const HandleSeq&& oset, Type t)
: FunctionLink(std::move(oset), t)
{
if (not nameserver().isA(t, COLLECTION_OF_LINK))
{
const std::string& tname = nameserver().getTypeName(t);
throw InvalidParamException(TRACE_INFO,
"Expecting an CollectionOfLink, got %s", tname.c_str());
}

if (1 != _outgoing.size())
throw InvalidParamException(TRACE_INFO,
"CollectionOfLink expects one args");
}

// ---------------------------------------------------------------

/// Return a SetLink vector.
ValuePtr CollectionOfLink::execute(AtomSpace* as, bool silent)
{
// If the given Atom is executable, then execute it.
// In effectively all cases, we expect it to be executable!
Handle base(_outgoing[0]);
if (not base->is_executable())
{
// Consume quotes
Type bt = base->get_type();
if (DONT_EXEC_LINK != bt and LOCAL_QUOTE_LINK != bt)
return as->add_link(SET_LINK, base);

return as->add_link(SET_LINK, base->getOutgoingAtom(0));
}

ValuePtr vp = base->execute(as, silent);
if (vp->is_atom())
return as->add_link(SET_LINK, HandleCast(vp));

// If its a FloatValue, we could maybe return a NumberNode??
// so be linke NumberOfLink ???
// if (vp->is_type(FLOAT_VALUE))

if (not vp->is_type(LINK_VALUE))
throw InvalidParamException(TRACE_INFO,
"CollectionOfLink expects a LinkValue, got %s",
vp->to_string().c_str());

LinkValuePtr lvp = LinkValueCast(vp);
HandleSeq hs = lvp->to_handle_seq();
return as->add_link(SET_LINK, std::move(hs));
}

DEFINE_LINK_FACTORY(CollectionOfLink, COLLECTION_OF_LINK)

/* ===================== END OF FILE ===================== */
58 changes: 58 additions & 0 deletions opencog/atoms/flow/CollectionOfLink.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* opencog/atoms/flow/CollectionOfLink.h
*
* Copyright (C) 2015, 2022 Linas Vepstas
* All Rights Reserved
*
* 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.
*/

#ifndef _OPENCOG_COLLECTION_OF_LINK_H
#define _OPENCOG_COLLECTION_OF_LINK_H

#include <opencog/atoms/core/FunctionLink.h>

namespace opencog
{
/** \addtogroup grp_atomspace
* @{
*/

/// The CollectionOfLink returns a SetLink holding the contents of
/// a LinkValue that resulted from the execution of whatever was
/// wrapped. Thus, if a pipeline produces a LinkValue, and you
/// wanted a SetLink instead, just wrap it with this.
///
class CollectionOfLink : public FunctionLink
{
public:
CollectionOfLink(const HandleSeq&&, Type = COLLECTION_OF_LINK);
CollectionOfLink(const CollectionOfLink&) = delete;
CollectionOfLink& operator=(const CollectionOfLink&) = delete;

// Return a SetLink
virtual ValuePtr execute(AtomSpace*, bool);

static Handle factory(const Handle&);
};

LINK_PTR_DECL(CollectionOfLink)
#define createCollectionOfLink CREATE_DECL(CollectionOfLink)

/** @}*/
}

#endif // _OPENCOG_COLLECTION_OF_LINK_H
9 changes: 5 additions & 4 deletions opencog/atoms/flow/FilterLink.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include <opencog/atoms/core/VariableSet.h>
#include <opencog/atoms/rule/RuleLink.h>
#include <opencog/atoms/value/LinkValue.h>
#include <opencog/atoms/value/VoidValue.h>

#include "FilterLink.h"

Expand Down Expand Up @@ -417,7 +416,7 @@ ValuePtr FilterLink::execute(AtomSpace* as, bool silent)

// If it is some other Value, we have no clue what to do with it.
if (not vex->is_atom())
return createVoidValue();
return createLinkValue();

// Fall through, if execution provided some Atom.
valh = HandleCast(vex);
Expand Down Expand Up @@ -445,10 +444,12 @@ ValuePtr FilterLink::execute(AtomSpace* as, bool silent)

// Avoid returning null pointer!
// If we were given Atoms, assum the caller wants Atoms back.
// Otherwise, avoid polution and return VoidValue.
// Otherwise, avoid pollution and return VoidValue.
// Actually, return an empty LinkValue; this allows downstream
// pipelines to handle it just like any other LinkValue return.
if (valh->is_atom())
return as->add_link(SET_LINK);
return createVoidValue();
return createLinkValue();
}

DEFINE_LINK_FACTORY(FilterLink, FILTER_LINK)
Expand Down
90 changes: 90 additions & 0 deletions opencog/atoms/flow/IncomingOfLink.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* IncomingOfLink.cc
*
* Copyright (C) 2015, 2022 Linas Vepstas
*
* Author: Linas Vepstas <[email protected]> January 2009
*
* 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 <opencog/atoms/core/TypeNode.h>
#include <opencog/atoms/value/LinkValue.h>

#include "IncomingOfLink.h"

using namespace opencog;

IncomingOfLink::IncomingOfLink(const HandleSeq&& oset, Type t)
: FunctionLink(std::move(oset), t)
{
if (not nameserver().isA(t, INCOMING_OF_LINK))
{
const std::string& tname = nameserver().getTypeName(t);
throw InvalidParamException(TRACE_INFO,
"Expecting an IncomingOfLink, got %s", tname.c_str());
}

size_t sz = _outgoing.size();

if (1 != sz and 2 != sz)
throw InvalidParamException(TRACE_INFO,
"IncomingOfLink expects one or two args, got %lu", sz);
}

// ---------------------------------------------------------------

/// Return a LinkValue vector.
ValuePtr IncomingOfLink::execute(AtomSpace* as, bool silent)
{
// If the given Atom is executable, then execute it.
Handle base(_outgoing[0]);
if (base->is_executable())
{
base = HandleCast(base->execute(as, silent));
if (nullptr == base) return createLinkValue();
}
else
{
// consume quotes
Type bt = base->get_type();
if (DONT_EXEC_LINK == bt or LOCAL_QUOTE_LINK == bt)
base = base->getOutgoingAtom(0);
}

// Simple case. Get IncomingSet.
if (1 == _outgoing.size())
return createLinkValue(base->getIncomingSet());

// Get incoming set by type.
Handle tnode(_outgoing[1]);
if (tnode->is_executable())
tnode = HandleCast(tnode->execute(as, silent));

if (not tnode->is_type(TYPE_NODE))
throw RuntimeException(TRACE_INFO,
"IncomingOfLink expects a type; got %s",
tnode->to_string().c_str());

TypeNodePtr tnp = TypeNodeCast(tnode);
Type intype = tnp->get_kind();
HandleSeq iset(base->getIncomingSetByType(intype));
return createLinkValue(iset);
}

DEFINE_LINK_FACTORY(IncomingOfLink, INCOMING_OF_LINK)

/* ===================== END OF FILE ===================== */
Loading

0 comments on commit 80bbde5

Please sign in to comment.