AmpersandTarski / Ampersand

Build database applications faster than anyone else, and keep your data pollution free as a bonus.
http://ampersandtarski.github.io/
GNU General Public License v3.0
40 stars 8 forks source link

Allow cyclic dependencies in Concepts as synonym #999

Closed stefjoosten closed 4 years ago

stefjoosten commented 5 years ago

Problem

Ampersand-v3.17.2 and earlier prohibit cyclic dependencies in Concepts. Also, it prohibits multiple root concepts in a typology. However, as a user, I might have reasons to allow synonyms. For instance when combining different contexts (from different offspring) into a new context.

Solution intent

We could simply allow cyclic dependencies. All concepts in a cycle represent the same set of atoms, so effectively this means they will be synonyms of each other.

In the same effort, we can allow multiple roots (see issue #898). Note that this differs from allowing cyclic dependencies. It fits well in the philosophy of allowing things that have a reasonable interpretation. Nevertheless, a warning is in place, because sometimes people define multiple roots by mistake. The way to get rid of the warning is to define a concept for the union of the roots as described in issue #898.

stefjoosten commented 5 years ago

Impact:

  1. CtxError.hs, line 153: mkCyclesInGensError Turn function mkCyclesInGensError into a warning.
  2. CtxError.hs, line 166: mkMultipleRootsError Turn function mkMultipleRootsErrorinto a warning.
  3. P2A_Converters.hs, line 377 Instead of calling mkCyclesInGensError, function mkTypology yields one concept with multiple names.
  4. P2A_Converters.hs, line 391 Instead of calling mkMultipleRootsError, function mkTypology produces one new concept that is the union of its constituents, together with the ISA's between each constituent and the newly generated concept.
  5. Allow concepts with multiple names. This affects the definition of A_Concept (AbstractSyntaxTree.hs line 754), which must accommodate multiple names. I would expect that P_Context need not have multiple names because that is a concept at parse-time. The P2A converter must collect multiple P_Concepts into one A_Concept.
hanjoosten commented 5 years ago

So what to do with

stefjoosten commented 5 years ago

Hi Han, good questions!

To start with, what to do with instance Named A_Concept? As there may be multiple names, the function name must pick one. For this purpose, the A_Concept must not only store different names, but also the contexts that define those names. For choosing which name to print, I suggest names from the "current context" have a preference. For now, I just pick the head from a NonEmpty P_Concept.

For the instances Eq A_Concept and Ord A_Concept we leave the code as-is because it hinges on the hash attribute. We do not rely on the concept's name for equality, so there is no impact here:

instance Ord A_Concept where
  compare (PlainConcept{cpthash=v1}) (PlainConcept{cpthash=v2}) = compare v1 v2
  compare ONE ONE = EQ
  compare ONE (PlainConcept{}) = LT
  compare (PlainConcept{}) ONE = GT

instance Eq A_Concept where
  (==) a b = compare a b == EQ

Then what about aConcept2pConcept :: A_Concept -> P_Concept. It will become

aConcept2pConcept :: A_Concept -> NEL.NonEmpty P_Concept

So it yields a nonempty list instead of a single P_Concept.

Functions pCpt2aCpt :: P_Concept -> A_Concept gets a different setup, because a number of P_Concepts from different contexts can be assembled into one A_Concept, after a cycle of concepts is detected.

Michiel-s commented 5 years ago

Makes sense. I recognize this from the OWL ontology language.

“NOTE: If we wanted to "upgrade" an axiom of the form "A subClassOf B" to "A equivalentClass B" (meaning that the class extension of A is not just any subset, but in fact the same set as the class extension of B), we could add a second subClassOf axiom of the form (B subClassOf A), which by definition makes the two class extensions equivalent (and thus has the same meaning as "A equivalentClass B"). Such subClassOf "cycles" are explicitly allowed. As OWL is usable in a distributed environment, this can be a useful feature.” Source: https://www.w3.org/TR/owl-ref/#subClassOf-def

hanjoosten commented 4 years ago

I have implemented a nice solution to this problem, and created pull request https://github.com/AmpersandTarski/Ampersand/pull/1055 for it. The idea is that in the P-structure we harvest all concepts that are equivalent, based on cycles in the CLASSIFY statements. All such concepts will be considered as a single concept in the A-structure. All relations that have any of these concepts as source of target will have that single concept as source/target in the a-structure.

Some choices I made in this implementation:

stefjoosten commented 4 years ago

Great! I like this solution because it is upwards compatible and it maintains the rule in the metamodel that (A ISA B) /\ (B ISA A) <=> (A=B). (Currently, this rule is true but empty)

We will get some details to look after, which may pop up as issues in the future:

hanjoosten commented 4 years ago

Aliassing of concept names now works and is merged into development.