Skip to content

Commit c5eae5f

Browse files
committed
improving patterns documentation
1 parent 6252d74 commit c5eae5f

4 files changed

Lines changed: 37 additions & 83 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- improved documentation.
1414

1515
### Removed
16+
- function patterns.edge_matches_pattern.
1617

1718
## [0.8.0] - 26-03-2026 - hyperbase is the successor of graphbrain
1819

docs/manual/api.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@
88

99
::: hyperbase.hyperedge
1010

11-
## Patterns module
12-
13-
::: hyperbase.patterns
14-
1511
## Parsers module
1612

1713
::: hyperbase.parsers

docs/manual/patterns.md

Lines changed: 36 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -60,118 +60,96 @@ but this pattern does:
6060
(plays/P * * ...)
6161
```
6262

63-
## Non-strict search
63+
## Type and subtype matching
6464

65-
Non-strict search allows for patterns to match atoms in the most general way, meaning that, if a subtype or other roles are not specified in the pattern, then any subtypes or argroles will match, as can be seen in this example:
65+
If only a type but not a subtype is specified in the pattern, then any subtypes of the given type will match, as can be seen in this example:
6666

67-
```pycon
68-
>>> from hyperbase import *
69-
>>> hg = hgraph('example.db')
70-
>>> hg.add('(plays/Pd.so alice/Cp.s chess/Cc.s)')
71-
(plays/Pd.so alice/Cp.s chess/Cc.s)
72-
>>> list(hg.search('(plays/P alice/C *)', strict=False))
73-
[(plays/Pd.so alice/Cp.s chess/Cc.s)]
67+
```python
68+
from hyperbase import hedge
69+
pattern = hedge("(plays/P.so */C */C)")
70+
edge = hedge("(plays/Pd.so alice/Cp chess/Cc)")
71+
edge.match(pattern) # returns [{}]
7472
```
7573

76-
Even though the full type and roles of `plays/Pd.so` and `alice/Cp.s` are not specified in the pattern, they still match the more general corresponding atoms `plays/P` and `alice/C`.
77-
78-
Non-strict search is semantically more powerful, at the expense of performance. Strict search can take advantage of the structure of the hypergraph database to perform fast queries, while non-strict search iterates through all edges in the hypergraph looking for matches.
74+
Even though the full types of `plays/Pd.so`, `alice/Cp` and `chess/Cc` are not specified in the pattern, they still match the more general corresponding atoms `plays/P.so` and `*/C`.
7975

8076
## Matching argroles
8177

82-
Argroles can be specified in patterns. So:
78+
As we have seen, argroles can be specified in patterns. So:
8379

84-
```
80+
```clojure
8581
(plays/P.so * *)
8682
```
8783

8884
matches:
8985

90-
```
86+
```clojure
9187
(plays/P.so alice/C chess/C)
9288
```
9389

9490
but not:
9591

96-
```
92+
```clojure
9793
(plays/P.sox alice/C chess/C (at/T (the/M club/C)))
9894
```
9995

10096
It is often desirable to match for the presence of a given set of argroles, independently of their respective positions, or of the presence of further argroles outside the set. This is indicated by surrounding with curly brackets the set of argroles that is to be matched in this way. For example:
10197

102-
```
98+
```clojure
10399
(is/P.{sc} * */C)
104100
```
105101

106102
The above pattern would match both (independently of position):
107103

108-
```
104+
```clojure
109105
(is/P.sc (the/M sky/C) blue/C)
110106
(is/P.cs blue/C (the/M sky/C))
111107
```
112108

113109
and also (independently of the presence of further argroles outside the set):
114110

115-
```
111+
```clojure
116112
(is/P.scx (the/M sky/C) blue/C (in/T (the/M morning/C)))
117113
```
118114

119115
In fact, when specifying argroles, more often than not this is the behavior that is the most useful, because it allows for the matching of the participants of a relationship purely according to the role they play in it (subject, object, etc.).
120116

121117
Sometimes it is also desirable to explicitly forbid certain argument roles. This is achieved by indicating them after '-' in the argrole sequence. For example:
122118

123-
```
119+
```clojure
124120
(plays/P.{so}-x * *)
125121
```
126122

127123
does not match:
128124

129-
```
125+
```clojure
130126
(plays/P.sox alice/C chess/C (at/T (the/M club/C)))
131127
```
132128

133-
When using `Hypergraph.search()`, order-independent (curly-braces) and argrole exclusions (-) only work in non-strict mode.
134-
135129
## Patterns with variables for information extraction
136130

137131
Let us introduce the concept of *variable*. Like a wildcard, a variable indicates a placeholder that can match a hyperedge, but can then be used to refer to that matched hyperedge. In SH representation, an atom label that starts with upper case represents a variable. For example: `PLAYER/C`. One can define perfectly valid hyperedges that include variables, as well as wildcards, so for example:
138132

139-
```
133+
```clojure
140134
(plays/P.{so} PLAYER/C *)
141135
```
142136

143-
Then the `match_pattern(edge, pattern)` function can be used to apply patterns to edges. It works like this:
137+
Then `edge.match(pattern)` can be used to apply patterns to edges. It works like this:
144138

145-
```pycon
146-
>>> from hyperbase import hedge
147-
>>> from hyperbase.patterns import match_pattern
148-
>>> pattern = hedge('(plays/P.{so} PLAYER/C *)')
149-
>>> edge = hedge('(plays/P.so mary/C *)')
150-
>>> match_pattern(edge, pattern)
151-
[{'PLAYER': mary/C}]
152-
```
153-
154-
So, `match_pattern` gives a list of dictionaries (one pattern can match the same edge in several ways). Each dictionary represents a match, and assigns a value to a variable.
155-
156-
The `Hypergraph` object provides the `match()` method, which is similar to `search()` but returns dictionaries with the matched variables. Like search, it offers a non-strict mode with the same trade-offs:
157-
158-
```pycon
159-
>>> hg.add('(is/Pd.cs blue/Ca (the/M sky/C))')
160-
(is/Pd.cs blue/Ca (the/M sky/C))
161-
>>> hg.add('(is/Pd.sc (the/M sky/C) blue/Ca)')
162-
(is/Pd.sc (the/M sky/C) blue/Ca)
163-
>>> list(hg.match('(is/P.{sc} OBJ/C PROP)', strict=False))
164-
[((is/Pd.cs blue/Ca (the/M sky/C)), [{'OBJ': (the/M sky/C), 'PROP': blue/Ca}]),
165-
((is/Pd.sc (the/M sky/C) blue/Ca), [{'OBJ': (the/M sky/C), 'PROP': blue/Ca}])]
139+
```python
140+
from hyperbase import hedge
141+
pattern = hedge("(plays/P.{so} PLAYER/C *)")
142+
edge = hedge("(plays/P.so mary/C *)")
143+
edge.match(pattern) # [{'PLAYER': mary/C}]
166144
```
167145

168-
The output is a list of tuples, where the first item is the matched hyperedge and the second is a dictionary with variables and their values.
146+
So, `edge.match(pattern)` gives a list of dictionaries (one pattern can match the same edge in several ways). Each dictionary represents a match, and assigns values to the pattern variable(s).
169147

170148
## Functional patterns
171149

172-
Even more sophisticated patterns can be represented with the help of functional pattern expressions. These expressions are akin to function application in LISP-like languages, and take the general form:
150+
More sophisticated patterns can be represented with the help of functional pattern expressions. These expressions are akin to function application in LISP-like languages, and take the general form:
173151

174-
```
152+
```clojure
175153
(functional-pattern-name argument_1 ...)
176154
```
177155

@@ -182,76 +160,56 @@ Even more sophisticated patterns can be represented with the help of functional
182160

183161
The `atoms` functional pattern matches any edge that contains all the atoms provided as arguments, at any depth:
184162

185-
```
163+
```clojure
186164
(atoms atom_1 ...)
187165
```
188166

189167
For example this pattern:
190168

191-
```
169+
```clojure
192170
(atoms going/P)
193171
```
194172

195173
would match the edge:
196174

197-
```
175+
```clojure
198176
(is/M (not/M going/P))
199177
```
200178

201179
In the same vein, this pattern:
202180

203-
```
181+
```clojure
204182
(atoms not/M going/P)
205183
```
206184

207185
would equally match the edge:
208186

209-
```
187+
```clojure
210188
(is/M (not/M going/P))
211189
```
212190

213191
but not:
214192

215-
```
193+
```clojure
216194
(is/M going/P)
217195
```
218196

219197
Furthermore, the atoms can define wildcards and all the pattern syntax specified above, for example:
220198

221-
```
199+
```clojure
222200
(atoms not/M */P)
223201
```
224202

225-
### Lemma
226-
227-
The `lemma` functional pattern matches any atom which has the same lemma as the one specified. This functional pattern only works in the context of a hypergraph database that contains lemma information, that can be generated by the parsers provided with hyperbase.
228-
229-
For example, this pattern:
230-
231-
```
232-
(lemma be/P)
233-
```
234-
235-
could be used to match:
236-
237-
```
238-
is/P
239-
was/P
240-
```
241-
242-
!!! note
243-
When using `lemma`, it is necessary to specify some semantic hypergraph object when calling the pattern matching function: `match_pattern(edge, pattern, hg=hg)`.
244-
245203
### Var
246204

247205
The `var` functional pattern is used to specify a part of a pattern while also capturing it as a variable. It has the general form:
248206

249-
```
207+
```clojure
250208
(var pattern-edge variable-name)
251209
```
252210

253211
This way, a complex expression such as the following can be captured in a variable:
254212

255-
```
213+
```clojure
256214
(var (atoms not/M (lemma be/P)) PREDICATE)
257215
```

mkdocs.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ nav:
6666
- Notation: manual/notation.md
6767
- Hyperedge Operations: manual/hyperedge-operations.md
6868
- Patterns: manual/patterns.md
69-
- Discovering Patterns: manual/discovering-patterns.md
7069
- Parsing: manual/parsing.md
7170
- API Reference: manual/api.md
7271
- Authors: authors.md

0 commit comments

Comments
 (0)