OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace / opencog / atoms / reduct / DecimateLink.cc

169 lines · cc ref:
/*
 * opencog/atoms/reduct/DecimateLink.cc
 *
 * Copyright (C) 2020, 2022 Linas Vepstas
 * All Rights Reserved
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

#include <opencog/atoms/atom_types/atom_types.h>
#include <opencog/atoms/base/Link.h>
#include <opencog/atoms/core/NumberNode.h>
#include <opencog/atoms/value/BoolValue.h>
#include <opencog/atoms/value/FloatValue.h>
#include <opencog/atoms/value/LinkValue.h>
#include <opencog/atoms/value/StringValue.h>
#include "DecimateLink.h"

using namespace opencog;

DecimateLink::DecimateLink(const HandleSeq&& oset, Type t)
    : Link(std::move(oset), t)
{
	init();
}

DecimateLink::DecimateLink(const Handle& a, const Handle& b)
    : Link({a, b}, DECIMATE_LINK)
{
	init();
}

void DecimateLink::init(void)
{
	Type tscope = get_type();
	if (not nameserver().isA(tscope, DECIMATE_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a DecimateLink");

	size_t nargs = _outgoing.size();
	if (2 != nargs)
		throw InvalidParamException(TRACE_INFO,
			"DecimateLink expects two arguments, got %s",
			to_string().c_str());
}

// ============================================================

ValuePtr DecimateLink::execute(AtomSpace* as, bool silent)
{
	// The vector we're planning on cutting down.
	ValuePtr vi(_outgoing[1]->execute(as, silent));

	// Lets see what kind of mask this is. We accept three kinds:
	// A BoolValue, NumberNode and FloatValue
	// get_value() causes execution to happen on the arguments
	ValuePtr vm(_outgoing[0]->execute(as, silent));
	Type mtype = vm->get_type();
	if (BOOL_VALUE == mtype)
	{
		BoolValuePtr bvp = BoolValueCast(vm);
		const std::vector<bool>& vmask = bvp->value();
		return do_execute(vmask, vi);
	}

	// XXX FIXME ... both the NumberNode and the FloatValue variations
	// below make a copy of the mask.  Instead of making a copy, create
	// something more efficient/faster. It is, after all, a simple
	// test...

	// Perhaps its a NumberNode?
	if (NUMBER_NODE == mtype)
	{
		NumberNodePtr nnp = NumberNodeCast(vm);
		const std::vector<double>& fmask = nnp->value();
		std::vector<bool> vmask;
		for (double f : fmask)
			vmask.emplace_back(0 < f);
		return do_execute(vmask, vi);
	}

	if (FLOAT_VALUE == mtype)
	{
		FloatValuePtr fvp = FloatValueCast(vm);
		const std::vector<double>& fmask = fvp->value();
		std::vector<bool> vmask;
		for (double f : fmask)
			vmask.emplace_back(0 < f);
		return do_execute(vmask, vi);
	}

	throw SyntaxException(TRACE_INFO, "Mask must be a BoolValue!");
}

ValuePtr DecimateLink::do_execute(const std::vector<bool>& vmask,
                                  const ValuePtr& vi)
{
	Type vitype = vi->get_type();

	// Get the shorter of the two.
	size_t len = std::min(vmask.size(), vi->size());

	// Handle the various value types. Try the most likely ones first.
	// If its a float value, it's a vector.
	if (nameserver().isA(vitype, FLOAT_VALUE))
	{
		const std::vector<double>& dvec(FloatValueCast(vi)->value());
		std::vector<double> chopped;
		for (size_t i=0; i<len; i++)
			if (vmask[i]) chopped.push_back(dvec[i]);
		return createFloatValue(std::move(chopped));
	}

	// A vector of bools.
	if (nameserver().isA(vitype, BOOL_VALUE))
	{
		const std::vector<bool>& bvec(BoolValueCast(vi)->value());
		std::vector<bool> chopped;
		for (size_t i=0; i<len; i++)
			if (vmask[i]) chopped.push_back(bvec[i]);
		return createBoolValue(std::move(chopped));
	}

	// If its a plain number, assume it's a vector.
	if (NUMBER_NODE == vitype)
	{
		const std::vector<double>& dvec(NumberNodeCast(vi)->value());
		std::vector<double> chopped;
		for (size_t i=0; i<len; i++)
			if (vmask[i]) chopped.push_back(dvec[i]);
		return createNumberNode(std::move(chopped));
	}

	// A vector of other things.
	if (nameserver().isA(vitype, LINK_VALUE))
	{
		const std::vector<ValuePtr>& lvec(LinkValueCast(vi)->value());
		std::vector<ValuePtr> chopped;
		for (size_t i=0; i<len; i++)
			if (vmask[i]) chopped.push_back(lvec[i]);
		return createLinkValue(std::move(chopped));
	}

	// A vector of strings
	if (nameserver().isA(vitype, STRING_VALUE))
	{
		const std::vector<std::string>& svec(StringValueCast(vi)->value());
		std::vector<std::string> chopped;
		for (size_t i=0; i<len; i++)
			if (vmask[i]) chopped.push_back(svec[i]);
		return createStringValue(std::move(chopped));
	}

	// A Link.
	if (vi->is_link())
	{
		const HandleSeq& oset(HandleCast(vi)->getOutgoingSet());
		HandleSeq chopped;
		for (size_t i=0; i<len; i++)
			if (vmask[i]) chopped.push_back(oset[i]);
		return createLink(std::move(chopped), vitype);
	}

	// WTF. Should never be reached.
	return get_handle();
}

DEFINE_LINK_FACTORY(DecimateLink, DECIMATE_LINK);

// ============================================================