logo Netzschleuder network catalog, repository, and centrifuge

History of us_inventor_coauthorship

The changes to the source code of this entry in the repository, newest first, each with the differences it made to the entry's files. They are also listed on GitLab.

[entries] Add the date when each entry was added, and remove icon_hash by Tiago de Paula Peixoto beff7c9
The dates are those of the commits that first added the entries' files
(2020-08-11 for the entries of the initial commit); renamed entries keep
the date of their first name.

Changed: none
diff --git a/entries/us_inventor_coauthorship/__init__.py b/entries/us_inventor_coauthorship/__init__.py
index c45888f..610b373 100644
--- a/entries/us_inventor_coauthorship/__init__.py
+++ b/entries/us_inventor_coauthorship/__init__.py
@@ -74,7 +74,7 @@ citation = [('G.-C. Li, R. Lai, A. D\'Amour, D. M. Doolin, Y. Sun, V. I. Torvik,
              'https://doi.org/10.1016/j.respol.2014.01.012'),
             ('L. Fleming et al., "Disambiguation and Co-authorship Networks of the U.S. Patent Inventor Database (1975 - 2010)." Harvard Dataverse, V5 (2013)',
              'https://doi.org/10.7910/DVN/5F1RRI')]
-icon_hash = None
+date_added = '2026-10-31'
 upstream_license = ("CC0", "https://creativecommons.org/publicdomain/zero/1.0/")
 # Harvard Dataverse files (version 5.1) by their ids
 upstream_prefix = 'https://dataverse.harvard.edu/api/access/datafile'
[entries] Prefix the properties in the descriptions with (Node), (Edge) or (Graph) by Tiago de Paula Peixoto bc3dbbd
The lists of properties at the end of the descriptions marked edge
properties with "Edge" but left node properties unmarked, or grouped
them in "Nodes: `a`, ...; `b`, ..." items, so the kind of a property
was often unclear. Every item now starts with (Node), (Edge) or (Graph),
followed by the property names, a colon and the explanation, one item
per property or group of properties; qualifications (kinds of nodes,
networks) follow the names in parentheses. Properties that were only
named got a short explanation, and a few items that named the wrong
kind of property were corrected.
diff --git a/entries/us_inventor_coauthorship/__init__.py b/entries/us_inventor_coauthorship/__init__.py
index 34d50d7..c45888f 100644
--- a/entries/us_inventor_coauthorship/__init__.py
+++ b/entries/us_inventor_coauthorship/__init__.py
@@ -41,24 +41,32 @@ The other raw tables of the authors (inventor, assignee, patent, non-patent refe
 
 The networks have the following properties:
 
-- `is_patent` (bipartite networks): whether the node is a patent (otherwise it is an inventor, a class or a lawyer).
-- `name`: the identifier of the inventor given by the disambiguation (the identifier of one of its records, as `<patent number>-<position of the inventor on the patent>`), the patent number (in `citations`, the number of the patent document), the class (as `<class>/<subclass>`), or the name of the lawyer (first and last name, or the name of the firm).
-- `country` (`citations`): the country of a cited foreign patent document (empty for U.S. documents).
-- Classes (`patent_class`): `class`, `subclass`.
-- Lawyers (`patent_lawyer`): `first_name`, `last_name`, `organization` (the firm), `country` (mostly `unknown`).
-- Inventors: `first_name`, `last_name`, and, in the co-inventorship networks, `city`, `state`, `country`, `assignee`, `assignee_number` (of one of the records of the inventor), and `patents` (the number of patents of the inventor in the network).
-- Patents (bipartite networks): `app_year` (the year of the application), `grant_year` (the year of the grant), `app_date` (the date of the application, as Unix time; -1 if unknown), `assignee` and `assignee_number` (the assignee of the patent, e.g. a company, and its identifier), `class` (the technology classes of the USPTO classification, separated by `/`).
-- Edge `invseq` (bipartite networks): the position of the inventor on the patent.
-- Edge `city`, `state`, `country`, `zipcode`, `latitude`, `longitude` (bipartite networks): the location of the inventor given on the patent.
-- Edge `weight` (co-inventorship networks): the number of patents shared by the two inventors.
-- Edge `app_year` (co-inventorship networks): the application year given to the edge in the data.
-- Edge `cit_date` (`citations`): the date of the cited document, as Unix time (-1 if not given, as for the patents of 1975-1999).
-- Edge `cit_name` (`citations`): the name of the first inventor or the applicant of the cited document, as given (from 2000).
-- Edge `cit_kind` (`citations`): the kind code of the cited document, if given.
-- Edge `category` (`citations`): the category of the citation (e.g. cited by the examiner or by the applicant), if given.
-- Edge `cit_seq` (`citations`): the position of the citation on the patent (-1 if not given, as from 2000).
-- Edge `primary` (`patent_class`): whether the class is the primary class of the patent.
-- Edge `law_seq` (`patent_lawyer`): the position of the lawyer on the patent."""
+- (Node) `is_patent` (bipartite networks): whether the node is a patent (otherwise it is an inventor, a class or a lawyer).
+- (Node) `name`: the identifier of the inventor given by the disambiguation (the identifier of one of its records, as `<patent number>-<position of the inventor on the patent>`), the patent number (in `citations`, the number of the patent document), the class (as `<class>/<subclass>`), or the name of the lawyer (first and last name, or the name of the firm).
+- (Node) `country` (`citations`): the country of a cited foreign patent document (empty for U.S. documents).
+- (Node) `class`, `subclass` (classes, `patent_class`): the class and subclass.
+- (Node) `first_name`, `last_name` (lawyers, `patent_lawyer`): the name of the lawyer.
+- (Node) `organization` (lawyers, `patent_lawyer`): the firm.
+- (Node) `country` (lawyers, `patent_lawyer`): the country of the lawyer (mostly `unknown`).
+- (Node) `first_name`, `last_name` (inventors): the name of the inventor.
+- (Node) `city`, `state`, `country`, `assignee`, `assignee_number` (inventors, co-inventorship networks): the location and the assignee of one of the records of the inventor.
+- (Node) `patents` (inventors, co-inventorship networks): the number of patents of the inventor in the network.
+- (Node) `app_year` (patents, bipartite networks): the year of the application.
+- (Node) `grant_year` (patents, bipartite networks): the year of the grant.
+- (Node) `app_date` (patents, bipartite networks): the date of the application, as Unix time (-1 if unknown).
+- (Node) `assignee`, `assignee_number` (patents, bipartite networks): the assignee of the patent, e.g. a company, and its identifier.
+- (Node) `class` (patents, bipartite networks): the technology classes of the USPTO classification, separated by `/`.
+- (Edge) `invseq` (bipartite networks): the position of the inventor on the patent.
+- (Edge) `city`, `state`, `country`, `zipcode`, `latitude`, `longitude` (bipartite networks): the location of the inventor given on the patent.
+- (Edge) `weight` (co-inventorship networks): the number of patents shared by the two inventors.
+- (Edge) `app_year` (co-inventorship networks): the application year given to the edge in the data.
+- (Edge) `cit_date` (`citations`): the date of the cited document, as Unix time (-1 if not given, as for the patents of 1975-1999).
+- (Edge) `cit_name` (`citations`): the name of the first inventor or the applicant of the cited document, as given (from 2000).
+- (Edge) `cit_kind` (`citations`): the kind code of the cited document, if given.
+- (Edge) `category` (`citations`): the category of the citation (e.g. cited by the examiner or by the applicant), if given.
+- (Edge) `cit_seq` (`citations`): the position of the citation on the patent (-1 if not given, as from 2000).
+- (Edge) `primary` (`patent_class`): whether the class is the primary class of the patent.
+- (Edge) `law_seq` (`patent_lawyer`): the position of the lawyer on the patent."""
 tags = ['Social', 'Collaboration', 'Affiliation', 'Citation', 'Bipartite', 'Multigraph', 'Weighted', 'Metadata']
 url = ['https://doi.org/10.7910/DVN/5F1RRI',
        'https://dataverse.harvard.edu/dataset.xhtml?persistentId=doi:10.7910/DVN/5F1RRI']
[entries] New entry: us_inventor_coauthorship by Tiago de Paula Peixoto c100c5c
diff --git a/entries/us_inventor_coauthorship/__init__.py b/entries/us_inventor_coauthorship/__init__.py
new file mode 100644
index 0000000..34d50d7
--- /dev/null
+++ b/entries/us_inventor_coauthorship/__init__.py
@@ -0,0 +1,356 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2026 Tiago de Paula Peixoto <tiago@skewed.de>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+import math
+from calendar import timegm
+
+import pyarrow
+import pyarrow.compute as pc
+import pyarrow.csv
+
+from .. import *
+
+title = "U.S. patent inventors, co-inventors, citations, classes and lawyers (1975-2010)"
+description = r"""The inventors of the utility patents granted by the U.S. Patent and Trademark Office (USPTO) from 1975 to 2010, disambiguated by G.-C. Li, R. Lai, A. D'Amour et al. (the Fung Institute, U.C. Berkeley), and their co-inventorship networks. The names of the inventors on the patents were disambiguated (determining which records belong to the same person) with a Bayesian supervised learning approach based on the "Author-ity" algorithm of V. Torvik and N. Smalheiser, comparing the names, locations, assignees, technology classes and co-inventors of the records. The disambiguation is given in two versions, a "lower bound" and an "upper bound" of the number of distinct inventors, obtained with different thresholds of the probability that two records belong to the same inventor (the "lower bound" merging more records).
+
+- `inventor_patent_lower`, `inventor_patent_upper`: the undirected bipartite networks of the inventors and the patents (granted 1975-2010), where an edge links a patent to each of its inventors, in the lower-bound and upper-bound disambiguations (the full disambiguation results).
+- `coinventor_1975_lower`, `coinventor_1975_upper`, `coinventor_1978_lower`, ..., `coinventor_2008_upper`: the co-inventorship networks of the patents applied for in three-year windows starting in 1975, 1978, ..., 2008 (the last one covering 2008-2010 incompletely), as given by the authors: the nodes are the inventors of the patents of the window, and an edge links two inventors who are co-inventors of at least one of them, weighted by the number of their shared patents. The data give one edge per pair of inventors and application year, so that a pair can have several (parallel) edges, with different `app_year`.
+- `coinventor_us_lower`, `coinventor_us_upper`: the co-inventorship networks of all the patents, as given by the authors ("entire US graph").
+
+- `citations`: the directed network of the citations of the patents granted 1975-2010 (from the raw citation tables of the authors, as extracted from the patent documents): an edge goes from a patent to each patent document it cites (one edge per row of the data). The cited documents include U.S. patents granted before 1975, U.S. design and reissue patents and applications, and foreign patent documents (identified by their country and number as given), so that most nodes are cited documents only.
+- `patent_class`: the undirected bipartite network of the patents and the technology classes of the USPTO classification (class and subclass, e.g. `360/130.24`; the data also contain classes of other schemes, e.g. `G9B/15.08`), where an edge links a patent to each class assigned to it (the primary class marked).
+- `patent_lawyer`: the undirected bipartite network of the patents and their lawyers, attorneys or agents (persons or firms), where an edge links a patent to each lawyer listed on it. The lawyers are identified by their first name, last name, firm name and country exactly as given (not disambiguated, so that the same lawyer can appear as several nodes); the names are as in the data, often with the last name in the field of the first name, followed by a semicolon.
+
+The other raw tables of the authors (inventor, assignee, patent, non-patent references, related documents, abstracts and titles, and the input tables of the disambiguation) are not included; the citations between the patents up to 1999 are also in the entry `us_patents`.
+
+The networks have the following properties:
+
+- `is_patent` (bipartite networks): whether the node is a patent (otherwise it is an inventor, a class or a lawyer).
+- `name`: the identifier of the inventor given by the disambiguation (the identifier of one of its records, as `<patent number>-<position of the inventor on the patent>`), the patent number (in `citations`, the number of the patent document), the class (as `<class>/<subclass>`), or the name of the lawyer (first and last name, or the name of the firm).
+- `country` (`citations`): the country of a cited foreign patent document (empty for U.S. documents).
+- Classes (`patent_class`): `class`, `subclass`.
+- Lawyers (`patent_lawyer`): `first_name`, `last_name`, `organization` (the firm), `country` (mostly `unknown`).
+- Inventors: `first_name`, `last_name`, and, in the co-inventorship networks, `city`, `state`, `country`, `assignee`, `assignee_number` (of one of the records of the inventor), and `patents` (the number of patents of the inventor in the network).
+- Patents (bipartite networks): `app_year` (the year of the application), `grant_year` (the year of the grant), `app_date` (the date of the application, as Unix time; -1 if unknown), `assignee` and `assignee_number` (the assignee of the patent, e.g. a company, and its identifier), `class` (the technology classes of the USPTO classification, separated by `/`).
+- Edge `invseq` (bipartite networks): the position of the inventor on the patent.
+- Edge `city`, `state`, `country`, `zipcode`, `latitude`, `longitude` (bipartite networks): the location of the inventor given on the patent.
+- Edge `weight` (co-inventorship networks): the number of patents shared by the two inventors.
+- Edge `app_year` (co-inventorship networks): the application year given to the edge in the data.
+- Edge `cit_date` (`citations`): the date of the cited document, as Unix time (-1 if not given, as for the patents of 1975-1999).
+- Edge `cit_name` (`citations`): the name of the first inventor or the applicant of the cited document, as given (from 2000).
+- Edge `cit_kind` (`citations`): the kind code of the cited document, if given.
+- Edge `category` (`citations`): the category of the citation (e.g. cited by the examiner or by the applicant), if given.
+- Edge `cit_seq` (`citations`): the position of the citation on the patent (-1 if not given, as from 2000).
+- Edge `primary` (`patent_class`): whether the class is the primary class of the patent.
+- Edge `law_seq` (`patent_lawyer`): the position of the lawyer on the patent."""
+tags = ['Social', 'Collaboration', 'Affiliation', 'Citation', 'Bipartite', 'Multigraph', 'Weighted', 'Metadata']
+url = ['https://doi.org/10.7910/DVN/5F1RRI',
+       'https://dataverse.harvard.edu/dataset.xhtml?persistentId=doi:10.7910/DVN/5F1RRI']
+citation = [('G.-C. Li, R. Lai, A. D\'Amour, D. M. Doolin, Y. Sun, V. I. Torvik, A. Z. Yu, L. Fleming, "Disambiguation and co-authorship networks of the U.S. patent inventor database (1975-2010)." Research Policy 43(6), 941-955 (2014)',
+             'https://doi.org/10.1016/j.respol.2014.01.012'),
+            ('L. Fleming et al., "Disambiguation and Co-authorship Networks of the U.S. Patent Inventor Database (1975 - 2010)." Harvard Dataverse, V5 (2013)',
+             'https://doi.org/10.7910/DVN/5F1RRI')]
+icon_hash = None
+upstream_license = ("CC0", "https://creativecommons.org/publicdomain/zero/1.0/")
+# Harvard Dataverse files (version 5.1) by their ids
+upstream_prefix = 'https://dataverse.harvard.edu/api/access/datafile'
+_graphml = {("1975", "lower"): 2301851, ("1975", "upper"): 2301867,
+            ("1978", "lower"): 2301860, ("1978", "upper"): 2301868,
+            ("1981", "lower"): 2301862, ("1981", "upper"): 2301873,
+            ("1984", "lower"): 2301858, ("1984", "upper"): 2301865,
+            ("1987", "lower"): 2301855, ("1987", "upper"): 2301871,
+            ("1990", "lower"): 2301853, ("1990", "upper"): 2301864,
+            ("1993", "lower"): 2301854, ("1993", "upper"): 2301870,
+            ("1996", "lower"): 2301852, ("1996", "upper"): 2301869,
+            ("1999", "lower"): 2301859, ("1999", "upper"): 2301872,
+            ("2002", "lower"): 2301861, ("2002", "upper"): 2301875,
+            ("2005", "lower"): 2301863, ("2005", "upper"): 2301876,
+            ("2008", "lower"): 2301856, ("2008", "upper"): 2301874,
+            ("us", "lower"): 2301857, ("us", "upper"): 2301866}
+_invpat = "2301997:zip:invpat.csv"
+# the raw tables of the same release
+_citations = ("2291676:zip:citation75_99.csv", "2291678:zip:citation00_10.csv")
+_class = "2291674:zip:class.csv"
+_lawyer = "2291669:zip:lawyer.csv"
+files = ([(_invpat, f"inventor_patent_{b}", None) for b in ("lower", "upper")] +
+         [(str(fid), f"coinventor_{w}_{b}", "graphml")
+          for (w, b), fid in _graphml.items()] +
+         [(_citations, "citations", None), (_class, "patent_class", None),
+          (_lawyer, "patent_lawyer", None)])
+
+def fetch_upstream(force=False):
+    return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+                                force)
+
+# For checks only: if set, only (about) this many rows of the tables are read
+_check_rows = None
+
+# The column of the inventor identifiers of each bound
+_bound_col = {"lower": "lower", "upper": "upper"}
+
+def to_time(x):
+    "Dates MM/DD/YYYY or YYYYMMDD as Unix time (-1 if invalid)."
+    try:
+        if "/" in x:
+            m, d, y = x.split("/")
+        else:
+            y, m, d = x[:4], x[4:6], x[6:8]
+        return timegm((int(y), int(m), int(d), 0, 0, 0))
+    except (ValueError, TypeError):
+        return -1
+
+def string_vp(g, offset, vals, name):
+    p = g.vp[name] if name in g.vp else g.new_vp("string")
+    for i, x in enumerate(vals):
+        if x:
+            p[offset + i] = x
+    g.vp[name] = p
+
+def string_ep(g, vals, name):
+    p = g.new_ep("string")
+    for e, x in zip(g.edges(), vals):
+        if x:
+            p[e] = x
+    g.ep[name] = p
+
+def read_table(name, fname, types):
+    "A raw table (all columns as strings unless given in `types`)."
+    with open_upstream_file(name, fname, "rb") as f:
+        reader = pyarrow.csv.open_csv(
+            f, read_options=pyarrow.csv.ReadOptions(block_size=1 << 24,
+                                                    use_threads=False),
+            convert_options=pyarrow.csv.ConvertOptions(
+                column_types=types, strings_can_be_null=False))
+        batches, n = [], 0
+        for b in reader:
+            batches.append(b)
+            n += b.num_rows
+            if _check_rows is not None and n >= _check_rows:
+                break
+    return pyarrow.Table.from_batches(batches)
+
+def strings(t, c):
+    return t.column(c).cast(pyarrow.string()).fill_null("")
+
+def bipartite(t, keys, eprops):
+    """The bipartite network of the patents (column Patent) and the other
+    nodes, identified by the (string) array `keys`, one edge per row."""
+    pat = strings(t, "Patent").combine_chunks().dictionary_encode()
+    oth = keys.combine_chunks().dictionary_encode() \
+        if isinstance(keys, pyarrow.ChunkedArray) else keys.dictionary_encode()
+    Np, No = len(pat.dictionary), len(oth.dictionary)
+    g = Graph(directed=False)
+    g.add_vertex(Np + No)
+    g.add_edge_list(numpy.column_stack([pat.indices.to_numpy(),
+                                        Np + oth.indices.to_numpy()]))
+    g.vp.is_patent = g.new_vp("bool")
+    g.vp.is_patent.a[:Np] = 1
+    string_vp(g, 0, pat.dictionary.to_pylist(), "name")
+    _, first = numpy.unique(oth.indices.to_numpy(), return_index=True)
+    for k, (c, typ) in eprops.items():
+        if typ == "string":
+            string_ep(g, strings(t, c).to_pylist(), k)
+        else:
+            fill = 0 if typ == "bool" else -1
+            g.ep[k] = g.new_ep(typ, vals=t.column(c).fill_null(fill).to_numpy())
+    return g, Np, pyarrow.array(first)
+
+def parse_citations(name):
+    types = {c: pyarrow.string() for c in
+             ("Patent", "Cit_Date", "Cit_Name", "Cit_Kind", "Cit_Country",
+              "Citation", "Category")}
+    types["CitSeq"] = pyarrow.int32()
+    t = pyarrow.concat_tables([read_table(name, f, types)
+                               for f in _citations])
+    # nodes by country and number (the citing patents are U.S. patents)
+    src = pc.binary_join_element_wise(pyarrow.scalar(""),
+                                      strings(t, "Patent"), ":")
+    tgt = pc.binary_join_element_wise(strings(t, "Cit_Country"),
+                                      strings(t, "Citation"), ":")
+    keys = pyarrow.chunked_array(src.chunks + tgt.chunks).combine_chunks() \
+        .dictionary_encode()
+    idx = keys.indices.to_numpy()
+    E = len(t)
+    g = Graph(directed=True)
+    g.add_vertex(len(keys.dictionary))
+    g.add_edge_list(numpy.column_stack([idx[:E], idx[E:]]))
+    del idx
+    country, number = [], []
+    for k in keys.dictionary.to_pylist():
+        c, _, x = k.partition(":")
+        country.append(c)
+        number.append(x)
+    string_vp(g, 0, number, "name")
+    string_vp(g, 0, country, "country")
+    del keys, country, number
+    date = pc.strptime(pc.if_else(pc.equal(strings(t, "Cit_Date"), ""),
+                                  pyarrow.scalar(None, pyarrow.string()),
+                                  strings(t, "Cit_Date")),
+                       format="%Y-%m-%d", unit="s", error_is_null=True)
+    g.ep.cit_date = g.new_ep("int64_t",
+                             vals=date.cast(pyarrow.int64()).fill_null(-1).to_numpy())
+    g.ep.cit_seq = g.new_ep("int", vals=t.column("CitSeq").fill_null(-1).to_numpy())
+    for k, c in (("cit_name", "Cit_Name"), ("cit_kind", "Cit_Kind"),
+                 ("category", "Category")):
+        string_ep(g, strings(t, c).to_pylist(), k)
+    return g
+
+def parse_class(name):
+    t = read_table(name, _class, {"Patent": pyarrow.string(),
+                                  "Prim": pyarrow.int8(),
+                                  "Class": pyarrow.string(),
+                                  "SubClass": pyarrow.string()})
+    keys = pc.binary_join_element_wise(strings(t, "Class"),
+                                       strings(t, "SubClass"), "/")
+    g, Np, first = bipartite(t, keys, {"primary": ("Prim", "bool")})
+    string_vp(g, Np, keys.take(first).to_pylist(), "name")
+    string_vp(g, Np, strings(t, "Class").take(first).to_pylist(), "class")
+    string_vp(g, Np, strings(t, "SubClass").take(first).to_pylist(), "subclass")
+    return g
+
+def parse_lawyer(name):
+    t = read_table(name, _lawyer, {c: pyarrow.string() for c in
+                                   ("Patent", "Firstname", "Lastname",
+                                    "LawCountry", "OrgName")} |
+                   {"LawSeq": pyarrow.int32()})
+    cols = [("first_name", "Firstname"), ("last_name", "Lastname"),
+            ("organization", "OrgName"), ("country", "LawCountry")]
+    # lawyers (persons or firms) by their names and country, exactly as given
+    keys = pc.binary_join_element_wise(*[strings(t, c) for k, c in cols],
+                                       "\x1f")
+    g, Np, first = bipartite(t, keys, {"law_seq": ("LawSeq", "int")})
+    vals = {k: strings(t, c).take(first).to_pylist() for k, c in cols}
+    for k, x in vals.items():
+        string_vp(g, Np, x, k)
+    string_vp(g, Np, [" ".join(y for y in (a.strip(), b.strip()) if y) or o
+                      for a, b, o in zip(vals["first_name"], vals["last_name"],
+                                         vals["organization"])], "name")
+    return g
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+    name = __name__.split(".")[-1]
+    for fname, alt, fmt in files:
+        if alts is not None and alt not in alts:
+            continue
+        if alt == "citations":
+            yield alt, parse_citations(name)
+            continue
+        if alt == "patent_class":
+            yield alt, parse_class(name)
+            continue
+        if alt == "patent_lawyer":
+            yield alt, parse_lawyer(name)
+            continue
+        if fmt == "graphml":
+            with open_upstream_file(name, fname, "rb") as f:
+                g = load_graph(f, fmt="graphml")
+            ug = g
+            vp = dict(g.vp)
+            ep = dict(g.ep)
+            for k in list(g.vp.keys()):
+                del g.vp[k]
+            for k in list(g.ep.keys()):
+                del g.ep[k]
+            ug.vp.name = vp["inventor_id"]
+            for k, n in (("first_name", "Firstname"), ("last_name", "Lastname"),
+                         ("city", "City"), ("state", "State"),
+                         ("country", "Country"), ("assignee", "Assignee"),
+                         ("assignee_number", "AsgNum")):
+                p = ug.new_vp("string")
+                for v, x in enumerate(vp[n]):
+                    if x and x != "None":
+                        p[v] = x
+                ug.vp[k] = p
+            ug.vp.patents = ug.new_vp("int", vals=vp["Patents"].a.astype("int"))
+            ug.ep.weight = ug.new_ep("int", vals=ep["Weight"].a.astype("int"))
+            years = [int(x) if x.strip().isdigit() else -1
+                     for x in ep["AppYear"]]
+            ug.ep.app_year = ug.new_ep("int", vals=years)
+            del vp, ep
+            yield alt, ug
+            continue
+
+        bound = alt.rsplit("_", 1)[1]
+        types = {c: pyarrow.string() for c in
+                 ("Firstname", "Lastname", "City", "State", "Country",
+                  "Zipcode", "Patent", "AppDateStr", "Assignee", "AsgNum",
+                  "Class", "Invnum", "lower", "upper")}
+        types.update({"Lat": pyarrow.float64(), "Lon": pyarrow.float64(),
+                      "InvSeq": pyarrow.int32(), "AppYearStr": pyarrow.int32(),
+                      "GYear": pyarrow.int32()})
+        with open_upstream_file(name, fname, "rb") as f:
+            reader = pyarrow.csv.open_csv(
+                f, read_options=pyarrow.csv.ReadOptions(block_size=1 << 26,
+                                                        use_threads=False),
+                convert_options=pyarrow.csv.ConvertOptions(
+                    column_types=types, strings_can_be_null=False,
+                    include_columns=list(types)))
+            batches, n = [], 0
+            for b in reader:
+                batches.append(b)
+                n += b.num_rows
+                if _check_rows is not None and n >= _check_rows:
+                    break
+            t = pyarrow.Table.from_batches(batches)
+            del batches
+        inv = t.column(_bound_col[bound])
+        # inventors in the order of their first record
+        inv_d = inv.combine_chunks().dictionary_encode()
+        iidx = inv_d.indices.to_numpy()
+        pat_d = t.column("Patent").combine_chunks().dictionary_encode()
+        pidx = pat_d.indices.to_numpy()
+        Ni, Np = len(inv_d.dictionary), len(pat_d.dictionary)
+        g = Graph(directed=False)
+        g.add_vertex(Ni + Np)
+        g.add_edge_list(numpy.column_stack([iidx, Ni + pidx]))
+        g.vp.is_patent = g.new_vp("bool")
+        g.vp.is_patent.a[Ni:] = 1
+        _, ifirst = numpy.unique(iidx, return_index=True)
+        _, pfirst = numpy.unique(pidx, return_index=True)
+        del iidx, pidx
+        string_vp(g, 0, inv_d.dictionary.to_pylist(), "name")
+        string_vp(g, Ni, pat_d.dictionary.to_pylist(), "name")
+        ifirst = pyarrow.array(ifirst)
+        pfirst = pyarrow.array(pfirst)
+        string_vp(g, 0, t.column("Firstname").take(ifirst).to_pylist(), "first_name")
+        string_vp(g, 0, t.column("Lastname").take(ifirst).to_pylist(), "last_name")
+        for k, c in (("assignee", "Assignee"), ("assignee_number", "AsgNum"),
+                     ("class", "Class")):
+            string_vp(g, Ni, t.column(c).take(pfirst).to_pylist(), k)
+        for k, c in (("app_year", "AppYearStr"), ("grant_year", "GYear")):
+            p = g.new_vp("int")
+            p.a[:Ni] = -1
+            p.a[Ni:] = t.column(c).take(pfirst).fill_null(-1).to_numpy()
+            g.vp[k] = p
+        g.vp.app_date = g.new_vp("int64_t")
+        g.vp.app_date.a[:Ni] = -1
+        g.vp.app_date.a[Ni:] = [to_time(x) for x in
+                                t.column("AppDateStr").take(pfirst).to_pylist()]
+        g.ep.invseq = g.new_ep("int", vals=t.column("InvSeq").fill_null(-1).to_numpy())
+        for k, c in (("latitude", "Lat"), ("longitude", "Lon")):
+            g.ep[k] = g.new_ep("double",
+                               vals=t.column(c).fill_null(math.nan).to_numpy())
+        for k, c in (("city", "City"), ("state", "State"),
+                     ("country", "Country"), ("zipcode", "Zipcode")):
+            string_ep(g, t.column(c).to_pylist(), k)
+        del t
+        yield alt, g