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

Extra incoming link from derived atomspace #1921

Closed
ngeiswei opened this issue Nov 28, 2018 · 8 comments
Closed

Extra incoming link from derived atomspace #1921

ngeiswei opened this issue Nov 28, 2018 · 8 comments

Comments

@ngeiswei
Copy link
Member

ngeiswei commented Nov 28, 2018

cog-incoming-set returns an extra link from a derived atomspace. I suspect it is a bug. Here's how to reproduce it.

;; Step 1: add atoms in base atomspace
(define base-as (cog-atomspace))
(define A (Concept "A"))
(define B (Concept "B"))
(define C (Concept "C"))
(define AB (Inheritance A B))

(cog-incoming-set A)

;; Step 2: add AC in derived atomspace
(define derived-as (cog-new-atomspace base-as))
(cog-set-atomspace! derived-as)
(define derived-AC (Inheritance A C))

(cog-incoming-set A)

;; Step 3: go back to base atomspace and add AC again
(cog-set-atomspace! base-as)
(define base-AC (Inheritance A C))

(cog-incoming-set A)

As you may see the last call of cog-incoming-set returns AC twice. I do understand why as AC is both in base-as and derived-as but is it normal?

Here's what is even more suspicious, if I add AC into the base atomspace before adding AC in the derived atomspace, then the duplicate never shows up. Specifically I mean (starting from a new guile session)

;; Step 1: add atoms in base atomspace (including AC)
(define base-as (cog-atomspace))
(define A (Concept "A"))
(define B (Concept "B"))
(define C (Concept "C"))
(define AB (Inheritance A B))
(define base-AC (Inheritance A C))

(cog-incoming-set A)

;; Step 2: add AC in derived atomspace
(define derived-as (cog-new-atomspace base-as))
(cog-set-atomspace! derived-as)
(define derived-AC (Inheritance A C))

(cog-incoming-set A)

;; Step 3: go back to base atomspace and see incoming set of A
(cog-set-atomspace! base-as)

(cog-incoming-set A)

As you can see this time the last cog-incoming-set call only shows 2 incoming atoms, contradicting the first example.

@ngeiswei
Copy link
Member Author

@linas, if you can confidently tell me what is the expected behavior I don't mind attempting to fixing it myself.

@linas
Copy link
Member

linas commented Nov 28, 2018

In the first example, this is an ugly side effect. There is no clear or obvious "easy" fix. There is also no clear or obvious idea of what "should" happen -- its not fixable, if you don't know what "should" happen.

The second example is working as designed, and is clearly correct, and working exactly as specified. There is no "second" inheritance link created, because it already exists in the base space. If you really really want to force creation of a second link in the derived space, mark the base-space as read-only, then create it, then alter it's truth value, then re-mark the base space as read-write.

So the fix is in two steps: explain what "should" happen in the first example. Then explain how to fix that.

@linas
Copy link
Member

linas commented Dec 3, 2018

So I thought about this some more. A key issue is that the scheme bindings always assume a "current" atomspace. Thus, in the first example, there is no simple way (in scheme) to move AC from the derived atomspace to the base atomspace. (its easy to do this in C++)

So three utilities are possible:

  1. move an atom (with all its values) from one atomspace to another
  2. copy an atom (and its values) from one atomspace to another
  3. project an atom from a derived space to a base space (i.e. move from derived to base, but never the other way)

I like alternative 3 the best, as it seems to be the one that makes the most sense, to me, in standard usage scenarios. I can see how 1) could be useful. Option 2) seems like the worst, as it just leads to multiple copies of atoms, which mostly need to be avoided. The only case where 2) make sense is if the base is read-only, and one wants to modify an atom in the base; then one must copy to make ti read-write. But this is already done automatically, so no explicit option 2 is needed.

.

@linas
Copy link
Member

linas commented Dec 24, 2018

OK, I thought about this some more, and have an "even better" solution, although it will take much longer to implement. It is hinted here: https://wiki.opencog.org/w/AtomSpace#Atoms_are_fat.3B_Atomspace_insertion_is_slow

The idea is this: denote atomspace membership using a new AtomSpaceLink, which is like MemberLink except different. Move all Values so that they live ONLY in the AtomSpaceLink, and NEVER on an atom. Thus an atom contains only the incoming/outgoing sets, and no values. Thus the incoming sets will always be unique, and the atom will continue to be unique (avoiding the problem you have above) Things like read-only, read-write and multiple atomspaces become easier. And AtomSpaceLink really becomes a kind-of ContextLink, so that contextual truth values now become easy. So I keep finding more and more reasons for AtomSpaceLink ... see #1967 for details.

@vsbogd
Copy link
Contributor

vsbogd commented Dec 24, 2018

I have a question about first example provided by @ngeiswei. It is not obvious for me why adding AC to the derived atomspace modifies parent atomspace. Am I right that side effect reason is that only instance of A atom is member of both atomspaces and adding link to its incoming set leads to this link appears in parent atomspace?

If so why this behavior will be fixed by #1967? Is it because it will be possible to implement get-incoming-set-by-atomspace?

@linas
Copy link
Member

linas commented Dec 24, 2018

It is not obvious for me why adding AC to the derived atomspace modifies parent atomspace.

It doesn't. In step 2, AC is added only to the derived atomspace.

instance of A

atom A is "really" "only" in the base atomspace. Its not "really" in the derived atomspace; it is only "virtually" in the derived atomspace. That is, the base atomspace is the only one actually holding A in a C++ std:set<Atom>. The derived atomspace first searches it's own copy of std::set<Atom>, cannot find A (because it's not there), and then asks the base atomspace "maybe you have it?" -- the base atomspace says "yes I do", and so the derived atomspace says "ok, well then, me too", and it returns the base-spaces copy of A.

Now apply this same logic to AC. Step 2 creates AC in the derived space. Step 3 creates it in the base space. As a result, two different atoms AC are stored in std:set<Atom> for two different atomspaces. (This is because the base space cannot ask the derived space "do you have it"?)

fixed by #1967 ?

Oh, huh. Maybe I spoke too soon, without thinking about it enough. As a part of #1967, I guess we would still need to have a global check: "is AC in any atomspace, anywhere?" If so, then use that copy.

@vsbogd
Copy link
Contributor

vsbogd commented Dec 25, 2018

Thanks, Linas.

@linas
Copy link
Member

linas commented May 10, 2022

This has been fixed in the recent spate of changes to support AtomSpace frames. Fixed in pull req #2925, I believe. (Early April 2022)

@linas linas closed this as completed May 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants