Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storing PLN formulas in the AtomSpace #2015

Merged
merged 28 commits into from
Jan 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8f88508
Add StrengthOf, ConfidenceOf link types.
linas Jan 26, 2019
5e22c73
Enable multiple library constructors
linas Jan 26, 2019
3af45f6
Convert FloatValues into TV's
linas Jan 26, 2019
db3ceee
Also evaluate outside of the EvluationLink
linas Jan 26, 2019
3ec2042
Allow numbers as well.
linas Jan 26, 2019
b984b1a
Allow Lambda for the forumlas.
linas Jan 26, 2019
740c426
Enable just ordinary formulas.
linas Jan 26, 2019
1edeef7
Add documentation
linas Jan 26, 2019
a77d373
More documentatiion
linas Jan 26, 2019
10c7c2d
Bug-fix handling of variables
linas Jan 27, 2019
6c6dd2e
Merge branch 'master' into vc
linas Jan 27, 2019
7b94317
Additional examples
linas Jan 27, 2019
d62caf8
Bug fix for PutLink
linas Jan 27, 2019
70ef6c8
One last bugfix for the demo
linas Jan 27, 2019
533f026
Expand the demo some more
linas Jan 27, 2019
5a509b8
Another bugfix
linas Jan 28, 2019
8ac829e
Start creating a unit test.
linas Jan 28, 2019
815f696
Extened the unit test
linas Jan 28, 2019
11c0ae9
Continue work on new unit test
linas Jan 28, 2019
87911ad
Expand unit test
linas Jan 28, 2019
d39e809
Last of the unit test expansion
linas Jan 28, 2019
f33ee7c
Allow DefinedPredicate to work, also
linas Jan 28, 2019
b92dc2e
Expand unit test for DefinedPrediate
linas Jan 28, 2019
ebb2281
Move a big block of code
linas Jan 28, 2019
01b4698
Cleanup for readability
linas Jan 28, 2019
37b090a
Use the correct exception type.
linas Jan 28, 2019
913d2ec
Wrap up the silent exceptions.
linas Jan 28, 2019
a552cff
The exceptions here will never be silent.
linas Jan 28, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 182 additions & 0 deletions examples/atomspace/formulas.scm
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
;
; formulas.scm -- Declaring formulas that compute truth values.
;
; The rule engine, PLN and other subsystems need to be able to compute
; and alter truth values. If those formulas are known a-priori, then
; thay can be hard-coded into GroundedPredicateNodes. However, it is
; possible that those formulas are not yet known: that they will be
; learned using some learning algorithm, for example, MOSES, or maybe
; the Pattern Miner, or some neural network.
;
; In this case, the formulas need to be placed where they can be
; accessed during computation: in the AtomSpace. The example below
; shows how formulas can be declared in the AtomSpace, but in such a
; way that they can also be evaluated to yeild an actual truth value,
; which is then attached to some Atom.
;
(use-modules (opencog) (opencog exec))

; The StrengthOfLink returns a single floating-point number,
; the strength of a TruthValue.
(Concept "A" (stv 0.8 1.0))
(cog-execute! (StrengthOf (Concept "A")))

; The demo needs at least one more Atom.
(Concept "B" (stv 0.6 0.9))

; Multiply the strength of the TV's of two atoms.
(cog-execute!
(Times (StrengthOf (Concept "A")) (StrengthOf (Concept "B"))))

; Create a SimpleTruthValue with a non-trivial formula:
; It will be the TV := (1-sA*sB, cA*cB) where sA and sB are strenghts
; and cA, cB are confidence values. The PredicateFormulaLink assembles
; two floating-point values, and create a SimpleTruthValue out of them.
;
(cog-evaluate!
(PredicateFormula
(Minus
(Number 1)
(Times (StrengthOf (Concept "A")) (StrengthOf (Concept "B"))))
(Times (ConfidenceOf (Concept "A")) (ConfidenceOf (Concept "B")))))

; The values do not need to be formulas; they can be hard-coded numbers.
(cog-evaluate!
(PredicateFormula (Number 0.7) (Number 0.314)))

; The below computes a truth value, and attaches it to the
; EvaluationLink. Let's demo this in three parts: first define it,
; then evaluate it, then look at it.
;
(define my-ev-link
(Evaluation
(PredicateFormula (Number 0.7) (Number 0.314))
(List
(Concept "A")
(Concept "B"))))

; Evaluate ...
(cog-evaluate! my-ev-link)

; Print.
(display my-ev-link)

; More typically, one wishes to have a formula in the abstract,
; with variables in it, so that one can apply it in any one of
; a number of different situations. In the below, the variables
; are automatically reduced with the Atoms in the ListLink, and
; then the formula is evaluated to obtain a TruthValue.
(cog-evaluate!
(Evaluation
; Compute TV = (1-sA*sB, cA*cB)
(PredicateFormula
(Minus
(Number 1)
(Times
(StrengthOf (Variable "$X"))
(StrengthOf (Variable "$Y"))))
(Times
(ConfidenceOf (Variable "$X"))
(ConfidenceOf (Variable "$Y"))))
(List
(Concept "A")
(Concept "B"))))

; Optionally, you can wrap formulas with LambdaLinks. This doesn't
; really change anything; formulas work fine without LambdaLinks.
(cog-evaluate!
(Evaluation
; Compute TV = (1-sA*sB, cA*cB)
(PredicateFormula
(Lambda (Minus
(Number 1)
(Times
(StrengthOf (Variable "$X"))
(StrengthOf (Variable "$Y")))))
(Lambda (Times
(ConfidenceOf (Variable "$X"))
(ConfidenceOf (Variable "$Y")))))
(List
(Concept "A")
(Concept "B"))))


; The PedicateFormulaLink behaves just like any other algebraic
; expression with VariableNodes in it. When executed, it might
; reduce a bit, but that is all.
(cog-execute!
(PredicateFormula
(Plus (Number 41)
(Minus
(Number 1)
(Times
(StrengthOf (Variable "$VA"))
(StrengthOf (Variable "$VB")))))
(Times
(ConfidenceOf (Variable "$VA"))
(ConfidenceOf (Variable "$VB")))))

; Beta-reducation works as normal. The below will create an
; EvaluationLink with ConceptNode A and B in it, and will set the
; truth value according to the formula.
(define the-put-result
(cog-execute!
(PutLink
(VariableList (Variable "$VA") (Variable "$VB"))
(Evaluation
; Compute TV = (1-sA*sB, cA*cB)
(PredicateFormula
(Minus
(Number 1)
(Times
(StrengthOf (Variable "$VA"))
(StrengthOf (Variable "$VB"))))
(Times
(ConfidenceOf (Variable "$VA"))
(ConfidenceOf (Variable "$VB"))))
(List
(Variable "$VA") (Variable "$VB")))
(Set (List (Concept "A") (Concept "B"))))))

; The scheme variable `the-put-result` contains a SetLink with the
; result in it. Lets unwrap it, so that `evelnk` is just the
; EvaluationLink. And tehn we play a little trick.
(define evelnk (cog-outgoing-atom the-put-result 0))

; Change the truth value on the two concept nodes ...
(Concept "A" (stv 0.3 0.5))
(Concept "B" (stv 0.4 0.5))

; Re-evaluate the EvaluationLink. Note the TV has been updated!
(cog-evaluate! evelnk)

; Do it again, for good luck!
(Concept "A" (stv 0.1 0.99))
(Concept "B" (stv 0.1 0.99))

; Re-evaluate the EvaluationLink. The TV is again recomputed!
(cog-evaluate! evelnk)

; One can also use DefinedPredicates, to give the formula a name.
(DefineLink
(DefinedPredicate "has a reddish color")
(PredicateFormula
(Minus
(Number 1)
(Times
(StrengthOf (Variable "$X"))
(StrengthOf (Variable "$Y"))))
(Times
(ConfidenceOf (Variable "$X"))
(ConfidenceOf (Variable "$Y")))))

(Concept "A" (stv 0.9 0.98))
(Concept "B" (stv 0.9 0.98))

; The will cause the formula to evaluate.
(cog-evaluate!
(Evaluation
(DefinedPredicate "has a reddish color")
(List
(Concept "A")
(Concept "B"))))
13 changes: 12 additions & 1 deletion opencog/atoms/atom_types/atom_types.script
Original file line number Diff line number Diff line change
Expand Up @@ -571,9 +571,20 @@ FUNCTION_LINK <- FREE_LINK
EXECUTION_OUTPUT_LINK <- FUNCTION_LINK

// Return the indicated value on the indicated atom.
// XXX It doesn't *always* return numbers ...
// XXX It's marked as "NUMERIC_OUTPUT, but doesn't *always* return
// numbers ... Probably should have a FLOAT_VALUE_OF_LINK to fix this.
// Ignore this issue for now ...
VALUE_OF_LINK <- FUNCTION_LINK,NUMERIC_OUTPUT_LINK
TRUTH_VALUE_OF_LINK <- VALUE_OF_LINK
STRENGTH_OF_LINK <- VALUE_OF_LINK
CONFIDENCE_OF_LINK <- VALUE_OF_LINK

// The opposite of the above: given something that evaluates to a
// FloatValue, return a TruthValue. Kind-of-like
// GROUNDED_PREDICATE_NODE, but holding the forumla in the atomspace.
// This is not really needed, but will make the transition process
// smoother.
PREDICATE_FORMULA_LINK <- EVALUATABLE_LINK

// Basic arithmetic operators
FOLD_LINK <- FUNCTION_LINK
Expand Down
9 changes: 7 additions & 2 deletions opencog/atoms/base/ClassServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ class ClassServer

ClassServer& classserver();

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)

#define DEFINE_LINK_FACTORY(CNAME,CTYPE) \
\
Handle CNAME::factory(const Handle& base) \
Expand All @@ -123,7 +126,8 @@ Handle CNAME::factory(const Handle& base) \
} \
\
/* This runs when the shared lib is loaded. */ \
static __attribute__ ((constructor)) void init(void) \
static __attribute__ ((constructor)) void \
TOKENPASTE2(init, __COUNTER__)(void) \
{ \
classserver().addFactory(CTYPE, &CNAME::factory); \
}
Expand All @@ -138,7 +142,8 @@ Handle CNAME::factory(const Handle& base) \
} \
\
/* This runs when the shared lib is loaded. */ \
static __attribute__ ((constructor)) void init(void) \
static __attribute__ ((constructor)) void \
TOKENPASTE2(init, __COUNTER__)(void) \
{ \
classserver().addFactory(CTYPE, &CNAME::factory); \
}
Expand Down
2 changes: 2 additions & 0 deletions opencog/atoms/core/PrenexLink.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ Handle PrenexLink::reassemble(Type prenex,
// prenexed. Check for PutLink to avoid infinite recursion.
if (PUT_LINK != prenex and not final_varlist.empty() and
nameserver().isA(prenex, PRENEX_LINK))
{
return Handle(createLink(prenex, vdecl, newbod));
}

// Otherwise, we are done with the beta-reduction.
return newbod;
Expand Down
96 changes: 96 additions & 0 deletions opencog/atoms/core/TruthValueOfLink.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,102 @@ ValuePtr TruthValueOfLink::execute() const
return ValueCast(_outgoing[0]->getTruthValue());
}

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

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

StrengthOfLink::StrengthOfLink(const Link &l)
: ValueOfLink(l)
{
// Type must be as expected
Type tscope = l.get_type();
if (not nameserver().isA(tscope, STRENGTH_OF_LINK))
{
const std::string& tname = nameserver().getTypeName(tscope);
throw InvalidParamException(TRACE_INFO,
"Expecting an StrengthOfLink, got %s", tname.c_str());
}
}

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

/// When executed, this will return the Strengths of all of the
/// atoms in the outgoing set.
ValuePtr StrengthOfLink::execute() const
{
std::vector<double> strengths;

for (const Handle& h : _outgoing)
{
// Cannot take the strength of an ungrounded variable.
Type t = h->get_type();
if (VARIABLE_NODE == t or GLOB_NODE == t)
return get_handle();

strengths.push_back(h->getTruthValue()->get_mean());
}

return createFloatValue(strengths);
}

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

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

ConfidenceOfLink::ConfidenceOfLink(const Link &l)
: ValueOfLink(l)
{
// Type must be as expected
Type tscope = l.get_type();
if (not nameserver().isA(tscope, CONFIDENCE_OF_LINK))
{
const std::string& tname = nameserver().getTypeName(tscope);
throw InvalidParamException(TRACE_INFO,
"Expecting an ConfidenceOfLink, got %s", tname.c_str());
}
}

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

/// When executed, this will return the Confidences of all of the
/// atoms in the outgoing set.
ValuePtr ConfidenceOfLink::execute() const
{
std::vector<double> confids;

for (const Handle& h : _outgoing)
{
// Cannot take the confidence of an ungrounded variable.
Type t = h->get_type();
if (VARIABLE_NODE == t or GLOB_NODE == t)
return get_handle();

confids.push_back(h->getTruthValue()->get_confidence());
}

return createFloatValue(confids);
}

DEFINE_LINK_FACTORY(TruthValueOfLink, TRUTH_VALUE_OF_LINK)
DEFINE_LINK_FACTORY(StrengthOfLink, STRENGTH_OF_LINK)
DEFINE_LINK_FACTORY(ConfidenceOfLink, CONFIDENCE_OF_LINK)

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