c2score 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. c2score-0.1.0/.github/workflows/ci.yml +59 -0
  2. c2score-0.1.0/.gitignore +9 -0
  3. c2score-0.1.0/CHANGELOG.md +30 -0
  4. c2score-0.1.0/LICENSE +21 -0
  5. c2score-0.1.0/PKG-INFO +314 -0
  6. c2score-0.1.0/README.md +287 -0
  7. c2score-0.1.0/pyproject.toml +48 -0
  8. c2score-0.1.0/src/c2score/__init__.py +25 -0
  9. c2score-0.1.0/src/c2score/_instance_json.py +165 -0
  10. c2score-0.1.0/src/c2score/cardinality.py +94 -0
  11. c2score-0.1.0/src/c2score/conciseness.py +191 -0
  12. c2score-0.1.0/src/c2score/coverage.py +222 -0
  13. c2score-0.1.0/src/c2score/datatypes.py +108 -0
  14. c2score-0.1.0/src/c2score/errors.py +17 -0
  15. c2score-0.1.0/src/c2score/evaluate.py +264 -0
  16. c2score-0.1.0/src/c2score/flatten.py +185 -0
  17. c2score-0.1.0/src/c2score/loaders/__init__.py +5 -0
  18. c2score-0.1.0/src/c2score/loaders/neo4j.py +270 -0
  19. c2score-0.1.0/src/c2score/model.py +379 -0
  20. c2score-0.1.0/src/c2score/resources/schema.json +74 -0
  21. c2score-0.1.0/src/c2score/schema_json.py +392 -0
  22. c2score-0.1.0/src/c2score/similarity.py +194 -0
  23. c2score-0.1.0/tests/data/example1.json +22 -0
  24. c2score-0.1.0/tests/data/example2.json +9 -0
  25. c2score-0.1.0/tests/data/example3.json +19 -0
  26. c2score-0.1.0/tests/data/fig1a.json +18 -0
  27. c2score-0.1.0/tests/data/mixed.json +32 -0
  28. c2score-0.1.0/tests/reference_impl.py +290 -0
  29. c2score-0.1.0/tests/test_abs_from_graph.py +136 -0
  30. c2score-0.1.0/tests/test_cardinality.py +106 -0
  31. c2score-0.1.0/tests/test_datatypes.py +118 -0
  32. c2score-0.1.0/tests/test_evaluate.py +476 -0
  33. c2score-0.1.0/tests/test_fast_matches_reference.py +217 -0
  34. c2score-0.1.0/tests/test_flatten.py +183 -0
  35. c2score-0.1.0/tests/test_flatten_self_loop.py +74 -0
  36. c2score-0.1.0/tests/test_instance_json.py +131 -0
  37. c2score-0.1.0/tests/test_model.py +150 -0
  38. c2score-0.1.0/tests/test_neo4j_integration.py +187 -0
  39. c2score-0.1.0/tests/test_neo4j_loader.py +316 -0
  40. c2score-0.1.0/tests/test_package.py +5 -0
  41. c2score-0.1.0/tests/test_schema_json.py +485 -0
  42. c2score-0.1.0/tests/test_similarity.py +213 -0
@@ -0,0 +1,59 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-24.04
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
14
+ steps:
15
+ - uses: actions/checkout@v7
16
+ - uses: actions/setup-python@v7
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - name: Install
20
+ run: python -m pip install -e ".[dev]"
21
+ - name: Test
22
+ run: python -m pytest
23
+
24
+ neo4j:
25
+ # Integration test #3 against a real Neo4j server.
26
+ runs-on: ubuntu-24.04
27
+ services:
28
+ neo4j:
29
+ image: neo4j:5.26.0-community
30
+ env:
31
+ NEO4J_AUTH: neo4j/c2score-ci
32
+ ports:
33
+ - 7687:7687
34
+ options: >-
35
+ --health-cmd "cypher-shell -u neo4j -p c2score-ci 'RETURN 1'"
36
+ --health-interval 5s
37
+ --health-timeout 10s
38
+ --health-retries 30
39
+ env:
40
+ C2SCORE_TEST_NEO4J_URI: bolt://localhost:7687
41
+ C2SCORE_TEST_NEO4J_USER: neo4j
42
+ C2SCORE_TEST_NEO4J_PASSWORD: c2score-ci
43
+ # Community edition has a single user database.
44
+ C2SCORE_TEST_NEO4J_DATABASE: neo4j
45
+ steps:
46
+ - uses: actions/checkout@v7
47
+ - uses: actions/setup-python@v7
48
+ with:
49
+ python-version: "3.12"
50
+ - name: Install
51
+ run: python -m pip install -e ".[dev]"
52
+ - name: Test
53
+ # bash here means -eo pipefail, so a pytest failure is not hidden by tee.
54
+ # Also fail if the tests were skipped instead of run.
55
+ shell: bash
56
+ run: |
57
+ set -o pipefail
58
+ python -m pytest tests/test_neo4j_integration.py -v -rs | tee pytest.log
59
+ ! grep -q SKIPPED pytest.log
@@ -0,0 +1,9 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .pytest_cache/
7
+ CLAUDE.local.md
8
+ docs/progress.md
9
+ docs/requests/
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (unreleased)
4
+
5
+ First release.
6
+
7
+ ### Added
8
+
9
+ - `load_schema_json`: read a schema from a JSON file or a `dict` and validate it. Every violation
10
+ raises `SchemaError` with its location. The format is also shipped as a JSON Schema
11
+ (`c2score/resources/schema.json`).
12
+ - `load_neo4j`: summarize a Neo4j 5.13+ database into its node and edge types (labels,
13
+ properties with data types, and cardinalities). The aggregation runs on the server in a
14
+ read-only session; APOC is not needed.
15
+ - `Instance.to_json` and `Instance.from_json`: save and restore such a summary.
16
+ - `evaluate`: compute C2-score with Coverage and Conciseness for node and edge types, the
17
+ redundant definitions, and the best-matching schema type for every instance type.
18
+ Parameters: `label_weight`, `edge_weights`, `redundancy_ratio`, `use_types`, `allow_any`.
19
+ - Schema features: data types (`STRING`, `INTEGER`, `FLOAT`, `BOOLEAN`, `DATETIME`, `ANY`),
20
+ mandatory and optional properties, cardinalities (`0..1`, `0..*`, `1..1`, `1..*`), and multiple
21
+ inheritance of node and edge types, including inherited edge endpoints.
22
+ - Exceptions: `C2ScoreError` and its subclasses `SchemaError`, `InstanceLoadError`, and `ParameterError`.
23
+ - Scales to large graphs and schemas: edge similarities are computed only for schema edge types
24
+ that can match, and Conciseness reuses the computed similarities when removing a definition
25
+ does not change the rest of the flattened schema. A DBpedia graph with about 20 million nodes
26
+ and 45 million edges loads in about 6 minutes and is evaluated against a schema with about
27
+ 180,000 edge definitions in about 8 minutes.
28
+
29
+ The library refines the definitions of the paper, so its scores can differ from those reported in
30
+ the paper. To reproduce the results of the paper, use https://github.com/kde-salt/C2-SCORE.
c2score-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fusuke Yukawa and Hiroaki Shiokawa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
c2score-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,314 @@
1
+ Metadata-Version: 2.5
2
+ Name: c2score
3
+ Version: 0.1.0
4
+ Summary: C2-score: quantitative quality evaluation of property graph schemas without ground truth
5
+ Project-URL: Repository, https://github.com/kde-salt/c2score
6
+ Author: Fusuke Yukawa, Hiroaki Shiokawa
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Keywords: graph database,neo4j,property graph,schema,schema quality
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Database
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: jsonschema
20
+ Requires-Dist: neo4j<6,>=5
21
+ Requires-Dist: numpy
22
+ Provides-Extra: dev
23
+ Requires-Dist: build; extra == 'dev'
24
+ Requires-Dist: pytest; extra == 'dev'
25
+ Requires-Dist: twine; extra == 'dev'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # c2score
29
+
30
+ C2-score measures the quality of a property graph schema **without a ground-truth schema**.
31
+ Given a property graph instance and a candidate schema, it computes two scores in [0, 1]:
32
+
33
+ - **Coverage**: how well the schema explains the node and edge types observed in the instance
34
+ (labels, properties and their data types, endpoints, and cardinalities).
35
+ - **Conciseness**: how free the schema is of redundant definitions, that is, definitions that
36
+ can be removed without a meaningful loss of Coverage.
37
+
38
+ C2-score is the harmonic mean of the two. Each score is also reported separately for nodes and
39
+ edges, together with the redundant definitions and the best-matching schema type for every type
40
+ in the instance, so that you can see *why* a schema scores as it does.
41
+
42
+ The measure is described in the paper *C2-score: Quantitative Quality Evaluation of Property Graph
43
+ Schemas without Ground Truth* (EDBT 2027).
44
+ This library refines the definitions of the paper, so its scores can differ from those reported in
45
+ the paper. To reproduce the results of the paper, use the artifact repository
46
+ [kde-salt/C2-SCORE](https://github.com/kde-salt/C2-SCORE).
47
+
48
+ ## Citation
49
+
50
+ If you use c2score in your research, please cite:
51
+
52
+ ```bibtex
53
+ @inproceedings{yukawa2027c2score,
54
+ author = {Fusuke Yukawa and Hiroaki Shiokawa},
55
+ title = {{C2-score}: Quantitative Quality Evaluation of Property Graph Schemas without Ground Truth},
56
+ booktitle = {Proceedings of the International Conference on Extending Database Technology (EDBT)},
57
+ year = {2027}
58
+ }
59
+ ```
60
+
61
+ (The bibliographic details will be completed when the proceedings are published.)
62
+
63
+ ## Installation
64
+
65
+ ```bash
66
+ pip install c2score
67
+ ```
68
+
69
+ Python 3.10 or later is required. The dependencies (`numpy`, `jsonschema`, and the `neo4j` driver 5.x)
70
+ are installed automatically.
71
+
72
+ ## Quick start
73
+
74
+ ### 1. Create an instance summary
75
+
76
+ c2score evaluates a schema against a summary of the graph: its node and edge types with their
77
+ properties and cardinalities. Read the summary from Neo4j and save it as `instance.json`. The
78
+ aggregation runs on the server; the graph is not copied to Python.
79
+
80
+ ```python
81
+ from c2score import load_neo4j
82
+
83
+ instance = load_neo4j("bolt://localhost:7687", auth=("neo4j", "password"), database="neo4j")
84
+ instance.to_json("instance.json")
85
+ ```
86
+
87
+ Suppose the summary below is created:
88
+
89
+ ```json
90
+ {
91
+ "format": "c2score-instance",
92
+ "version": 1,
93
+ "node_types": [
94
+ {"labels": ["Company"], "properties": {"name": {"type": "STRING", "required": true}}},
95
+ {"labels": ["Person"], "properties": {"name": {"type": "STRING", "required": true}}}
96
+ ],
97
+ "edge_types": [
98
+ {"labels": ["WORKS_AT"], "source_labels": ["Person"], "target_labels": ["Company"],
99
+ "cardinality": {"out": "0..1", "in": "0..*"}, "properties": {}}
100
+ ]
101
+ }
102
+ ```
103
+
104
+ ### 2. Write a schema
105
+
106
+ Write the schema to evaluate as `schema.json` (see "Writing a schema" below), for example:
107
+
108
+ ```json
109
+ {
110
+ "node_types": [
111
+ {"id": "personType", "labels": ["Person"], "properties": {"name": {"type": "STRING"}}},
112
+ {"id": "companyType", "labels": ["Company"], "properties": {"name": {"type": "STRING"}}}
113
+ ],
114
+ "edge_types": [
115
+ {"id": "worksAtType", "labels": ["WORKS_AT"], "source": "personType", "target": "companyType",
116
+ "cardinality": {"out": "0..1", "in": "0..*"}}
117
+ ]
118
+ }
119
+ ```
120
+
121
+ ### 3. Evaluate
122
+
123
+ ```python
124
+ from c2score import Instance, evaluate, load_schema_json
125
+
126
+ instance = Instance.from_json("instance.json")
127
+ schema = load_schema_json("schema.json")
128
+ result = evaluate(instance, schema)
129
+
130
+ print(result.c2) # C2-score
131
+ print(result.coverage, result.conciseness) # overall Coverage and Conciseness
132
+ print(result.cov_v, result.cov_e, result.con_v, result.con_e)
133
+ print(result.redundant_types) # {"node_types": [...], "edge_types": [...]}
134
+ ```
135
+
136
+ A saved summary can be evaluated against any number of schemas without reading the graph again.
137
+
138
+ ### The result
139
+
140
+ `evaluate` returns an `EvaluationResult`, a read-only dataclass:
141
+
142
+ | Attribute | Meaning |
143
+ | --- | --- |
144
+ | `c2` | C2-score: the harmonic mean of `coverage` and `conciseness` (0 if both are 0) |
145
+ | `coverage`, `conciseness` | `(cov_v + cov_e) / 2` and `(con_v + con_e) / 2` |
146
+ | `cov_v`, `cov_e`, `con_v`, `con_e` | Coverage and Conciseness of node types and of edge types |
147
+ | `redundant_types` | `{"node_types": [id, ...], "edge_types": [id, ...]}`: the redundant definitions, in id order |
148
+ | `best_matches` | `{"node_types": [...], "edge_types": [...]}`: one entry per type of the instance (see below) |
149
+ | `params` | The parameters actually used, including the edge weights and whether they were chosen automatically (`"edge_weights_mode": "auto"` or `"user"`) |
150
+ | `to_dict()` | Everything above as a JSON-serializable `dict` |
151
+
152
+ The dataclass is frozen, but the dictionaries and lists in `redundant_types`, `best_matches`, and
153
+ `params` are ordinary Python objects: modifying them modifies the result. Use `to_dict()` to get an
154
+ independent copy that you can change.
155
+
156
+ An entry of `best_matches["node_types"]` looks like
157
+ `{"labels": ["Person"], "schema_type": "personType", "similarity": 1.0}`.
158
+ An entry of `best_matches["edge_types"]` also has `source_labels` and `target_labels` (of the
159
+ instance type) and `source` and `target` (the ids of the schema node types at the two ends).
160
+ Labels are sorted. When the best similarity is 0, `schema_type` (and, for edges, `source` and
161
+ `target`) is `None`. When several schema types tie, the first one in a fixed order is reported
162
+ (node types by id; edge types by the smallest id of the definitions that produce them, then by
163
+ the source and target ids).
164
+
165
+ ## Writing a schema
166
+
167
+ A schema is a JSON object with two arrays, `node_types` and `edge_types`. Both may be omitted.
168
+ `load_schema_json` accepts a path to a UTF-8 JSON file (a byte order mark is allowed) or an
169
+ already parsed `dict`.
170
+
171
+ | Key | In | Required | Meaning and default |
172
+ | --- | --- | --- | --- |
173
+ | `id` | node and edge types | yes | A non-empty string, unique across node **and** edge types |
174
+ | `labels` | node and edge types | no | An array of labels without duplicates. Default `[]`. A type inheriting from others lists only its own labels |
175
+ | `properties` | node and edge types | no | An object mapping a property name to `{"type": ..., "required": ...}`. Default `{}` |
176
+ | `properties.*.type` | | no | `STRING`, `INTEGER`, `FLOAT`, `BOOLEAN`, `DATETIME`, or `ANY` (case-insensitive). **Default `ANY`** |
177
+ | `properties.*.required` | | no | `true` (mandatory) or `false` (optional). **Default `true`** |
178
+ | `supertypes` | node and edge types | no | The ids of the direct parents, without duplicates. **The order matters** (see below). Node types inherit only from node types, edge types only from edge types |
179
+ | `source`, `target` | edge types | no | The ids of the node types at the two ends. If omitted, they are inherited from the nearest parent edge type that has them |
180
+ | `cardinality` | edge types | no | `{"out": interval, "in": interval}`, both required. An interval is one of `"0..1"`, `"0..*"`, `"1..1"`, `"1..*"`. If omitted, it is inherited; if no ancestor has one, it is treated as `0..*` in both directions |
181
+
182
+ The top level may also contain `"format": "c2score-schema"` and a `"version"` string; both are optional.
183
+
184
+ A minimal schema, in which `name` is mandatory and `email` optional, both of type `ANY`:
185
+
186
+ ```json
187
+ {
188
+ "node_types": [
189
+ {"id": "personType", "labels": ["Person"],
190
+ "properties": {"name": {}, "email": {"required": false}}}
191
+ ],
192
+ "edge_types": [
193
+ {"id": "knowsType", "labels": ["KNOWS"], "source": "personType", "target": "personType"}
194
+ ]
195
+ }
196
+ ```
197
+
198
+ ### Inheritance
199
+
200
+ A type inherits the labels, properties, cardinality, and (for edge types) endpoints of its
201
+ ancestors.
202
+
203
+ - **Labels** are the union of the labels of the type and all its ancestors.
204
+ - **Properties, cardinality, and endpoints** are taken from the nearest type that defines them.
205
+ The type itself comes first, followed by its ancestors in breadth-first order, visiting the
206
+ `supertypes` of each type in the order written. The description of a property (type and
207
+ `required`) is taken as a whole from one type.
208
+ - The `source` and `target` of an edge type are inherited independently. Every edge type must end
209
+ up with both.
210
+ - **An edge type also applies to the descendants of its endpoints.** An edge type from `s` to `t`
211
+ stands for every pair (s′, t′) where s′ is `s` or one of its descendants and t′ is `t` or one of
212
+ its descendants.
213
+ - **Inheritance cycles are rejected**, and so is a type listing itself in `supertypes`.
214
+
215
+ Multiple inheritance and an inherited edge type:
216
+
217
+ ```json
218
+ {
219
+ "node_types": [
220
+ {"id": "personType", "labels": ["Person"],
221
+ "properties": {"name": {"type": "STRING"}, "email": {"type": "STRING", "required": false}}},
222
+ {"id": "employeeType", "labels": ["Employee"], "supertypes": ["personType"],
223
+ "properties": {"email": {"type": "STRING", "required": true}, "salary": {"type": "FLOAT"}}},
224
+ {"id": "shareholderType", "labels": ["Shareholder"], "supertypes": ["personType"],
225
+ "properties": {"email": {"type": "STRING", "required": false}, "shares": {"type": "INTEGER"}}},
226
+ {"id": "managerType", "labels": ["Manager"], "supertypes": ["employeeType", "shareholderType"]},
227
+ {"id": "companyType", "labels": ["Company"], "properties": {"name": {"type": "STRING"}}}
228
+ ],
229
+ "edge_types": [
230
+ {"id": "worksAtType", "labels": ["WORKS_AT"], "source": "employeeType", "target": "companyType",
231
+ "properties": {"since": {"type": "DATETIME"}},
232
+ "cardinality": {"out": "1..1", "in": "0..*"}},
233
+ {"id": "managesType", "labels": ["MANAGES"], "supertypes": ["worksAtType"], "source": "managerType",
234
+ "properties": {"since": {"type": "DATETIME", "required": false}}}
235
+ ]
236
+ }
237
+ ```
238
+
239
+ Here `managerType` has the labels Manager, Employee, Shareholder, and Person, and its `email` is
240
+ mandatory because `employeeType` is listed before `shareholderType`. `managesType` has the labels
241
+ MANAGES and WORKS_AT, an optional `since`, the cardinality of `worksAtType`, and the target
242
+ `companyType` inherited from `worksAtType`.
243
+
244
+ ### Validation
245
+
246
+ `load_schema_json` raises `SchemaError` (a subclass of `ValueError`) for every violation, with the
247
+ location in the message, for example `edge_types[1] (id='managesType').source: unknown id 'x'`.
248
+ Besides the rules above, it rejects unknown keys (to catch typos) and an object that repeats a key.
249
+ The format is also defined as a JSON Schema (Draft 2020-12), shipped with the package as
250
+ `c2score/resources/schema.json`
251
+ ([view](https://github.com/kde-salt/c2score/blob/main/src/c2score/resources/schema.json)).
252
+
253
+ ## Parameters
254
+
255
+ ```python
256
+ evaluate(instance, schema, *, label_weight=0.5, edge_weights=None,
257
+ redundancy_ratio=0.15, use_types=True, allow_any=True)
258
+ ```
259
+
260
+ | Argument | Paper | Default | Allowed values |
261
+ | --- | --- | --- | --- |
262
+ | `label_weight` | α | `0.5` | A number in [0, 1]: the weight of labels against properties, for nodes and edges |
263
+ | `edge_weights` | (α_A, α_E, α_C) | `None` (automatic) | A tuple, list, or 1-D NumPy array of three numbers in [0, 1] summing to 1: the weights of the edge's own attributes, its endpoints, and its cardinality |
264
+ | `redundancy_ratio` | γ (replaces ε) | `0.15` | A finite number greater than 0. The larger it is, the more readily a definition counts as redundant |
265
+ | `use_types` | — | `True` | `True` or `False` (a NumPy boolean is accepted). See the table below |
266
+ | `allow_any` | — | `True` | `True` or `False`. See the table below |
267
+
268
+ `use_types` and `allow_any` decide how properties are compared. A property without `type` in the
269
+ schema has type `ANY`.
270
+
271
+ | `use_types` | `allow_any` | What is compared |
272
+ | --- | --- | --- |
273
+ | `True` | `True` (default) | Property names, mandatory or optional, and data types. `ANY` matches every type |
274
+ | `True` | `False` | The same, but `ANY` matches no type. Every property of the schema must have a type other than `ANY`; otherwise `evaluate` raises `SchemaError` |
275
+ | `False` | ignored | Property names and mandatory or optional only |
276
+
277
+ With `edge_weights=None`, the weights are (1/3, 1/3, 1/3) if any edge definition of the schema
278
+ writes a `cardinality`, and (0.5, 0.5, 0) otherwise. They are decided once, on the whole schema.
279
+
280
+ An argument out of range raises `ParameterError` (a subclass of `ValueError`).
281
+
282
+ The library names correspond to the paper as follows: `Instance` holds Abs(G), the types of the
283
+ instance; `Schema` is the candidate schema S; `cov_v`, `cov_e`, `con_v`, `con_e` are Cov_V, Cov_E,
284
+ Con_V, Con_E; `coverage` and `conciseness` are Cov and Con; `c2` is C2.
285
+
286
+ ## Neo4j requirements
287
+
288
+ ```python
289
+ load_neo4j(uri=None, *, auth=None, database=None, driver=None)
290
+ ```
291
+
292
+ - Neo4j 5.13 or later. APOC is not needed.
293
+ - Connect with `uri` and `auth`, or pass an existing `neo4j.Driver` as `driver`. Choose the
294
+ database with `database`; if omitted, the server's default database is used.
295
+ - Only read access is needed. Load a graph that is not being written to.
296
+ - Failures (connection, authentication, queries, an older server) raise `InstanceLoadError`.
297
+ - Reading a large graph can take several minutes. Save the summary once, as in step 1 of the
298
+ quick start, and evaluate the saved file. The file also shows what was read from the graph.
299
+
300
+ ## Notes
301
+
302
+ - A string passed to `load_schema_json` or `Instance.from_json` is always treated as a file
303
+ path, never as JSON text. To pass a schema that is already in memory, pass a `dict`
304
+ (for example the result of `json.loads`).
305
+ - A missing file raises `FileNotFoundError` (from `open`), not a c2score exception.
306
+ - `evaluate` raises `TypeError` if `instance` is not an `Instance` or `schema` is not a `Schema`.
307
+ - All exceptions raised by c2score derive from `C2ScoreError`: `SchemaError`, `InstanceLoadError`,
308
+ and `ParameterError`.
309
+ - Not included in this release: reading PG-Schema, loading an instance from a JSON graph, and
310
+ databases other than Neo4j.
311
+
312
+ ## License
313
+
314
+ MIT. See [LICENSE](https://github.com/kde-salt/c2score/blob/main/LICENSE).