Skip to content

Commit

Permalink
Revert the cartesian-any idea.
Browse files Browse the repository at this point in the history
Now that the issue is clearly understood, we can do it correctly.
See #1351 for details.
  • Loading branch information
linas committed Nov 4, 2022
2 parents c819037 + 3e95bb6 commit fa0e613
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 82 deletions.
30 changes: 9 additions & 21 deletions link-grammar/dict-atomese/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,11 +294,16 @@ LG disjuncts must be associated with Atomese disjuncts, so that when
LG produces a parse, we can know which Atomese disjunct was used in
that parse (and thus increment the use count on it).

This is currently done in several steps. First, an `LgConnNode`
is associated to a germ-connector pair, ass follows:
This is accomplished by associating the LG Link type to the word or
word-class pair from which it was made. For the case of plain words,
this pairing can be directly reconstructed from the parse. For the
case of WordClasses, it is impossible to guess, and so it is explicitly
provided.

The association is:
```
(Evaluation
(Predicate "*-LG connector string-*")
(Predicate "*-LG link string-*")
(LgLinkNode ...) ; The name is the LG link type.
(List
(Word ...) ; The left word (from germ or connector)
Expand All @@ -308,23 +313,6 @@ In the above, the two Words/WordClasses appear as germ-connector or
connector-germ in the Atomese disjuncts. See examples in `lg-atomese`
that show how above can be accessed.

The above is enough to recreate an association between LG disjuncts
and Atomese Sections; however, computing this requires some painful
code. Thus, it seems easiest to cache the disjunct string, and attach
it to each Section. It would appear thus:
```
(Evaluation
(Predicate "*-LG disjunct string-*")
(ItemNode "A- & B- & C+")
(Section ...))
```

After an LG parse is performed, the resulting `LgDisjunct` can be
easily converted to a string, that string can be used to search for
the above `ItemNode` and thus find the `Section`. This seems to be
the easiest thing to do, avoiding the need to create complicated
code to convert from `LgDisjunct`s to `Section`s.

* Side note: we need a `get-incoming-by-predicate` function!

### Reproducible Connector Names
Expand All @@ -338,7 +326,7 @@ It might be desirable to be able to have reproducible connector names,
adds considerable new complexity. Is it worth doing?
The following would be needed:

* The `(Predicate "*-LG connector string-*")` described above need to be
* The `(Predicate "*-LG link string-*")` described above need to be
fetched. This can add significant network overhead.

* The StorageNode needs to queried for a block of unused link names
Expand Down
6 changes: 3 additions & 3 deletions link-grammar/dict-atomese/local-as.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ class Local
const char* node_str; // (StorageNode \"foo://bar/baz\")
AtomSpacePtr asp;
StorageNodePtr stnp;
Handle linkp; // (Predicate "*-LG connector string-*")
// Handle djp; // (Predicate "*-LG disjunct string-*")
Handle linkp; // (Predicate "*-LG link string-*")
Handle prk; // (Predicate "*-fetched-pair-*")

// Sections
Expand Down Expand Up @@ -63,10 +62,11 @@ Exp* make_sect_exprs(Dictionary dict, const Handle& germ);
Exp* make_pair_exprs(Dictionary dict, const Handle& germ);
Exp* make_cart_pairs(Dictionary dict, const Handle& germ, int arity, bool any);
Exp* make_any_exprs(Dictionary dict);
Exp* make_cart_any(Dictionary dict, int arity);

void or_enchain(Dictionary, Exp* &orhead, Exp*);
void and_enchain_left(Dictionary, Exp* &orhead, Exp* &ortail, Exp*);
void and_enchain_right(Dictionary, Exp* &orhead, Exp* &ortail, Exp*);

std::string cached_linkname(Local*, const Handle& pair);

//----
11 changes: 2 additions & 9 deletions link-grammar/dict-atomese/lookup-atomese.cc
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,7 @@ bool as_open(Dictionary dict)

// Create the connector predicate.
// This will be used to cache LG connector strings.
local->linkp = local->asp->add_node(PREDICATE_NODE,
"*-LG connector string-*");

// local->djp = local->asp->add_node(PREDICATE_NODE,
// "*-LG disjunct string-*");
local->linkp = local->asp->add_node(PREDICATE_NODE, "*-LG link string-*");

// Internal-use only. Do we have this pair yet?
local->prk = local->asp->add_node(PREDICATE_NODE, "*-fetched-pair-*");
Expand Down Expand Up @@ -427,10 +423,7 @@ Dict_node * as_lookup_list(Dictionary dict, const char *s)

if (local->enable_unknown_word and 0 == strcmp(s, "<UNKNOWN-WORD>"))
{
// XXX Note the hard-coded 6. I do not understand why 2 is not
// enough. See issue #1351 for a discussion.
// https://github.com/opencog/link-grammar/issues/1351
Exp* exp = make_cart_any(dict, 6);
Exp* exp = make_any_exprs(dict);
return make_dn(dict, exp, ssc);
}

Expand Down
17 changes: 5 additions & 12 deletions link-grammar/dict-atomese/utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ class reverse {
// ===============================================================

#if 0
// Unused just right now.

// Currently unused. Left over from an earlier attempt to label
// disjuncts.

// This is a minimalist version of `lg_exp_stringify()` because
// we want the string, without the costs on it. We also know that
Expand Down Expand Up @@ -73,11 +75,11 @@ static std::string prt_andex(Exp* e)

else if (OR_type == e->type)
{
str += "{";
str += "(";
Exp* con = e->operand_first->operand_next;
str += con->condesc->string;

This comment has been minimized.

Copy link
@ampli

ampli Nov 4, 2022

Member

You may need to prepend @ if con->multi.

This comment has been minimized.

Copy link
@linas

linas Nov 7, 2022

Author Member

Thanks, Yes. This was not meant as a public function, but as an index into a table. But anyway It's dead code, I just removed it.

str += con->dir;
str += "}";
str += ")";
}
else if (AND_type == e->type)
{
Expand All @@ -94,15 +96,6 @@ static std::string prt_andex(Exp* e)
return str;
}

// XXX Unused right now. What was the plan, here?
static void cache_disjunct_string(Local* local,
const Handle& sect, Exp* andex)
{
local->asp->add_link(
EVALUATION_LINK, local->djp,
createNode(ITEM_NODE, prt_andex(andex)),
sect);
}
#endif

#endif /* HAVE_ATOMESE */
51 changes: 14 additions & 37 deletions link-grammar/dict-atomese/word-pairs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,17 @@ Exp* make_cart_pairs(Dictionary dict, const Handle& germ,

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

/// Create exprs that are cartesian products of ANY links. The
/// corresponding disjuncts will have `arity` number of connectors.
/// If these are used all by themselves, the resulting parses will
/// be random planar graphs; i.e. will be equivalent to the `any`
/// language parses.
/// Create an expression having the form
/// @ANY- or @ANY+ or (@ANY- & @ANY+)
/// These are multi-connectors. The cost on each connector is the
/// default any-cost from the configuration. Note that the use of
/// this expression will result in random planar parses between the
/// words having this expression. i.e. it will be the same as using
/// the `any` language to create random planar pares.
///
/// FYI, there is a minor issue for cost-accounting on multi-connectors;
/// see https://github.com/opencog/link-grammar/issues/1351 for details.
///
Exp* make_any_exprs(Dictionary dict)
{
// Create a pair of ANY-links that can connect either left or right.
Expand All @@ -238,39 +244,10 @@ Exp* make_any_exprs(Dictionary dict)

Exp* any = make_or_node(dict->Exp_pool, aneg, apos);

return any;
}

/// Much like make_part_pairs, except that this duplicates the
/// ANY connector. It creates the expression
/// {@ANY- or @ANY+} and {@ANY- or @ANY+} and ... and {@ANY- or @ANY+}
/// This cartesian allows multiple connectors to participate in loops.
/// However, the behavior is ... sruprising. See
/// https://github.com/opencog/link-grammar/issues/1351
/// for a discussion of what this is all about.
Exp* make_cart_any(Dictionary dict, int arity)
{
if (0 >= arity) return nullptr;

Exp* andhead = nullptr;
Exp* andtail = nullptr;

Exp* any = make_any_exprs(dict);

Exp* optex = make_optional_node(dict->Exp_pool, any);
Exp* andy = make_and_node(dict->Exp_pool, aneg, apos);
or_enchain(dict, any, andy);

// If its 1-dimensional, we are done.
if (1 == arity) return optex;

and_enchain_right(dict, andhead, andtail, optex);

for (int i=1; i< arity; i++)
{
Exp* opt = make_optional_node(dict->Exp_pool, any);
and_enchain_right(dict, andhead, andtail, opt);
}

return andhead;
return any;
}

// ===============================================================
Expand Down

0 comments on commit fa0e613

Please sign in to comment.