示例#1
0
 def constrained(self):
     """
     Tells whether the datatype of this restriction is constrained by graph composition.
     :rtype: bool
     """
     f1 = lambda x: x.isItem(Item.InputEdge)
     f2 = lambda x: x.isItem(Item.DatatypeRestrictionNode)
     f3 = lambda x: x.isItem(Item.ValueDomainNode)
     x = first(self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2))
     if x:
         return first(x.incomingNodes(filter_on_edges=f1, filter_on_nodes=f3)) is not None
     return False
示例#2
0
 def constrained(self):
     """
     Tells whether the datatype of this restriction is constrained by graph composition.
     :rtype: bool
     """
     f1 = lambda x: x.isItem(Item.InputEdge)
     f2 = lambda x: x.isItem(Item.DatatypeRestrictionNode)
     f3 = lambda x: x.isItem(Item.ValueDomainNode)
     x = first(self.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2))
     if x:
         return first(
             x.incomingNodes(filter_on_edges=f1,
                             filter_on_nodes=f3)) is not None
     return False
示例#3
0
    def __init__(self, scene, edges):
        """
        Initialize the command.
        """
        if len(edges) == 1:
            super().__init__('swap {}'.format(first(edges).name))
        else:
            super().__init__('swap {} edges'.format(len(edges)))

        self.scene = scene
        self.edges = edges

        self.inputs = {n: {
            'undo': n.inputs[:],
            'redo': n.inputs[:],
        } for edge in self.edges \
            if edge.isItem(Item.InputEdge) \
                for n in {edge.source, edge.target} \
                    if n.isItem(Item.RoleChainNode, Item.PropertyAssertionNode)}

        for edge in self.edges:
            if edge.isItem(Item.InputEdge) and edge.target in self.inputs:
                self.inputs[edge.target]['redo'].remove(edge.id)

        for edge in self.edges:
            if edge.isItem(Item.InputEdge) and edge.source in self.inputs:
                self.inputs[edge.source]['redo'].append(edge.id)
示例#4
0
    def buildDomainRestrictionNodeMenu(self, mainwindow, scene, node):
        """
        Build and return a QMenu instance for domain restriction nodes.
        :type mainwindow: MainWindow
        :type scene: DiagramScene
        :type node: DomainRestrictionNode
        :rtype: QMenu
        """
        menu = self.buildGenericNodeMenu(mainwindow, scene, node)
        menu.addSeparator()
        menu.insertMenu(scene.mainwindow.actionOpenNodeProperties, scene.mainwindow.menuRestrictionChange)

        f1 = lambda x: x.isItem(Item.InputEdge)
        f2 = lambda x: x.identity is Identity.Attribute

        qualified = node.qualified
        attribute = first(node.incomingNodes(filter_on_edges=f1, filter_on_nodes=f2))

        # Switch the currently active restriction and hide invalid ones.
        for action in scene.mainwindow.actionsRestrictionChange:
            action.setChecked(node.restriction is action.data())
            action.setVisible(action.data() is not Restriction.Self or not qualified and not attribute)

        # Append label specific actions.
        collection = self.buildNodeLabelSpecificActionSet(mainwindow, scene, node)
        if collection:
            menu.insertSeparator(mainwindow.actionOpenNodeProperties)
            for action in collection:
                menu.insertAction(mainwindow.actionOpenNodeProperties, action)

        menu.insertSeparator(scene.mainwindow.actionOpenNodeProperties)
        return menu
示例#5
0
    def __init__(self, scene, edges):
        """
        Initialize the command.
        """
        if len(edges) == 1:
            super().__init__('swap {}'.format(first(edges).name))
        else:
            super().__init__('swap {} edges'.format(len(edges)))

        self.scene = scene
        self.edges = edges

        self.inputs = {n: {
            'undo': n.inputs[:],
            'redo': n.inputs[:],
        } for edge in self.edges \
            if edge.isItem(Item.InputEdge) \
                for n in {edge.source, edge.target} \
                    if n.isItem(Item.RoleChainNode, Item.PropertyAssertionNode)}

        for edge in self.edges:
            if edge.isItem(Item.InputEdge) and edge.target in self.inputs:
                self.inputs[edge.target]['redo'].remove(edge.id)

        for edge in self.edges:
            if edge.isItem(Item.InputEdge) and edge.source in self.inputs:
                self.inputs[edge.source]['redo'].append(edge.id)
示例#6
0
    def __init__(self, scene, collection):
        """
        Initialize the command.
        """
        self.scene = scene
        self.nodes = {item for item in collection if item.node}
        self.edges = {item for item in collection if item.edge}

        # compute the new inputs order for role chain and property assertion nodes
        # which are not being removed but whose other endpoint is being detached.
        self.inputs = {n: {
            'undo': n.inputs[:],
            'redo': n.inputs[:],
        } for edge in self.edges \
            if edge.isItem(Item.InputEdge) \
                for n in {edge.source, edge.target} \
                    if n.isItem(Item.RoleChainNode, Item.PropertyAssertionNode) and \
                        n not in self.nodes}

        for node in self.inputs:
            for edge in node.edges:
                if edge.isItem(Item.InputEdge) and edge in self.edges and edge.target is node:
                    self.inputs[node]['redo'].remove(edge.id)

        if len(collection) == 1:
            super().__init__('remove {}'.format(first(collection).name))
        else:
            super().__init__('remove {} items'.format(len(collection)))
示例#7
0
    def buildRangeRestrictionNodeMenu(self, mainwindow, scene, node):
        """
        Build and return a QMenu instance for range restriction nodes.
        :type mainwindow: MainWindow
        :type scene: DiagramScene
        :type node: RangeRestrictionNode
        :rtype: QMenu
        """
        menu = self.buildGenericNodeMenu(mainwindow, scene, node)

        f1 = lambda x: x.isItem(Item.InputEdge)
        f2 = lambda x: x.identity is Identity.Attribute

        # Allow to change the restriction type only if it's not an Attribute range restriction.
        if not first(node.incomingNodes(filter_on_edges=f1, filter_on_nodes=f2)):
            menu.addSeparator()
            menu.insertMenu(mainwindow.actionOpenNodeProperties, mainwindow.menuRestrictionChange)
            for action in mainwindow.actionsRestrictionChange:
                action.setChecked(node.restriction is action.data())
                action.setVisible(action.data() is not Restriction.Self)

        # Append label specific actions.
        collection = self.buildNodeLabelSpecificActionSet(mainwindow, scene, node)
        if collection:
            menu.insertSeparator(mainwindow.actionOpenNodeProperties)
            for action in collection:
                menu.insertAction(mainwindow.actionOpenNodeProperties, action)

        menu.insertSeparator(mainwindow.actionOpenNodeProperties)
        return menu
示例#8
0
    def __init__(self, scene, collection):
        """
        Initialize the command.
        """
        self.scene = scene
        self.nodes = {item for item in collection if item.node}
        self.edges = {item for item in collection if item.edge}

        # compute the new inputs order for role chain and property assertion nodes
        # which are not being removed but whose other endpoint is being detached.
        self.inputs = {n: {
            'undo': n.inputs[:],
            'redo': n.inputs[:],
        } for edge in self.edges \
            if edge.isItem(Item.InputEdge) \
                for n in {edge.source, edge.target} \
                    if n.isItem(Item.RoleChainNode, Item.PropertyAssertionNode) and \
                        n not in self.nodes}

        for node in self.inputs:
            for edge in node.edges:
                if edge.isItem(
                        Item.InputEdge
                ) and edge in self.edges and edge.target is node:
                    self.inputs[node]['redo'].remove(edge.id)

        if len(collection) == 1:
            super().__init__('remove {}'.format(first(collection).name))
        else:
            super().__init__('remove {} items'.format(len(collection)))
示例#9
0
 def __init__(self, scene, nodes, brush):
     """
     Initilize the command.
     """
     self.scene = scene
     self.nodes = nodes
     self.brush = {x: {'undo': x.brush, 'redo': brush} for x in nodes}
     if len(nodes) != 1:
         super().__init__('change color of {} nodes'.format(len(nodes)))
     else:
         super().__init__('change {} color'.format(first(nodes).name))
示例#10
0
 def __init__(self, scene, nodes, brush):
     """
     Initilize the command.
     """
     self.scene = scene
     self.nodes = nodes
     self.brush = {x: {'undo': x.brush, 'redo': brush} for x in nodes}
     if len(nodes) != 1:
         super().__init__('change color of {} nodes'.format(len(nodes)))
     else:
         super().__init__('change {} color'.format(first(nodes).name))
示例#11
0
    def __init__(self, scene, data):
        """
        Initialize the command.
        """
        if len(data) == 1:
            super().__init__('toggle {} completness'.format(first(data.keys()).name))
        else:
            super().__init__('toggle completness for {} edges'.format(len(data)))

        self.scene = scene
        self.data = data
示例#12
0
    def stack(self):
        """
        Set the current stacked widget.
        """
        if self.scene:
            selected = self.scene.selectedItems()
            if not selected or len(selected) > 1:
                show = self.infoDiagram
                show.updateData(self.scene)
            else:
                item = first(selected)
                if item.node:
                    if item.predicate:
                        if item.item is Item.ValueDomainNode:
                            show = self.infoValueDomainNode
                            show.updateData(item)
                        elif item.item is Item.ValueRestrictionNode:
                            show = self.infoValueRestrictionNode
                            show.updateData(item)
                        elif item.item is Item.RoleNode:
                            show = self.infoRoleNode
                            show.updateData(item)
                        elif item.item is Item.AttributeNode:
                            show = self.infoAttributeNode
                            show.updateData(item)
                        elif item.item is Item.IndividualNode and item.identity is Identity.Value:
                            show = self.infoValueNode
                            show.updateData(item)
                        elif item.label.editable:
                            show = self.infoEditableNode
                            show.updateData(item)
                        else:
                            show = self.infoPredicateNode
                            show.updateData(item)
                    else:
                        show = self.infoNode
                        show.updateData(item)
                else:
                    if item.item is Item.InclusionEdge:
                        show = self.infoInclusionEdge
                        show.updateData(item)
                    else:
                        show = self.infoEdge
                        show.updateData(item)
        else:
            show = self.infoEmpty

        prev = self.stacked.currentWidget()
        self.stacked.setCurrentWidget(show)
        self.stacked.setFixedSize(show.size())
        if prev is not show:
            scrollbar = self.verticalScrollBar()
            scrollbar.setValue(0)
示例#13
0
    def __init__(self, scene, collection):
        """
        Initialize the command.
        """
        self.scene = scene
        self.collection = collection
        self.selected = scene.selectedItems()

        if len(collection) == 1:
            super().__init__('add {}'.format(first(collection).name))
        else:
            super().__init__('add {} items'.format(len(collection)))
示例#14
0
    def __init__(self, scene, collection):
        """
        Initialize the command.
        """
        self.scene = scene
        self.collection = collection
        self.selected = scene.selectedItems()

        if len(collection) == 1:
            super().__init__('add {}'.format(first(collection).name))
        else:
            super().__init__('add {} items'.format(len(collection)))
示例#15
0
    def stack(self):
        """
        Set the current stacked widget.
        """
        if self.scene:
            selected = self.scene.selectedItems()
            if not selected or len(selected) > 1:
                show = self.infoDiagram
                show.updateData(self.scene)
            else:
                item = first(selected)
                if item.node:
                    if item.predicate:
                        if item.item is Item.ValueDomainNode:
                            show = self.infoValueDomainNode
                            show.updateData(item)
                        elif item.item is Item.ValueRestrictionNode:
                            show = self.infoValueRestrictionNode
                            show.updateData(item)
                        elif item.item is Item.RoleNode:
                            show = self.infoRoleNode
                            show.updateData(item)
                        elif item.item is Item.AttributeNode:
                            show = self.infoAttributeNode
                            show.updateData(item)
                        elif item.item is Item.IndividualNode and item.identity is Identity.Value:
                            show = self.infoValueNode
                            show.updateData(item)
                        elif item.label.editable:
                            show = self.infoEditableNode
                            show.updateData(item)
                        else:
                            show = self.infoPredicateNode
                            show.updateData(item)
                    else:
                        show = self.infoNode
                        show.updateData(item)
                else:
                    if item.item is Item.InclusionEdge:
                        show = self.infoInclusionEdge
                        show.updateData(item)
                    else:
                        show = self.infoEdge
                        show.updateData(item)
        else:
            show = self.infoEmpty

        prev = self.stacked.currentWidget()
        self.stacked.setCurrentWidget(show)
        self.stacked.setFixedSize(show.size())
        if prev is not show:
            scrollbar = self.verticalScrollBar()
            scrollbar.setValue(0)
示例#16
0
    def __init__(self, scene, data):
        """
        Initialize the command.
        """
        if len(data) == 1:
            super().__init__('toggle {} completness'.format(
                first(data.keys()).name))
        else:
            super().__init__('toggle completness for {} edges'.format(
                len(data)))

        self.scene = scene
        self.data = data
示例#17
0
    def __init__(self, scene, data):
        """
        Initialize the command.
        """
        self.data = data
        self.scene = scene
        self.edges = set()

        for node in data['redo']['nodes']:
            self.edges |= set(node.edges)

        if len(data['redo']['nodes']) != 1:
            params = 'move {} nodes'.format(len(data['redo']['nodes']))
        else:
            params = 'move {}'.format(first(data['redo']['nodes'].keys()).name)

        super().__init__(params)
示例#18
0
 def mouseReleaseEvent(self, mouseEvent):
     """
     Executed when the mouse is pressed on the tree view
     :type mouseEvent: QMouseEvent
     """
     if mouseEvent.button() == Qt.RightButton:
         index = first(self.selectedIndexes())
         if index:
             model = self.model().sourceModel()
             index = self.model().mapToSource(index)
             item = model.itemFromIndex(index)
             node = item.data()
             if node:
                 menu = self.mainwindow.menuFactory.create(
                     self.mainwindow, node.scene(), node)
                 menu.exec_(mouseEvent.screenPos().toPoint())
     super().mouseReleaseEvent(mouseEvent)
示例#19
0
    def __init__(self, scene, data):
        """
        Initialize the command.
        """
        self.data = data
        self.scene = scene
        self.edges = set()

        for node in data['redo']['nodes']:
            self.edges |= set(node.edges)

        if len(data['redo']['nodes']) != 1:
            params = 'move {} nodes'.format(len(data['redo']['nodes']))
        else:
            params = 'move {}'.format(first(data['redo']['nodes'].keys()).name)

        super().__init__(params)
示例#20
0
    def browse(self, view):
        """
        Set the widget to inspect the given view.
        :type view: MainView
        """
        self.reset()
        self.mainview = view

        if self.mainview:

            scene = self.mainview.scene()
            connect(scene.index.sgnItemAdded, self.add)
            connect(scene.index.sgnItemRemoved, self.remove)

            for item in scene.index.nodes():
                self.add(item)

            if self.mainview in self.expanded:
                expanded = self.expanded[self.mainview]
                for i in range(self.model.rowCount()):
                    item = self.model.item(i)
                    index = self.proxy.mapFromSource(
                        self.model.indexFromItem(item))
                    self.view.setExpanded(index, item.text() in expanded)

            key = ''
            if self.mainview in self.searched:
                key = self.searched[self.mainview]
            self.search.setText(key)

            if self.mainview in self.scrolled:
                rect = self.rect()
                item = first(self.model.findItems(
                    self.scrolled[self.mainview]))
                for i in range(self.model.rowCount()):
                    self.view.scrollTo(
                        self.proxy.mapFromSource(
                            self.model.indexFromItem(self.model.item(i))))
                    index = self.proxy.mapToSource(
                        self.view.indexAt(rect.topLeft()))
                    if self.model.itemFromIndex(index) is item:
                        break
示例#21
0
    def run(self, source, edge, target):
        """
        Run the validation algorithm on the given triple and generates the ValidationResult instance.
        :type source: AbstractNode
        :type edge: AbstractEdge
        :type target: AbstractNode
        """
        try:

            if source is target:
                # We do not allow the connection if source and target are the same node.
                raise SyntaxError('Self connection is not valid')

            if edge.item is Item.InclusionEdge:

                ########################################################################################################
                #                                                                                                      #
                #   INCLUSION EDGE                                                                                     #
                #                                                                                                      #
                ########################################################################################################

                supported = {
                    Identity.Concept, Identity.Role, Identity.Attribute,
                    Identity.ValueDomain
                }
                remaining = source.identities & target.identities - {
                    Identity.Neutral, Identity.Unknown
                }

                if remaining - supported:
                    # Inclusion assertions can be specified only between Graphol expressions: Concept
                    # expressions, Role expressions, Value-Domain expressions, Attribute expressions.
                    raise SyntaxError(
                        'Type mismatch: inclusion must involve two graphol expressions'
                    )

                if not remaining:
                    # If source and target nodes do not share a common identity then we can't create an inclusion.
                    raise SyntaxError(
                        'Type mismatch: {} and {} are not compatible'.format(
                            source.name, target.name))

                if Identity.Neutral not in {
                        source.identity, target.identity
                } and source.identity is not target.identity:
                    # If both nodes are not NEUTRAL and they specify a different identity we can't create an inclusion.
                    idA = source.identity.value
                    idB = target.identity.value
                    raise SyntaxError(
                        'Type mismatch: inclusion between {} and {}'.format(
                            idA, idB))

                if Identity.ValueDomain in {source.identity, target.identity}:

                    # We exclude from the following check inclusion edges sourcing from a RangeRestriction
                    # node since it will be translated into OWL DataPropertyRange that accepts ValueDomain
                    # i.e. complex datatypes and not only atomic ones.
                    if source.item is not Item.RangeRestrictionNode:

                        if source.item is not Item.ValueDomainNode and target.item is not Item.ValueDomainNode:
                            # Inclusion assertions between value-domain expressions must involve at least an atomic
                            # datatype (i.e., the source or the target of the assertion must be an atomic datatype).
                            raise SyntaxError(
                                'Inclusion between value-domain expressions must include at least an '
                                'atomic datatype')

                if source.item is Item.ComplementNode:

                    identity = first({source.identity, target.identity} -
                                     {Identity.Neutral})
                    if identity and identity in {
                            Identity.Attribute, Identity.Role
                    }:
                        # Role and attribute expressions whose sink node is a
                        # complement node cannot be the source of any inclusion edge.
                        raise SyntaxError(
                            'Invalid source for {} inclusion: {}'.format(
                                identity.value, source.name))

                if target.item is Item.RoleChainNode:
                    # Role expressions constructed with chain nodes cannot be the target of any inclusion edge.
                    raise SyntaxError(
                        'Type mismatch: role chain nodes cannot be target of a Role inclusion'
                    )

                if source.item is Item.RoleChainNode:
                    # Role expressions constructed with chain nodes can be included only in basic role expressions, that
                    # are either Role nodes or RoleInverse nodes with one input Role node (this check is done elsewhere)
                    if target.item not in {
                            Item.RoleNode, Item.RoleInverseNode
                    }:
                        raise SyntaxError(
                            'Inclusion between {} and {} is forbidden'.format(
                                source.name, target.name))

            elif edge.item is Item.InputEdge:

                ########################################################################################################
                #                                                                                                      #
                #   INPUT EDGE                                                                                         #
                #                                                                                                      #
                ########################################################################################################

                if not target.constructor:
                    # Input edges can only target constructor nodes.
                    raise SyntaxError(
                        'Input edges can only target constructor nodes')

                if target.item in {
                        Item.ComplementNode, Item.DisjointUnionNode,
                        Item.IntersectionNode, Item.UnionNode
                }:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET IN { COMPLEMENT, DISJOINT UNION, INTERSECTION, UNION }                                  #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.identity not in target.identities:
                        # Source node identity is not supported by this node despite the currently set identity.
                        raise SyntaxError('Invalid input to {}: {}'.format(
                            target.name, source.identity.value))

                    if source.item is Item.ValueRestrictionNode:
                        # Exclude invalid nodes despite identity matching.
                        raise SyntaxError('Invalid target: {}'.format(
                            target.name))

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = COMPLEMENT                                                                            #
                    #                                                                                                  #
                    ####################################################################################################

                    if target.item is Item.ComplementNode:

                        if len(
                                target.incomingNodes(
                                    lambda x: x.item is Item.InputEdge and x is
                                    not edge)) > 0:
                            # The Complement operator may have at most one node connected to it.
                            raise SyntaxError('Too many inputs to {}'.format(
                                target.name))

                        if source.item in {
                                Item.RoleNode, Item.RoleInverseNode,
                                Item.AttributeNode
                        }:

                            # See if the source of the node matches an ObjectPropertyExpression ({Role, RoleInv}) or a
                            # DataPropertyExpression (Attribute). If that's the case check for the node not to have any
                            # outgoing Input edge: the only supported expression are NegativeObjectPropertyAssertion,
                            # R1 ISA NOT R2, and NegativeDataPropertyAssertion, A1 ISA NOT A2. This prevents the
                            # connection of Role expressions to Complement nodes that are given as inputs to Enumeration,
                            # Union and Disjoint Union operatore nodes.
                            if len(
                                    target.incomingNodes(
                                        lambda x: x.item is Item.InputEdge and
                                        x.source is target)) > 0:
                                raise SyntaxError(
                                    'Invalid negative {} expression'.format(
                                        source.identity.value))

                    else:

                        ################################################################################################
                        #                                                                                              #
                        #   TARGET IN { DISJOINT UNION, INTERSECTION, UNION }                                          #
                        #                                                                                              #
                        ################################################################################################

                        if Identity.Neutral not in {
                                source.identity, target.identity
                        }:

                            if source.identity is not target.identity:
                                # Union/Intersection between different type of graphol expressions.
                                idA = source.identity.value
                                idB = target.identity.value
                                composition = cutR(target.name, ' node')
                                raise SyntaxError(
                                    'Type mismatch: {} between {} and {}'.
                                    format(composition, idA, idB))

                elif target.item is Item.EnumerationNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = ENUMERATION                                                                           #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.item is not Item.IndividualNode:
                        # Enumeration operator (oneOf) takes as inputs instances or values, both represented
                        # by the Individual node, and has the job of composing a set if individuals (either Concept
                        # or ValueDomain, but not both together).
                        name = source.identity.value if source.identity is not Identity.Neutral else source.name
                        raise SyntaxError('Invalid input to {}: {}'.format(
                            target.name, name))

                    if target.identity is Identity.Unknown:
                        # Target node has an unkown identity: we do not allow the connection => the user MUST fix the
                        # error first and then try to create again the connection (this should never happen actually).
                        raise SyntaxError(
                            'Target node has an invalid identity: {}'.format(
                                target.identity.value))

                    if target.identity is not Identity.Neutral:

                        if source.identity is Identity.Instance and target.identity is Identity.ValueDomain:
                            raise SyntaxError('Invalid input to {}: {}'.format(
                                target.name, source.identity.value))

                        if source.identity is Identity.Value and target.identity is Identity.Concept:
                            raise SyntaxError('Invalid input to {}: {}'.format(
                                target.name, source.identity.value))

                elif target.item is Item.RoleInverseNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = ROLE INVERSE                                                                          #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.item is not Item.RoleNode:
                        # The Role Inverse operator takes as input a role and constructs its inverse by switching
                        # domain and range of the role. Assume to have a Role labelled 'is_owner_of' whose instances
                        # are {(o1,o2), (o1,o3), (o4,o5)}: connecting this Role in input to a Role Inverse node will
                        # construct a new Role whose instances are {(o2,o1), (o3,o1), (o5,o4)}.
                        raise SyntaxError(
                            'Role Inverse accepts only a Role node as input')

                    if len(
                            target.incomingNodes(
                                lambda x: x.item is Item.InputEdge and x is
                                not edge)) > 0:
                        # The Role Inverse operator may have at most one Role node connected to it: if we need to
                        # define multiple Role inverse we would need to use multiple Role Inverse operator nodes.
                        raise SyntaxError('Too many inputs to {}'.format(
                            target.name))

                elif target.item is Item.RoleChainNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = ROLE CHAIN                                                                            #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.item not in {
                            Item.RoleNode, Item.RoleInverseNode
                    }:
                        # The Role Chain operator constructs a concatenation of roles. Assume to have 2 Role nodes
                        # defined as 'lives_in_region' and 'region_in_country': if {(o1, o2), (o3, o4)} is the
                        # instance of 'lives_in_region' and {(o2, o6)} is the instance of 'region_in_country', then
                        # {(o1, o6)} is the instance of the chain, which would match another Role 'lives_in_country'.
                        # ObjectPropertyExpression := ObjectProperty | InverseObjectProperty => we need to match only
                        # Role nodes and Role Inverse nodes as sources of our edge (it's not possible to create a chain
                        # of chains, despite the identity matches Role in both expressions).
                        raise SyntaxError('Invalid input to {}: {}'.format(
                            target.name, source.name))

                elif target.item is Item.DatatypeRestrictionNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = DATATYPE RESTRICTION                                                                  #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.item not in {
                            Item.ValueDomainNode, Item.ValueRestrictionNode
                    }:
                        # The DatatypeRestriction node is used to compose complex datatypes and
                        # accepts as inputs one value-domain node and n >= 1 value-restriction
                        # nodes to compose the OWL 2 equivalent DatatypeRestriction.
                        raise SyntaxError('Invalid input to {}: {}'.format(
                            target.name, source.name))

                    if source.item is Item.ValueDomainNode:

                        f1 = lambda x: x.item is Item.InputEdge and x is not edge
                        f2 = lambda x: x.item is Item.ValueDomainNode
                        if len(
                                target.incomingNodes(filter_on_edges=f1,
                                                     filter_on_nodes=f2)) > 0:
                            # The value-domain has already been attached to the DatatypeRestriction.
                            raise SyntaxError(
                                'Too many value-domain nodes in input to {}'.
                                format(target.name))

                    # We need to check whether the DatatypeRestriction node has already datatype
                    # inferred: if that's the case and the datatype doesn't match the datatype of
                    # the source node, we deny the connection to prevent inconsistencies.
                    f1 = lambda x: x.item is Item.InputEdge and x is not edge
                    f2 = lambda x: x.item in {
                        Item.ValueDomainNode, Item.ValueRestrictionNode
                    } and x is not source
                    collection = target.incomingNodes(filter_on_edges=f1,
                                                      filter_on_nodes=f2)
                    if collection:
                        datatype = first(collection).datatype
                        if datatype is not source.datatype:
                            d1 = source.datatype.value
                            d2 = datatype.value
                            raise SyntaxError(
                                'Datatype mismatch: restriction between {} and {}'
                                .format(d1, d2))

                elif target.item is Item.PropertyAssertionNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = PROPERTY ASSERTION                                                                    #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.item is not Item.IndividualNode:
                        # Property Assertion operators accepts only Individual nodes as input: they are
                        # used to construct ObjectPropertyAssertion and DataPropertyAssertion axioms.
                        raise SyntaxError('Invalid input to {}: {}'.format(
                            target.name, source.identity.value))

                    if len(
                            target.incomingNodes(
                                lambda x: x.item is Item.InputEdge and x is
                                not edge)) >= 2:
                        # At most 2 Individual nodes can be connected to a PropertyAssertion node. As an example
                        # we can construct ObjectPropertyAssertion(presiede M.Draghi BCE) where the individuals
                        # are identified by M.Draghi and BCE, or DataPropertyAssertion(nome M.Draghi "Mario") where
                        # the individuals are identified by M.Draghi and "Mario".
                        raise SyntaxError('Too many inputs to {}'.format(
                            target.name))

                    if target.identity is Identity.RoleInstance:

                        if source.identity is Identity.Value:
                            # We are constructing an ObjectPropertyAssertion expression so we can't connect a Value.
                            raise SyntaxError(
                                'Invalid input to {}: Value'.format(
                                    target.identity.value))

                    if target.identity is Identity.AttributeInstance:

                        if source.identity is Identity.Instance:

                            f1 = lambda x: x.item is Item.InputEdge and x is not edge
                            f2 = lambda x: x.identity is Identity.Instance
                            if len(
                                    target.incomingNodes(
                                        filter_on_edges=f1,
                                        filter_on_nodes=f2)) > 0:
                                # We are constructing a DataPropertyAssertion and so we can't have more than 1 instance.
                                raise SyntaxError(
                                    'Too many instances in input to {}'.format(
                                        target.identity.value))

                        if source.identity is Identity.Value:

                            f1 = lambda x: x.item is Item.InputEdge and x is not edge
                            f2 = lambda x: x.identity is Identity.Value
                            if len(
                                    target.incomingNodes(
                                        filter_on_edges=f1,
                                        filter_on_nodes=f2)) > 0:
                                # At most one Literal can be given as input (2 instance | 1 instance + 1 value)
                                raise SyntaxError(
                                    'Too many values in input to {}'.format(
                                        target.identity.value))

                elif target.item is Item.DomainRestrictionNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = DOMAIN RESTRICTION                                                                    #
                    #                                                                                                  #
                    ####################################################################################################

                    if len(
                            target.incomingNodes(
                                lambda x: x.item is Item.InputEdge and x is
                                not edge)) >= 2:
                        # Domain Restriction node can have at most 2 inputs.
                        raise SyntaxError('Too many inputs to {}'.format(
                            target.name))

                    supported = {
                        Identity.Concept, Identity.Attribute, Identity.Role,
                        Identity.ValueDomain
                    }
                    if source.identity is not Identity.Neutral and source.identity not in supported:
                        # Domain Restriction node takes as input:
                        #  - Role => OWL 2 ObjectPropertyExpression
                        #  - Attribute => OWL 2 DataPropertyExpression
                        #  - Concept => Qualified Existential/Universal Role Restriction
                        #  - ValueDomain => Qualified Existential Data Restriction
                        raise SyntaxError('Invalid input to {}: {}'.format(
                            target.name, source.identity.value))

                    if source.item in {
                            Item.DomainRestrictionNode,
                            Item.RangeRestrictionNode, Item.RoleChainNode
                    }:
                        # Exclude incompatible sources: note that while RoleChain has a correct identity
                        # it is excluded because it doesn't represent the OWL 2 ObjectPropertyExpression.
                        raise SyntaxError('Invalid input to {}: {}'.format(
                            target.name, source.name))

                    # SOURCE => CONCEPT EXPRESSION || NEUTRAL

                    if source.identity in {Identity.Concept, Identity.Neutral}:

                        if target.restriction is Restriction.Self:
                            # Not a Qualified Restriction.
                            raise SyntaxError(
                                'Invalid restriction (self) for qualified restriction'
                            )

                        # A Concept can be given as input only if there is no input or if the other input is a Role.
                        node = first(
                            target.incomingNodes(lambda x: x.item is Item.
                                                 InputEdge and x is not edge))
                        if node and node.identity is not Identity.Role:
                            # We found another input on this node which is not a Role
                            # so we can't construct a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError(
                                'Invalid inputs ({} + {}) for qualified restriction'
                                .format(idA, idB))

                    # SOURCE => ROLE EXPRESSION

                    elif source.identity is Identity.Role:

                        # We can connect a Role in input only if there is no other input or if the
                        # other input is a Concept and the node specifies a Qualified Restriction.
                        node = first(
                            target.incomingNodes(lambda x: x.item is Item.
                                                 InputEdge and x is not edge))
                        if node and node.identity is not Identity.Concept:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError(
                                'Invalid inputs ({} + {}) for qualified restriction'
                                .format(idA, idB))

                    # SOURCE => ATTRIBUTE

                    elif source.identity is Identity.Attribute:

                        if target.restriction is Restriction.Self:
                            # Attributes don't have self.
                            raise SyntaxError('Attributes don\'t have self')

                        # We can connect an Attribute in input only if there is no other input or if the
                        # other input is a ValueDomain and the node specifies a Qualified Restriction.
                        node = first(
                            target.incomingNodes(lambda x: x.item is Item.
                                                 InputEdge and x is not edge))
                        if node and node.identity is not Identity.ValueDomain:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError(
                                'Invalid inputs ({} + {}) for qualified restriction'
                                .format(idA, idB))

                    # SOURCE => VALUE-DOMAIN

                    elif source.identity is Identity.ValueDomain:

                        if target.restriction is Restriction.Self:
                            # Not a Qualified Restriction.
                            raise SyntaxError(
                                'Invalid restriction (self) for qualified restriction'
                            )

                        # We can connect a ValueDomain in input only if there is no other input or if the
                        # other input is an Attribute and the node specifies a Qualified Restriction.
                        node = first(
                            target.incomingNodes(lambda x: x.item is Item.
                                                 InputEdge and x is not edge))
                        if node and node.identity is not Identity.Attribute:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError(
                                'Invalid inputs ({} + {}) for qualified restriction'
                                .format(idA, idB))

                elif target.item is Item.RangeRestrictionNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = RANGE RESTRICTION                                                                     #
                    #                                                                                                  #
                    ####################################################################################################

                    if len(
                            target.incomingNodes(
                                lambda x: x.item is Item.InputEdge and x is
                                not edge)) >= 2:
                        # Range Restriction node can have at most 2 inputs.
                        raise SyntaxError('Too many inputs to {}'.format(
                            target.name))

                    supported = {
                        Identity.Concept, Identity.Attribute, Identity.Role,
                        Identity.ValueDomain
                    }
                    if source.identity is not Identity.Neutral and source.identity not in supported:
                        # Range Restriction node takes as input:
                        #  - Role => OWL 2 ObjectPropertyExpression
                        #  - Attribute => OWL 2 DataPropertyExpression
                        #  - Concept => Qualified Existential/Universal Role Restriction
                        #  - ValueDomain => Qualified Existential Data Restriction
                        raise SyntaxError('Invalid input to {}: {}'.format(
                            target.name, source.identity.value))

                    if source.item in {
                            Item.DomainRestrictionNode,
                            Item.RangeRestrictionNode, Item.RoleChainNode
                    }:
                        # Exclude incompatible sources: not that while RoleChain has a correct identity
                        # it is excluded because it doesn't represent the OWL 2 ObjectPropertyExpression.
                        raise SyntaxError('Invalid input to {}: {}'.format(
                            target.name, source.name))

                    # SOURCE => CONCEPT EXPRESSION || NEUTRAL

                    if source.identity in {Identity.Concept, Identity.Neutral}:

                        # We can connect a Concept in input iff there is no other input or if the other input is a Role.
                        node = first(
                            target.incomingNodes(lambda x: x.item is Item.
                                                 InputEdge and x is not edge))
                        if node and node.identity is not Identity.Role:
                            # We found another input on this node which is not a Role
                            # so we can't construct a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError(
                                'Invalid inputs ({} + {}) for qualified restriction'
                                .format(idA, idB))

                    # SOURCE => ROLE EXPRESSION

                    if source.identity is Identity.Role:

                        # We can connect a Role in input only if there is no other input or if the
                        # other input is a Concept and the node specifies a Qualified Restriction.
                        node = first(
                            target.incomingNodes(lambda x: x.item is Item.
                                                 InputEdge and x is not edge))
                        if node and node.identity is not Identity.Concept:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError(
                                'Invalid inputs ({} + {}) for qualified restriction'
                                .format(idA, idB))

                    # SOURCE => ATTRIBUTE NODE

                    elif source.identity is Identity.Attribute:

                        # We can connect an Attribute in input only if there is no other input or if the
                        # other input is a ValueDomain and the node specifies a Qualified Restriction.
                        node = first(
                            target.incomingNodes(lambda x: x.item is Item.
                                                 InputEdge and x is not edge))
                        if node and node.identity is not Identity.ValueDomain:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError(
                                'Invalid inputs ({} + {}) for qualified restriction'
                                .format(idA, idB))

                    # SOURCE => VALUE-DOMAIN

                    elif source.identity is Identity.ValueDomain:

                        # We can connect a ValueDomain in input only if there is no other input or if the
                        # other input is an Attribute and the node specifies a Qualified Restriction.
                        node = first(
                            target.incomingNodes(lambda x: x.item is Item.
                                                 InputEdge and x is not edge))
                        if node and node.identity is not Identity.Attribute:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError(
                                'Invalid inputs ({} + {}) for qualified restriction'
                                .format(idA, idB))

            elif edge.item is Item.InstanceOfEdge:

                ########################################################################################################
                #                                                                                                      #
                #   INSTANCE OF EDGE                                                                                   #
                #                                                                                                      #
                ########################################################################################################

                if source.identity is not Identity.Instance and source.item is not Item.PropertyAssertionNode:
                    # The source of the edge must be one of Instance or a Property Assertion node.
                    raise SyntaxError(
                        'Invalid source for instanceOf edge: {}'.format(
                            source.identity.value))

                if target.identity is not Identity.Concept and target.item not in {
                        Item.RoleNode, Item.RoleInverseNode, Item.AttributeNode
                }:
                    # The target of the edge must be a ClassExpression, ObjectPropertyExpression or DataPropertyExpression.
                    raise SyntaxError(
                        'Invalid target for instanceOf edge: {}'.format(
                            target.name))

                if source.identity is Identity.Instance:

                    if target.identity is not Identity.Concept:
                        # If the source of the edge is an Instance it means that we are trying to construct a
                        # ClassAssertion and so the target of the edge MUST be a class expression.
                        # OWL 2: ClassAssertion(axiomAnnotations ClassExpression Individual)
                        raise SyntaxError(
                            'Invalid target for Concept assertion: {}'.format(
                                target.identity.value))

                if source.item is Item.PropertyAssertionNode:

                    if source.identity is Identity.RoleInstance and target.item not in {
                            Item.RoleNode, Item.RoleInverseNode
                    }:
                        # If the source of the edge is a Role Instance then we MUST target a Role expression.
                        raise SyntaxError(
                            'Invalid target for Role assertion: {}'.format(
                                target.name))

                    if source.identity is Identity.AttributeInstance and target.item is not Item.AttributeNode:
                        # If the source of the edge is an Attribute Instance then we MUST target an Attribute.
                        raise SyntaxError(
                            'Invalid target for Attribute assertion: {}'.
                            format(target.name))

        except SyntaxError as e:
            self._result = ValidationResult(source, edge, target, False, e.msg)
        else:
            self._result = ValidationResult(source, edge, target, True)
示例#22
0
    def buildIndividualNodeMenu(self, mainwindow, scene, node):
        """
        Build and return a QMenu instance for individual nodes.
        :type mainwindow: MainWindow
        :type scene: DiagramScene
        :type node: IndividualNode
        :rtype: QMenu
        """
        menu = self.buildGenericNodeMenu(mainwindow, scene, node)
        menu.insertMenu(mainwindow.actionOpenNodeProperties, mainwindow.menuNodeRefactor)
        menu.insertMenu(mainwindow.actionOpenNodeProperties, mainwindow.menuNodeChangeBrush)
        menu.insertMenu(mainwindow.actionOpenNodeProperties, mainwindow.menuSetIndividualNodeAs)

        ##################################
        ## BEGIN CONSTRAIN IDENTITY SWITCH
        ##################################

        I = True
        V = True

        f1 = lambda x: x.isItem(Item.InputEdge)
        f2 = lambda x: x.isItem(Item.EnumerationNode)
        f3 = lambda x: x.isItem(Item.IndividualNode)
        f4 = lambda x: x.isItem(Item.PropertyAssertionNode)
        f5 = lambda x: x.isItem(Item.InstanceOfEdge)
        f6 = lambda x: x.identity in {Identity.Attribute, Identity.Role}

        enumeration = first(node.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2))

        if enumeration:
            num = len(enumeration.incomingNodes(filter_on_edges=f1, filter_on_nodes=f3))
            I = enumeration.identity is Identity.Concept or num < 2
            V = enumeration.identity is Identity.ValueDomain or num < 2

        assertion = first(node.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f4))
        if assertion:
            operand = first(assertion.outgoingNodes(filter_on_edges=f5, filter_on_nodes=f6))
            if operand:
                if operand.identity is Identity.Role:
                    V = False
                elif operand.identity is Identity.Attribute:
                    num = len(assertion.incomingNodes(filter_on_edges=f1, filter_on_nodes=f3))
                    I = I and (node.identity is Identity.Instance or num < 2)
                    V = V and (node.identity is Identity.Value or num < 2)

        for a in mainwindow.actionsSetIndividualNodeAs:
            a.setVisible(a.data() is Identity.Instance and I or a.data() is Identity.Value and V)

        ################################
        ## END CONSTRAIN IDENTITY SWITCH
        ################################

        # Append label specific actions.
        collection = self.buildNodeLabelSpecificActionSet(mainwindow, scene, node)
        if collection:
            menu.insertSeparator(mainwindow.actionOpenNodeProperties)
            for action in collection:
                menu.insertAction(mainwindow.actionOpenNodeProperties, action)

        menu.insertSeparator(mainwindow.actionOpenNodeProperties)
        return menu
示例#23
0
文件: owl.py 项目: gitter-badger/eddy
    def run(self, source, edge, target):
        """
        Run the validation algorithm on the given triple and generates the ValidationResult instance.
        :type source: AbstractNode
        :type edge: AbstractEdge
        :type target: AbstractNode
        """
        try:

            if source is target:
                # We do not allow the connection if source and target are the same node.
                raise SyntaxError('Self connection is not valid')

            if edge.item is Item.InclusionEdge:

                ########################################################################################################
                #                                                                                                      #
                #   INCLUSION EDGE                                                                                     #
                #                                                                                                      #
                ########################################################################################################

                supported = {Identity.Concept, Identity.Role, Identity.Attribute, Identity.ValueDomain}
                remaining = source.identities & target.identities - {Identity.Neutral, Identity.Unknown}

                if remaining - supported:
                    # Inclusion assertions can be specified only between Graphol expressions: Concept
                    # expressions, Role expressions, Value-Domain expressions, Attribute expressions.
                    raise SyntaxError('Type mismatch: inclusion must involve two graphol expressions')

                if not remaining:
                    # If source and target nodes do not share a common identity then we can't create an inclusion.
                    raise SyntaxError('Type mismatch: {} and {} are not compatible'.format(source.name, target.name))

                if Identity.Neutral not in {source.identity, target.identity} and source.identity is not target.identity:
                    # If both nodes are not NEUTRAL and they specify a different identity we can't create an inclusion.
                    idA = source.identity.value
                    idB = target.identity.value
                    raise SyntaxError('Type mismatch: inclusion between {} and {}'.format(idA, idB))

                if Identity.ValueDomain in {source.identity, target.identity}:

                    # We exclude from the following check inclusion edges sourcing from a RangeRestriction
                    # node since it will be translated into OWL DataPropertyRange that accepts ValueDomain
                    # i.e. complex datatypes and not only atomic ones.
                    if source.item is not Item.RangeRestrictionNode:

                        if source.item is not Item.ValueDomainNode and target.item is not Item.ValueDomainNode:
                            # Inclusion assertions between value-domain expressions must involve at least an atomic
                            # datatype (i.e., the source or the target of the assertion must be an atomic datatype).
                            raise SyntaxError('Inclusion between value-domain expressions must include at least an '
                                              'atomic datatype')

                if source.item is Item.ComplementNode:

                    identity = first({source.identity, target.identity} - {Identity.Neutral})
                    if identity and identity in {Identity.Attribute, Identity.Role}:
                        # Role and attribute expressions whose sink node is a
                        # complement node cannot be the source of any inclusion edge.
                        raise SyntaxError('Invalid source for {} inclusion: {}'.format(identity.value, source.name))

                if target.item is Item.RoleChainNode:
                    # Role expressions constructed with chain nodes cannot be the target of any inclusion edge.
                    raise SyntaxError('Type mismatch: role chain nodes cannot be target of a Role inclusion')

                if source.item is Item.RoleChainNode:
                    # Role expressions constructed with chain nodes can be included only in basic role expressions, that
                    # are either Role nodes or RoleInverse nodes with one input Role node (this check is done elsewhere)
                    if target.item not in {Item.RoleNode, Item.RoleInverseNode}:
                        raise SyntaxError('Inclusion between {} and {} is forbidden'.format(source.name, target.name))

            elif edge.item is Item.InputEdge:

                ########################################################################################################
                #                                                                                                      #
                #   INPUT EDGE                                                                                         #
                #                                                                                                      #
                ########################################################################################################

                if not target.constructor:
                    # Input edges can only target constructor nodes.
                    raise SyntaxError('Input edges can only target constructor nodes')

                if target.item in {Item.ComplementNode, Item.DisjointUnionNode, Item.IntersectionNode, Item.UnionNode}:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET IN { COMPLEMENT, DISJOINT UNION, INTERSECTION, UNION }                                  #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.identity not in target.identities:
                        # Source node identity is not supported by this node despite the currently set identity.
                        raise SyntaxError('Invalid input to {}: {}'.format(target.name, source.identity.value))

                    if source.item is Item.ValueRestrictionNode:
                        # Exclude invalid nodes despite identity matching.
                        raise SyntaxError('Invalid target: {}'.format(target.name))

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = COMPLEMENT                                                                            #
                    #                                                                                                  #
                    ####################################################################################################

                    if target.item is Item.ComplementNode:

                        if len(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge)) > 0:
                            # The Complement operator may have at most one node connected to it.
                            raise SyntaxError('Too many inputs to {}'.format(target.name))

                        if source.item in {Item.RoleNode, Item.RoleInverseNode, Item.AttributeNode}:

                            # See if the source of the node matches an ObjectPropertyExpression ({Role, RoleInv}) or a
                            # DataPropertyExpression (Attribute). If that's the case check for the node not to have any
                            # outgoing Input edge: the only supported expression are NegativeObjectPropertyAssertion,
                            # R1 ISA NOT R2, and NegativeDataPropertyAssertion, A1 ISA NOT A2. This prevents the
                            # connection of Role expressions to Complement nodes that are given as inputs to Enumeration,
                            # Union and Disjoint Union operatore nodes.
                            if len(target.incomingNodes(lambda x: x.item is Item.InputEdge and x.source is target)) > 0:
                                raise SyntaxError('Invalid negative {} expression'.format(source.identity.value))

                    else:

                        ################################################################################################
                        #                                                                                              #
                        #   TARGET IN { DISJOINT UNION, INTERSECTION, UNION }                                          #
                        #                                                                                              #
                        ################################################################################################

                        if Identity.Neutral not in {source.identity, target.identity}:

                            if source.identity is not target.identity:
                                # Union/Intersection between different type of graphol expressions.
                                idA = source.identity.value
                                idB = target.identity.value
                                composition = cutR(target.name, ' node')
                                raise SyntaxError('Type mismatch: {} between {} and {}'.format(composition, idA, idB))

                elif target.item is Item.EnumerationNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = ENUMERATION                                                                           #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.item is not Item.IndividualNode:
                        # Enumeration operator (oneOf) takes as inputs instances or values, both represented
                        # by the Individual node, and has the job of composing a set if individuals (either Concept
                        # or ValueDomain, but not both together).
                        name = source.identity.value if source.identity is not Identity.Neutral else source.name
                        raise SyntaxError('Invalid input to {}: {}'.format(target.name, name))

                    if target.identity is Identity.Unknown:
                        # Target node has an unkown identity: we do not allow the connection => the user MUST fix the
                        # error first and then try to create again the connection (this should never happen actually).
                        raise SyntaxError('Target node has an invalid identity: {}'.format(target.identity.value))

                    if target.identity is not Identity.Neutral:

                        if source.identity is Identity.Instance and target.identity is Identity.ValueDomain:
                            raise SyntaxError('Invalid input to {}: {}'.format(target.name, source.identity.value))

                        if source.identity is Identity.Value and target.identity is Identity.Concept:
                            raise SyntaxError('Invalid input to {}: {}'.format(target.name, source.identity.value))

                elif target.item is Item.RoleInverseNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = ROLE INVERSE                                                                          #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.item is not Item.RoleNode:
                        # The Role Inverse operator takes as input a role and constructs its inverse by switching
                        # domain and range of the role. Assume to have a Role labelled 'is_owner_of' whose instances
                        # are {(o1,o2), (o1,o3), (o4,o5)}: connecting this Role in input to a Role Inverse node will
                        # construct a new Role whose instances are {(o2,o1), (o3,o1), (o5,o4)}.
                        raise SyntaxError('Role Inverse accepts only a Role node as input')

                    if len(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge)) > 0:
                        # The Role Inverse operator may have at most one Role node connected to it: if we need to
                        # define multiple Role inverse we would need to use multiple Role Inverse operator nodes.
                        raise SyntaxError('Too many inputs to {}'.format(target.name))

                elif target.item is Item.RoleChainNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = ROLE CHAIN                                                                            #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.item not in {Item.RoleNode, Item.RoleInverseNode}:
                        # The Role Chain operator constructs a concatenation of roles. Assume to have 2 Role nodes
                        # defined as 'lives_in_region' and 'region_in_country': if {(o1, o2), (o3, o4)} is the
                        # instance of 'lives_in_region' and {(o2, o6)} is the instance of 'region_in_country', then
                        # {(o1, o6)} is the instance of the chain, which would match another Role 'lives_in_country'.
                        # ObjectPropertyExpression := ObjectProperty | InverseObjectProperty => we need to match only
                        # Role nodes and Role Inverse nodes as sources of our edge (it's not possible to create a chain
                        # of chains, despite the identity matches Role in both expressions).
                        raise SyntaxError('Invalid input to {}: {}'.format(target.name, source.name))

                elif target.item is Item.DatatypeRestrictionNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = DATATYPE RESTRICTION                                                                  #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.item not in {Item.ValueDomainNode, Item.ValueRestrictionNode}:
                        # The DatatypeRestriction node is used to compose complex datatypes and
                        # accepts as inputs one value-domain node and n >= 1 value-restriction
                        # nodes to compose the OWL 2 equivalent DatatypeRestriction.
                        raise SyntaxError('Invalid input to {}: {}'.format(target.name, source.name))

                    if source.item is Item.ValueDomainNode:

                        f1 = lambda x: x.item is Item.InputEdge and x is not edge
                        f2 = lambda x: x.item is Item.ValueDomainNode
                        if len(target.incomingNodes(filter_on_edges=f1, filter_on_nodes=f2)) > 0:
                            # The value-domain has already been attached to the DatatypeRestriction.
                            raise SyntaxError('Too many value-domain nodes in input to {}'.format(target.name))

                    # We need to check whether the DatatypeRestriction node has already datatype
                    # inferred: if that's the case and the datatype doesn't match the datatype of
                    # the source node, we deny the connection to prevent inconsistencies.
                    f1 = lambda x: x.item is Item.InputEdge and x is not edge
                    f2 = lambda x: x.item in {Item.ValueDomainNode, Item.ValueRestrictionNode} and x is not source
                    collection = target.incomingNodes(filter_on_edges=f1, filter_on_nodes=f2)
                    if collection:
                        datatype = first(collection).datatype
                        if  datatype is not source.datatype:
                            d1 = source.datatype.value
                            d2 = datatype.value
                            raise SyntaxError('Datatype mismatch: restriction between {} and {}'.format(d1, d2))

                elif target.item is Item.PropertyAssertionNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = PROPERTY ASSERTION                                                                    #
                    #                                                                                                  #
                    ####################################################################################################

                    if source.item is not Item.IndividualNode:
                        # Property Assertion operators accepts only Individual nodes as input: they are
                        # used to construct ObjectPropertyAssertion and DataPropertyAssertion axioms.
                        raise SyntaxError('Invalid input to {}: {}'.format(target.name, source.identity.value))

                    if len(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge)) >= 2:
                        # At most 2 Individual nodes can be connected to a PropertyAssertion node. As an example
                        # we can construct ObjectPropertyAssertion(presiede M.Draghi BCE) where the individuals
                        # are identified by M.Draghi and BCE, or DataPropertyAssertion(nome M.Draghi "Mario") where
                        # the individuals are identified by M.Draghi and "Mario".
                        raise SyntaxError('Too many inputs to {}'.format(target.name))

                    if target.identity is Identity.RoleInstance:

                        if source.identity is Identity.Value:
                            # We are constructing an ObjectPropertyAssertion expression so we can't connect a Value.
                            raise SyntaxError('Invalid input to {}: Value'.format(target.identity.value))

                    if target.identity is Identity.AttributeInstance:

                        if source.identity is Identity.Instance:

                            f1 = lambda x: x.item is Item.InputEdge and x is not edge
                            f2 = lambda x: x.identity is Identity.Instance
                            if len(target.incomingNodes(filter_on_edges=f1, filter_on_nodes=f2)) > 0:
                                # We are constructing a DataPropertyAssertion and so we can't have more than 1 instance.
                                raise SyntaxError('Too many instances in input to {}'.format(target.identity.value))

                        if source.identity is Identity.Value:

                            f1 = lambda x: x.item is Item.InputEdge and x is not edge
                            f2 = lambda x: x.identity is Identity.Value
                            if len(target.incomingNodes(filter_on_edges=f1, filter_on_nodes=f2)) > 0:
                                # At most one Literal can be given as input (2 instance | 1 instance + 1 value)
                                raise SyntaxError('Too many values in input to {}'.format(target.identity.value))

                elif target.item is Item.DomainRestrictionNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = DOMAIN RESTRICTION                                                                    #
                    #                                                                                                  #
                    ####################################################################################################

                    if len(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge)) >= 2:
                        # Domain Restriction node can have at most 2 inputs.
                        raise SyntaxError('Too many inputs to {}'.format(target.name))

                    supported = {Identity.Concept, Identity.Attribute, Identity.Role, Identity.ValueDomain}
                    if source.identity is not Identity.Neutral and source.identity not in supported:
                        # Domain Restriction node takes as input:
                        #  - Role => OWL 2 ObjectPropertyExpression
                        #  - Attribute => OWL 2 DataPropertyExpression
                        #  - Concept => Qualified Existential/Universal Role Restriction
                        #  - ValueDomain => Qualified Existential Data Restriction
                        raise SyntaxError('Invalid input to {}: {}'.format(target.name, source.identity.value))

                    if source.item in {Item.DomainRestrictionNode, Item.RangeRestrictionNode, Item.RoleChainNode}:
                        # Exclude incompatible sources: note that while RoleChain has a correct identity
                        # it is excluded because it doesn't represent the OWL 2 ObjectPropertyExpression.
                        raise SyntaxError('Invalid input to {}: {}'.format(target.name, source.name))

                    # SOURCE => CONCEPT EXPRESSION || NEUTRAL

                    if source.identity in {Identity.Concept, Identity.Neutral}:

                        if target.restriction is Restriction.Self:
                            # Not a Qualified Restriction.
                            raise SyntaxError('Invalid restriction (self) for qualified restriction')

                        # A Concept can be given as input only if there is no input or if the other input is a Role.
                        node = first(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge))
                        if node and node.identity is not Identity.Role:
                            # We found another input on this node which is not a Role
                            # so we can't construct a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError('Invalid inputs ({} + {}) for qualified restriction'.format(idA, idB))

                    # SOURCE => ROLE EXPRESSION

                    elif source.identity is Identity.Role:

                        # We can connect a Role in input only if there is no other input or if the
                        # other input is a Concept and the node specifies a Qualified Restriction.
                        node = first(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge))
                        if node and node.identity is not Identity.Concept:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError('Invalid inputs ({} + {}) for qualified restriction'.format(idA, idB))

                    # SOURCE => ATTRIBUTE

                    elif source.identity is Identity.Attribute:

                        if target.restriction is Restriction.Self:
                            # Attributes don't have self.
                            raise SyntaxError('Attributes don\'t have self')

                        # We can connect an Attribute in input only if there is no other input or if the
                        # other input is a ValueDomain and the node specifies a Qualified Restriction.
                        node = first(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge))
                        if node and node.identity is not Identity.ValueDomain:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError('Invalid inputs ({} + {}) for qualified restriction'.format(idA, idB))

                    # SOURCE => VALUE-DOMAIN

                    elif source.identity is Identity.ValueDomain:

                        if target.restriction is Restriction.Self:
                            # Not a Qualified Restriction.
                            raise SyntaxError('Invalid restriction (self) for qualified restriction')

                        # We can connect a ValueDomain in input only if there is no other input or if the
                        # other input is an Attribute and the node specifies a Qualified Restriction.
                        node = first(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge))
                        if node and node.identity is not Identity.Attribute:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError('Invalid inputs ({} + {}) for qualified restriction'.format(idA, idB))

                elif target.item is Item.RangeRestrictionNode:

                    ####################################################################################################
                    #                                                                                                  #
                    #   TARGET = RANGE RESTRICTION                                                                     #
                    #                                                                                                  #
                    ####################################################################################################

                    if len(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge)) >= 2:
                        # Range Restriction node can have at most 2 inputs.
                        raise SyntaxError('Too many inputs to {}'.format(target.name))

                    supported = {Identity.Concept, Identity.Attribute, Identity.Role, Identity.ValueDomain}
                    if source.identity is not Identity.Neutral and source.identity not in supported:
                        # Range Restriction node takes as input:
                        #  - Role => OWL 2 ObjectPropertyExpression
                        #  - Attribute => OWL 2 DataPropertyExpression
                        #  - Concept => Qualified Existential/Universal Role Restriction
                        #  - ValueDomain => Qualified Existential Data Restriction
                        raise SyntaxError('Invalid input to {}: {}'.format(target.name, source.identity.value))

                    if source.item in {Item.DomainRestrictionNode, Item.RangeRestrictionNode, Item.RoleChainNode}:
                        # Exclude incompatible sources: not that while RoleChain has a correct identity
                        # it is excluded because it doesn't represent the OWL 2 ObjectPropertyExpression.
                        raise SyntaxError('Invalid input to {}: {}'.format(target.name, source.name))

                    # SOURCE => CONCEPT EXPRESSION || NEUTRAL

                    if source.identity in {Identity.Concept, Identity.Neutral}:

                        # We can connect a Concept in input iff there is no other input or if the other input is a Role.
                        node = first(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge))
                        if node and node.identity is not Identity.Role:
                            # We found another input on this node which is not a Role
                            # so we can't construct a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError('Invalid inputs ({} + {}) for qualified restriction'.format(idA, idB))

                    # SOURCE => ROLE EXPRESSION

                    if source.identity is Identity.Role:

                        # We can connect a Role in input only if there is no other input or if the
                        # other input is a Concept and the node specifies a Qualified Restriction.
                        node = first(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge))
                        if node and node.identity is not Identity.Concept:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError('Invalid inputs ({} + {}) for qualified restriction'.format(idA, idB))

                    # SOURCE => ATTRIBUTE NODE

                    elif source.identity is Identity.Attribute:

                        # We can connect an Attribute in input only if there is no other input or if the
                        # other input is a ValueDomain and the node specifies a Qualified Restriction.
                        node = first(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge))
                        if node and node.identity is not Identity.ValueDomain:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError('Invalid inputs ({} + {}) for qualified restriction'.format(idA, idB))

                    # SOURCE => VALUE-DOMAIN

                    elif source.identity is Identity.ValueDomain:

                        # We can connect a ValueDomain in input only if there is no other input or if the
                        # other input is an Attribute and the node specifies a Qualified Restriction.
                        node = first(target.incomingNodes(lambda x: x.item is Item.InputEdge and x is not edge))
                        if node and node.identity is not Identity.Attribute:
                            # Not a Qualified Restriction.
                            idA = source.identity.value
                            idB = node.identity.value
                            raise SyntaxError('Invalid inputs ({} + {}) for qualified restriction'.format(idA, idB))

            elif edge.item is Item.InstanceOfEdge:

                ########################################################################################################
                #                                                                                                      #
                #   INSTANCE OF EDGE                                                                                   #
                #                                                                                                      #
                ########################################################################################################

                if source.identity is not Identity.Instance and source.item is not Item.PropertyAssertionNode:
                    # The source of the edge must be one of Instance or a Property Assertion node.
                    raise SyntaxError('Invalid source for instanceOf edge: {}'.format(source.identity.value))

                if target.identity is not Identity.Concept and target.item not in {Item.RoleNode, Item.RoleInverseNode, Item.AttributeNode}:
                    # The target of the edge must be a ClassExpression, ObjectPropertyExpression or DataPropertyExpression.
                    raise SyntaxError('Invalid target for instanceOf edge: {}'.format(target.name))

                if source.identity is Identity.Instance:

                    if target.identity is not Identity.Concept:
                        # If the source of the edge is an Instance it means that we are trying to construct a
                        # ClassAssertion and so the target of the edge MUST be a class expression.
                        # OWL 2: ClassAssertion(axiomAnnotations ClassExpression Individual)
                        raise SyntaxError('Invalid target for Concept assertion: {}'.format(target.identity.value))

                if source.item is Item.PropertyAssertionNode:

                    if source.identity is Identity.RoleInstance and target.item not in {Item.RoleNode, Item.RoleInverseNode}:
                        # If the source of the edge is a Role Instance then we MUST target a Role expression.
                        raise SyntaxError('Invalid target for Role assertion: {}'.format(target.name))

                    if source.identity is Identity.AttributeInstance and target.item is not Item.AttributeNode:
                        # If the source of the edge is an Attribute Instance then we MUST target an Attribute.
                        raise SyntaxError('Invalid target for Attribute assertion: {}'.format(target.name))

        except SyntaxError as e:
            self._result = ValidationResult(source, edge, target, False, e.msg)
        else:
            self._result = ValidationResult(source, edge, target, True)