In the pattern matcher, virtual links are links that behave as if they exist, but cannot be found as real links in the AtomSpace. Virtual links are useful for implementing relations that have a very large domain, and would require far too many real atoms to fully describe. An example of this would be a virtual atom implementing a greater-than relation (the GreaterThanLink) between numbers: it would be impossible to stuff the the atom space with real atoms for every possible pair of numbers.
Virtual links come in two forms: the black-box link, which is an EvaluationLink with a GroundedPredicateNode inside of it, and the clear-box form, examples of which are the GreaterThanLink, EqualLink, AbsentLink and DeleteLink. The distinction between black-box and clear-box is that it is "obvious" what the clear-box links do: one can tell from thier name. By contrast, the black-box links depend on the executation of some scheme or python snippet, which could do anything, and about which it is impossible to reason about.
In either case, because virtual links can be evaluated to a true/false value, they can be combined to form arbitrarily complicated boolean expressions, by making use of the AndLink, OrLink and NotLink.
Black-box virtual links are of the form:
EvaluationLink GroundedPredicateNode "some_predicate_function" ListLink VariableNode $X ;;; or some constant node VariableNode $Y ;;; or some constant node ... ;;; any number of args VariableNode $W
The virtual atom is deemed "to exist" if the function "some_predicate_function" evaluates to true; else, the atom does not exist. Evaluation is done in the pattern matcher, during grounding. The actual evaluation is done in C++ code: see /opencog/execution/EvaluationLink.h for the implementation.
As usual, "some_compare_function" can be any py: or scm: function. (At this time, the py: style URL's are broken, so reallly only the scm: URL's work). There are two hard-coded functions:
- c++:greater: which compares the numeric value of two NumberNodes, and accepts if the first is greater than the second.
- c++:exclusive: which compares a set of N atoms, and accepts if they are all different.
Caution: In order to support virtual links, the pattern matcher must first explore all possible groundings of all of the real links in a pattern. This may result in a combinatoric explosion, depending on the pattern. Thus, in general, patterns with virtual links in them will be matched more slowly than patterns consisting entirely of real atoms; and, when poorly designed, the slowdown could be large.
The following performs a numeric greater-than check:
EvaluationLink GroundedPredicateNode "c++:greater" ListLink VariableNode $X NumberNode "42"
The above virtual link "exists" when $X is a NumberNode that is larger than 42, else it does not. The GreaterThanUTest dataset shows a working example of the above. It declares four people with different amounts of wealth, and then uses a BindLink to find everyone wealthier than a given person.
The above example only compares two things; however, an N-ary relation is possible. So, for example one might want to have a comparison that depends on the context, or that depends on the specific predicate. For example, one might have data:
EvaluationLink PredicateNode "richness" ListLink ConcpetNode "Bill Gates" NumberNode "456123789"
EvaluationLink PredicateNode "political astuteness" ListLink ConcpetNode "Bill Gates" ConceptNode "medium-high"
and suppose one wanted to compare someone's political astuteness. One might then write
EvaluationLink GroundedPredicateNode "generic_predicate_based_compare_function" ListLink PredicateNode "political astuteness" VariableNode $X ConceptNode "low"
Its assumed that "generic_predicate_based_compare_function" would then use the PredicateNode in some way, when comparing $X to "low". Here, "generic_predicate_based_compare_function" is just an example: this function doesn't actually exist at this time, and if you wanted such a function, you would need to create it.
But, perhaps, its not clear if richness or political astuteness should be compared. One might then try:
EvaluationLink GroundedPredicateNode "generic_predicate_based_compare_function" ListLink VariableNode $pred-name ;; some other clause fixes this VariableNode $X VariableNode $Y
This would allow comparisons to be done on objects, when it is not know ahead of time what kind of comparison should be done.
One can also search for expressions that contain virtual links, without actually evaluating them, by escaping them with a QuoteLink.