# Path: pattern/graph/commonsense.py
# class Commonsense(Graph):
# 
#     def __init__(self, data=os.path.join(MODULE, "commonsense.csv"), **kwargs):
#         """ A semantic network of commonsense, using different relation types:
#             - is-a,
#             - is-part-of,
#             - is-opposite-of,
#             - is-property-of,
#             - is-related-to,
#             - is-same-as,
#             - is-effect-of.
#         """
#         Graph.__init__(self, **kwargs)
#         self._properties = None
#         # Load data from the given path,
#         # a CSV-file of (concept1, relation, concept2, context, weight)-items.
#         if data is not None:
#             s = open(data, encoding = 'utf-8').read()
#             s = s.strip(BOM_UTF8)
#             s = ((v.strip("\"") for v in r.split(",")) for r in s.splitlines())
#             for concept1, relation, concept2, context, weight in s:
#                 self.add_edge(concept1, concept2,
#                     type = relation,
#                  context = context,
#                   weight = min(int(weight) * 0.1, 1.0))
# 
#     @property
#     def concepts(self):
#         return self.nodes
# 
#     @property
#     def relations(self):
#         return self.edges
# 
#     @property
#     def properties(self):
#         """ Yields all concepts that are properties (i.e., adjectives).
#             For example: "cold is-property-of winter" => "cold".
#         """
#         if self._properties is None:
#             #self._properties = set(e.node1.id for e in self.edges if e.type == "is-property-of")
#             self._properties = (e for e in self.edges if e.context == "properties")
#             self._properties = set(chain(*((e.node1.id, e.node2.id) for e in self._properties)))
#         return self._properties
# 
#     def add_node(self, id, *args, **kwargs):
#         """ Returns a Concept (Node subclass).
#         """
#         self._properties = None
#         kwargs.setdefault("base", Concept)
#         return Graph.add_node(self, id, *args, **kwargs)
# 
#     def add_edge(self, id1, id2, *args, **kwargs):
#         """ Returns a Relation between two concepts (Edge subclass).
#         """
#         self._properties = None
#         kwargs.setdefault("base", Relation)
#         return Graph.add_edge(self, id1, id2, *args, **kwargs)
# 
#     def remove(self, x):
#         self._properties = None
#         Graph.remove(self, x)
# 
#     def similarity(self, concept1, concept2, k=3, heuristic=COMMONALITY):
#         """ Returns the similarity of the given concepts,
#             by cross-comparing shortest path distance between k concept properties.
#             A given concept can also be a flat list of properties, e.g. ["creepy"].
#             The given heuristic is a tuple of two functions:
#             1) function(concept) returns a list of salient properties,
#             2) function(edge) returns the cost for traversing this edge (0.0-1.0).
#         """
#         if isinstance(concept1, str):
#             concept1 = self[concept1]
#         if isinstance(concept2, str):
#             concept2 = self[concept2]
#         if isinstance(concept1, Node):
#             concept1 = heuristic[0](concept1)
#         if isinstance(concept2, Node):
#             concept2 = heuristic[0](concept2)
#         if isinstance(concept1, list):
#             concept1 = [isinstance(n, Node) and n or self[n] for n in concept1]
#         if isinstance(concept2, list):
#             concept2 = [isinstance(n, Node) and n or self[n] for n in concept2]
#         h = lambda id1, id2: heuristic[1](self.edge(id1, id2))
#         w = 0.0
#         for p1 in concept1[:k]:
#             for p2 in concept2[:k]:
#                 p = self.shortest_path(p1, p2, heuristic=h)
#                 w += 1.0 / (p is None and 1e10 or len(p))
#         return w / k
# 
#     def nearest_neighbors(self, concept, concepts=[], k=3):
#         """ Returns the k most similar concepts from the given list.
#         """
#         return sorted(concepts, key=lambda candidate: self.similarity(concept, candidate, k), reverse=True)
# 
#     similar = neighbors = nn = nearest_neighbors
# 
#     def taxonomy(self, concept, depth=3, fringe=2):
#         """ Returns a list of concepts that are descendants of the given concept, using "is-a" relations.
#             Creates a subgraph of "is-a" related concepts up to the given depth,
#             then takes the fringe (i.e., leaves) of the subgraph.
#         """
#         def traversable(node, edge):
#             # Follow parent-child edges.
#             return edge.node2 == node and edge.type == "is-a"
#         if not isinstance(concept, Node):
#             concept = self[concept]
#         g = self.copy(nodes=concept.flatten(depth, traversable))
#         g = g.fringe(depth=fringe)
#         g = [self[n.id] for n in g if n != concept]
#         return g
# 
#     field = semantic_field = taxonomy


from builtins import str, bytes, dict, int
from pattern.graph.commonsense import Commonsense
import os
import sys
from __future__ import print_function
from __future__ import unicode_literals


sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))


# A semantic network is a graph in which each node represents a concept
# (e.g., flower, red, rose) and each edge represents a relation between
# concepts, for example rose is-a flower, red is-property-of rose.

# Module pattern.graph.commonsense implements a semantic network of commonsense.
# It contains a Concept class (Node subclass), Relation class (Edge subclass),
# and a Commonsense class (Graph subclass).
# It contains about 10,000 manually annotated relations between mundane concepts,
# for example gondola is-related-to romance, or spoon is-related-to soup.
# This is the PERCEPTION dataset. See the visualizer at:
# http://nodebox.net/perception/

# Relation.type can be:
# - is-a,
# - is-part-of,
# - is-opposite-of,
# - is-property-of,
# - is-related-to,
# - is-same-as,
# - is-effect-of.


# Path: pattern/graph/commonsense.py
# class Commonsense(Graph):
# 
#     def __init__(self, data=os.path.join(MODULE, "commonsense.csv"), **kwargs):
#         """ A semantic network of commonsense, using different relation types:
#             - is-a,
#             - is-part-of,
#             - is-opposite-of,
#             - is-property-of,
#             - is-related-to,
#             - is-same-as,
#             - is-effect-of.
#         """
#         Graph.__init__(self, **kwargs)
#         self._properties = None
#         # Load data from the given path,
#         # a CSV-file of (concept1, relation, concept2, context, weight)-items.
#         if data is not None:
#             s = open(data, encoding = 'utf-8').read()
#             s = s.strip(BOM_UTF8)
#             s = ((v.strip("\"") for v in r.split(",")) for r in s.splitlines())
#             for concept1, relation, concept2, context, weight in s:
#                 self.add_edge(concept1, concept2,
#                     type = relation,
#                  context = context,
#                   weight = min(int(weight) * 0.1, 1.0))
# 
#     @property
#     def concepts(self):
#         return self.nodes
# 
#     @property
#     def relations(self):
#         return self.edges
# 
#     @property
#     def properties(self):
#         """ Yields all concepts that are properties (i.e., adjectives).
#             For example: "cold is-property-of winter" => "cold".
#         """
#         if self._properties is None:
#             #self._properties = set(e.node1.id for e in self.edges if e.type == "is-property-of")
#             self._properties = (e for e in self.edges if e.context == "properties")
#             self._properties = set(chain(*((e.node1.id, e.node2.id) for e in self._properties)))
#         return self._properties
# 
#     def add_node(self, id, *args, **kwargs):
#         """ Returns a Concept (Node subclass).
#         """
#         self._properties = None
#         kwargs.setdefault("base", Concept)
#         return Graph.add_node(self, id, *args, **kwargs)
# 
#     def add_edge(self, id1, id2, *args, **kwargs):
#         """ Returns a Relation between two concepts (Edge subclass).
#         """
#         self._properties = None
#         kwargs.setdefault("base", Relation)
#         return Graph.add_edge(self, id1, id2, *args, **kwargs)
# 
#     def remove(self, x):
#         self._properties = None
#         Graph.remove(self, x)
# 
#     def similarity(self, concept1, concept2, k=3, heuristic=COMMONALITY):
#         """ Returns the similarity of the given concepts,
#             by cross-comparing shortest path distance between k concept properties.
#             A given concept can also be a flat list of properties, e.g. ["creepy"].
#             The given heuristic is a tuple of two functions:
#             1) function(concept) returns a list of salient properties,
#             2) function(edge) returns the cost for traversing this edge (0.0-1.0).
#         """
#         if isinstance(concept1, str):
#             concept1 = self[concept1]
#         if isinstance(concept2, str):
#             concept2 = self[concept2]
#         if isinstance(concept1, Node):
#             concept1 = heuristic[0](concept1)
#         if isinstance(concept2, Node):
#             concept2 = heuristic[0](concept2)
#         if isinstance(concept1, list):
#             concept1 = [isinstance(n, Node) and n or self[n] for n in concept1]
#         if isinstance(concept2, list):
#             concept2 = [isinstance(n, Node) and n or self[n] for n in concept2]
#         h = lambda id1, id2: heuristic[1](self.edge(id1, id2))
#         w = 0.0
#         for p1 in concept1[:k]:
#             for p2 in concept2[:k]:
#                 p = self.shortest_path(p1, p2, heuristic=h)
#                 w += 1.0 / (p is None and 1e10 or len(p))
#         return w / k
# 
#     def nearest_neighbors(self, concept, concepts=[], k=3):
#         """ Returns the k most similar concepts from the given list.
#         """
#         return sorted(concepts, key=lambda candidate: self.similarity(concept, candidate, k), reverse=True)
# 
#     similar = neighbors = nn = nearest_neighbors
# 
#     def taxonomy(self, concept, depth=3, fringe=2):
#         """ Returns a list of concepts that are descendants of the given concept, using "is-a" relations.
#             Creates a subgraph of "is-a" related concepts up to the given depth,
#             then takes the fringe (i.e., leaves) of the subgraph.
#         """
#         def traversable(node, edge):
#             # Follow parent-child edges.
#             return edge.node2 == node and edge.type == "is-a"
#         if not isinstance(concept, Node):
#             concept = self[concept]
#         g = self.copy(nodes=concept.flatten(depth, traversable))
#         g = g.fringe(depth=fringe)
#         g = [self[n.id] for n in g if n != concept]
#         return g
# 
#     field = semantic_field = taxonomy


# Path: examples/06-graph/06-commonsense.py
from builtins import str, bytes, dict, int
from pattern.graph.commonsense import Commonsense
import os
import sys

from __future__ import print_function
from __future__ import unicode_literals


sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))


# A semantic network is a graph in which each node represents a concept
# (e.g., flower, red, rose) and each edge represents a relation between
# concepts, for example rose is-a flower, red is-property-of rose.

# Module pattern.graph.commonsense implements a semantic network of commonsense.
# It contains a Concept class (Node subclass), Relation class (Edge subclass),
# and a Commonsense class (Graph subclass).
# It contains about 10,000 manually annotated relations between mundane concepts,
# for example gondola is-related-to romance, or spoon is-related-to soup.
# This is the PERCEPTION dataset. See the visualizer at:
# http://nodebox.net/perception/

# Relation.type can be:
# - is-a,
# - is-part-of,
# - is-opposite-of,
# - is-property-of,
# - is-related-to,
# - is-same-as,
# - is-effect-of.


g = Commonsense()