{
  "access": {
    "embargo": {
      "active": false,
      "reason": null
    },
    "files": "public",
    "record": "public",
    "status": "open"
  },
  "created": "2025-07-31T19:11:09.678382+00:00",
  "custom_fields": {
    "code:codeRepository": "https://github.com/AlgebraicJulia/Catlab.jl"
  },
  "deletion_status": {
    "is_deleted": false,
    "status": "P"
  },
  "files": {
    "count": 1,
    "enabled": true,
    "entries": {
      "AlgebraicJulia/Catlab.jl-v0.17.0.zip": {
        "access": {
          "hidden": false
        },
        "checksum": "md5:2a0581f98a6b172756c0090d723ae67b",
        "ext": "zip",
        "id": "d6153914-b6bb-4c52-986b-3cfaad0886fb",
        "key": "AlgebraicJulia/Catlab.jl-v0.17.0.zip",
        "links": {
          "content": "https://zenodo.org/api/records/16649399/files/AlgebraicJulia/Catlab.jl-v0.17.0.zip/content",
          "self": "https://zenodo.org/api/records/16649399/files/AlgebraicJulia/Catlab.jl-v0.17.0.zip"
        },
        "metadata": null,
        "mimetype": "application/zip",
        "size": 657592,
        "storage_class": "L"
      }
    },
    "order": [],
    "total_bytes": 657592
  },
  "id": "16649399",
  "is_draft": false,
  "is_published": true,
  "links": {
    "access": "https://zenodo.org/api/records/16649399/access",
    "access_grants": "https://zenodo.org/api/records/16649399/access/grants",
    "access_links": "https://zenodo.org/api/records/16649399/access/links",
    "access_request": "https://zenodo.org/api/records/16649399/access/request",
    "access_users": "https://zenodo.org/api/records/16649399/access/users",
    "archive": "https://zenodo.org/api/records/16649399/files-archive",
    "archive_media": "https://zenodo.org/api/records/16649399/media-files-archive",
    "communities": "https://zenodo.org/api/records/16649399/communities",
    "communities-suggestions": "https://zenodo.org/api/records/16649399/communities-suggestions",
    "doi": "https://doi.org/10.5281/zenodo.16649399",
    "draft": "https://zenodo.org/api/records/16649399/draft",
    "file_modification": "https://zenodo.org/api/records/16649399/file-modification",
    "files": "https://zenodo.org/api/records/16649399/files",
    "latest": "https://zenodo.org/api/records/16649399/versions/latest",
    "latest_html": "https://zenodo.org/records/16649399/latest",
    "media_files": "https://zenodo.org/api/records/16649399/media-files",
    "parent": "https://zenodo.org/api/records/598366",
    "parent_doi": "https://doi.org/10.5281/zenodo.598366",
    "parent_doi_html": "https://zenodo.org/doi/10.5281/zenodo.598366",
    "parent_html": "https://zenodo.org/records/598366",
    "preview_html": "https://zenodo.org/records/16649399?preview=1",
    "quota_increase": "https://zenodo.org/api/records/16649399/quota-increase",
    "request_deletion": "https://zenodo.org/api/records/16649399/request-deletion",
    "requests": "https://zenodo.org/api/records/16649399/requests",
    "reserve_doi": "https://zenodo.org/api/records/16649399/draft/pids/doi",
    "self": "https://zenodo.org/api/records/16649399",
    "self_doi": "https://doi.org/10.5281/zenodo.16649399",
    "self_doi_html": "https://zenodo.org/doi/10.5281/zenodo.16649399",
    "self_html": "https://zenodo.org/records/16649399",
    "self_iiif_manifest": "https://zenodo.org/api/iiif/record:16649399/manifest",
    "self_iiif_sequence": "https://zenodo.org/api/iiif/record:16649399/sequence/default",
    "versions": "https://zenodo.org/api/records/16649399/versions"
  },
  "media_files": {
    "count": 0,
    "enabled": false,
    "entries": {},
    "order": [],
    "total_bytes": 0
  },
  "metadata": {
    "creators": [
      {
        "affiliations": [
          {
            "name": "@ToposInstitute"
          }
        ],
        "person_or_org": {
          "family_name": "Evan Patterson",
          "name": "Evan Patterson",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Owen Lynch",
          "name": "Owen Lynch",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Micah Halter",
          "name": "Micah Halter",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "University of Florida -- MAE"
          }
        ],
        "person_or_org": {
          "family_name": "James Fairbanks",
          "name": "James Fairbanks",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "Topos Institute"
          }
        ],
        "person_or_org": {
          "family_name": "Kris Brown",
          "name": "Kris Brown",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "Topos Institute"
          }
        ],
        "person_or_org": {
          "family_name": "Kevin Carlson",
          "name": "Kevin Carlson",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Andrew Baas",
          "name": "Andrew Baas",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "@mrc-ide  @dd-harp"
          }
        ],
        "person_or_org": {
          "family_name": "Sean",
          "name": "Sean",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "slibkind",
          "name": "slibkind",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Angeline Aguinaldo",
          "name": "Angeline Aguinaldo",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Matt Cuffaro",
          "name": "Matt Cuffaro",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Samuel Steakley",
          "name": "Samuel Steakley",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "@beacon-biosignals"
          }
        ],
        "person_or_org": {
          "family_name": "Chris de Graaf",
          "name": "Chris de Graaf",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "cbw124",
          "name": "cbw124",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "AlgebraicJulia Bot",
          "name": "AlgebraicJulia Bot",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "University of Saskatchewan"
          }
        ],
        "person_or_org": {
          "family_name": "Xiaoyan Li",
          "name": "Xiaoyan Li",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Luke Morris",
          "name": "Luke Morris",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Tyler Hanks",
          "name": "Tyler Hanks",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Thomas Purdy",
          "name": "Thomas Purdy",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "sjbreiner",
          "name": "sjbreiner",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "University of Trento"
          }
        ],
        "person_or_org": {
          "family_name": "Pietro Monticone",
          "name": "Pietro Monticone",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "Topos Institute"
          }
        ],
        "person_or_org": {
          "family_name": "Michael Lambert",
          "name": "Michael Lambert",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "Max Planck Institute for Biogeochemistry"
          }
        ],
        "person_or_org": {
          "family_name": "Felix Cremer",
          "name": "Felix Cremer",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Christian Scaff",
          "name": "Christian Scaff",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "@PlantingSpace"
          }
        ],
        "person_or_org": {
          "family_name": "Alessandro Cheli",
          "name": "Alessandro Cheli",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Axel Baudot",
          "name": "Axel Baudot",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "Massachusetts Institute of Technology"
          }
        ],
        "person_or_org": {
          "family_name": "Christopher Rackauckas",
          "name": "Christopher Rackauckas",
          "type": "personal"
        }
      },
      {
        "person_or_org": {
          "family_name": "Julia TagBot",
          "name": "Julia TagBot",
          "type": "personal"
        }
      },
      {
        "affiliations": [
          {
            "name": "Google Deepmind"
          }
        ],
        "person_or_org": {
          "family_name": "Logan Kilpatrick",
          "name": "Logan Kilpatrick",
          "type": "personal"
        }
      }
    ],
    "description": "<h2>Catlab v0.17.0</h2>\n<p><a href=\"https://github.com/AlgebraicJulia/Catlab.jl/compare/v0.16.20...v0.17.0\">Diff since v0.16.20</a></p>\n<p>This major release comes with a variety of breaking changes. This guide provides some general advice for getting code which had worked with <code>v0.16</code> to work with <code>v0.17</code>. The difficulty of migrating the code can vary depending on how deep one's code reaches into Catlab's internals. We start with some easy fixes that should apply to most uses of Catlab:</p>\n<h3>Interacting with ACSets</h3>\n<h4><code>ThACSetCategory</code> implementations</h4>\n<p>The main change with ACSets is that that we do not infer from the ACSet itself (or its morphisms) what kind of category of ACSets we are working with. Although we can make educated guesses sometimes, this is in principle extra data that must be supplied whenever working with ACSets categorically. There are a variety of <code>ThACSetCategory</code> implementations which Catlab comes with:</p>\n<p>| Implementation | Has attributes | Mark as Deleted | Has attribute variables | Julia functions in components[^1] |\n|:--:|:--:|:--:|:--:|:--:|\n| <code>CSetCat</code> | $\\times$ | $\\times$ | $\\times$ | $\\times$ |\n| <code>ACSetCat</code> | $\\checkmark$ | $\\times$ | $\\times$ | $\\times$ |\n| <code>MADCSetCat</code> | $\\times$ | $\\checkmark$ | $\\times$ | $\\times$ |\n| <code>MADACSetCat</code> | $\\checkmark$ | $\\checkmark$ | $\\times$ | $\\times$ |\n| <code>VarACSetCat</code> | $\\checkmark$ | $\\times$ | $\\checkmark$ | $\\times$ |\n| <code>MADVarACSetCat</code> | $\\checkmark$ | $\\checkmark$ | $\\checkmark$ | $\\times$ |\n| <code>LooseACSetCat</code> | $\\checkmark$ | $\\times$ | $\\times$ | $\\checkmark$ |</p>\n<p>[^1]: Almost always, when attributes are involved, we want maps between ACSets to preserve the attributes on the nose. However, in the category with &quot;loose ACSetTransformations&quot;, we allow maps between ACSets to include the data of a Julia function is not the identity function for some type.</p>\n<p>Each of these takes in an (arbitrary) <code>ACSet</code> of the kind one wishes to work with. We then wrap the implementation of  <code>ThACSetCategory</code> with its designated wrapper type: <code>ACSetCategory</code>.</p>\n<pre><code>const \ud835\udc9e = ACSetCategory(CSetCat(Graph()))\n</code></pre>\n<h4>Calling methods with <code>ThACSetCategory</code> implementations</h4>\n<p>Now we can use this piece of data as a parameter for various ACSet-related operations. Presently this can happen in two ways, depending on whether the method we are using belongs to a formal interface (via GATlab) or not. For example, if we call <code>methods(coproduct)</code> we'll see a method whose first argument is <code>GATlab.WithModel</code>. This indicates that we should use <code>coproduct</code> like the following:</p>\n<pre><code>G2 = ob(coproduct[\ud835\udc9e](Graph(1), Graph(1))) # instead of: ob(coproduct(Graph(1), Graph(1)))\n</code></pre>\n<p>Other methods haven't yet been put into a formal interface. E.g. <code>is_natural</code> and <code>homomorphism</code> do not have a <code>WithModel</code> parameter, though they do take keyword arguments. In such cases, <code>homomorphism(X,Y; cat=\ud835\udc9e)</code> is how we signal which category we want to work in.[^2]</p>\n<p>[^2]: If the <code>cat</code> kwarg is not provided, most methods will do their best to silently infer what the right category to work in is, based on the ACSet argument provided.</p>\n<p>The hardest place to insert this extra parameter is binary operators like <code>\u2295</code>. These can't be modified with the indexing notation. This is where the <code>@withmodel</code> macro is helpful.</p>\n<pre><code>@withmodel TypedCatWithCoproducts(\ud835\udc9e) (\u2295) begin\n  @test is_isomorphic(G2, Graph(1) \u2295 Graph(1))\nend\n</code></pre>\n<p>As you can see, we presently need to wrap <code>\ud835\udc9e</code> with <code>TypedCatWithCoproducts</code> for this to work. For subobject connectives like <code>\u2227</code>, one can use <code>\ud835\udc9e</code> directly.</p>\n<h4>Interacting with category interface</h4>\n<p>One thing we do with morphisms (including <code>ACSetTransformations</code>) is compose them. This is now parameterized by a choice of implementation of <code>ThCategory</code>. Our <code>\ud835\udc9e</code> from above should be used as a model parameter for <code>compose</code> and <code>id</code>.</p>\n<pre><code>f = ACSetTransformation(G2, Graph(1); V=[1,1], cat=\ud835\udc9e)\nf\u2032 = compose[\ud835\udc9e](id[\ud835\udc9e](G2), f)\n</code></pre>\n<h4>Extensional equality and <code>force</code></h4>\n<p>There are many granularities of equality that one may be interested in. <code>==</code> is quite coarse: <code>f</code> and <code>f\u2032</code> above are not equal under that equivalence relation. However, under <code>\u2243</code> (an operator introduced in <code>v0.17</code>) they are equal. This should be used in place of <code>force(f) == force(f\u2032)</code>.</p>\n<p><code>force</code> can be used to improve the performance of a function by replacing it with an equivalent-behavior one, but this is not always a normal form for comparison of extensional behavior (e.g. <code>id(FinSet(100))</code> when converted to a normal form is much less efficient than just leaving it as an <code>IdentityFunction</code>).</p>\n<h3>Other changes</h3>\n<h4>General</h4>\n<ul>\n<li>Pretty printing may have changed, and some things that previously were pretty printed may not be presently pretty printed at all. This can be fixed piecemeal in the future.</li>\n</ul>\n<h4>SetFunctions/FinFunctions</h4>\n<ul>\n<li>Functions (e.g. <code>FinFunction</code>) previously were able to be applied to a vector, which was taken to mean it should be mapped over its elements. Now, because the function may have a domain which includes vectors as elements, this mapping behavior is best done using Julia's dot notation</li>\n</ul>\n<pre><code>f = FinFunction([3,2,1], 3)\nf(1) == 3\nf.([1,1,3,2]) == [3,3,1,2] # instead of: f([1,1,3,2])\n</code></pre>\n<ul>\n<li><p>It is no longer the case that <code>FinFunction</code> has type parameters for the type of its (co)domain sets. One can get these in a way generic to any implementation of any theory, i.e. <code>impl_type(my_finfunction, :Dom)</code>. Likewise, types in the set hierarchy (<code>FinSet</code>, <code>SetOb</code>) do not have type parameters. These are all wrapper types around models of a particular theory.</p>\n</li>\n<li><p>Catlab no longer infers the codomain of a FinFunction presented by just a vector.</p>\n</li>\n</ul>\n<pre><code>FinFunction([1,2,4], 4) # instead of: FinFunction([1,2,4])\n</code></pre>\n<ul>\n<li><code>TypeSet(T::Type)</code> is now an <em>implementation</em> of <code>ThSet</code> (something which could be wrapped by <code>SetOb</code>), <em>not</em> a <code>SetOb</code> itself. Old code which explicitly uses <code>TypeSet(T)</code> will likely not work, so instead one should use <code>SetOb(T)</code> which is defined to be <code>SetOb(TypeSet(T))</code>. Likewise, <code>ConstantFunction</code> is not a function but an <em>implementation</em> of <code>ThSetFunction</code>. In this case, however, one must manually apply the wrapper type:</li>\n</ul>\n<pre><code># Previously:\n# c = ConstantFunction(&quot;foo&quot;, TypeSet(Int))\n# (dom(c), codom(c)) == (TypeSet(Int), TypeSet(String))\n\nc = SetFunction(ConstantFunction(&quot;foo&quot;, SetOb(Int)))\n(dom(c), codom(c)) == (SetOb(Int), SetOb(String))\n</code></pre>\n<ul>\n<li>There may be subtle differences in how indexing of functions works with composing (e.g. if you (pre/post)compose an indexed <code>FinFunctionVector</code> with some other implementation of <code>FinFunction</code>, is the result indexed?). Trying to make this more systematic or predictable is future work.</li>\n</ul>\n<h4>FreeDiagrams</h4>\n<p><code>FreeDiagram</code> is now the wrapper type for implementations of the <code>ThFreeDiagram</code> interface. What was previously called <code>FreeDiagram</code> is now called <code>FreeGraph</code> (it is itself one particular implementation of <code>ThFreeDiagram</code>).</p>\n<p>Now that <code>(co)dom</code> are model-parameterized methods which are called within the constructor of multi(co)spans, one can pass a <code>cat</code> keyword argument to these constructors. Alternatively, one can provide the feet of the span as a vector as well, in which case <code>(co)dom</code> will not be called when constructing the multi(co)span.</p>\n<h4>FinCats / FinDomFunctors</h4>\n<p>There have been subtle changes to the <code>FinCat</code> and <code>Fin(Dom)Functor</code> constructors, as the previous code really presupposed there are only two types of FinCats (graph-like ones with integers as objects and schema-like ones with symbols/presentation generators as objects). We now have FinFunctors which work with anything which implements <code>ThFinCat</code> (which could in principle be done with any Julia types for <code>Ob</code> and <code>Hom</code>), but the tradeoff is that things that were once unambiguous become ambiguous and more data is required to be specified. For example, one previously could define a <code>FinFunctor</code> via an object mapping, a hom mapping, a source schema, and a target schema. Presently, one should be more explicit: plugging in <code>FinCat</code>s for the (co)domain and using the actual objects/homs of that category in the mappings (which happen to GAT generators, not symbols).</p>\n<pre><code># Previously: \n# F = FinFunctor(Dict(:V =&gt; :El, :E =&gt; :Arr), Dict(:src =&gt; :src, :tgt =&gt; :tgt),\n#                 SchGraph, SchElements)\nV, E, src, tgt = generators(SchGraph)\nEl, Arr, _, _, src\u2032, tgt\u2032, _ = generators(SchElements)\nsrc, tgt = \nF = FinFunctor(Dict(V =&gt; El, E =&gt; Arr), Dict(src =&gt; src\u2032, tgt =&gt; tgt\u2032),\n                FinCat(SchGraph), FinCat(SchElements); homtype=:generator)\n</code></pre>\n<p>Another difference is the <code>homtype</code> keyword argument. If the codomain is itself\na <code>FinCat</code>, it has both <code>Hom</code> and <code>Gen</code> Julia types associated with itself.\nTherefore we can talk about <code>Hom</code>s in the codomain category in one of\nthe four following:</p>\n<ul>\n<li><code>:hom</code>: give an element of <code>Hom</code> directly</li>\n<li><code>:generator</code>: give an element of <code>Gen</code> directly (coerce via <code>to_hom(cod, f)</code>)</li>\n<li><code>:list</code>: give a <em>nonempty</em> list of composable <code>Gen</code> (coerce via <code>compose[cod](to_hom.(cod, f))</code>)</li>\n<li><code>:path</code>: give a <code>Path</code> of composable <code>Gen</code> (where <code>Path</code> enforces composability + also allows representing id maps)</li>\n</ul>\n<p>Previously <code>hom_map(F, f)</code> was used <em>both</em> to apply <code>F</code> to generators and homs in the domain of a <code>Fin(Dom)Functor</code>. To do so now would be ambiguous behavior (if <code>DomGen</code> and <code>DomHom</code> are the same Julia type), so <code>gen_map</code> is new a method one can call.</p>\n<p>The <code>ob_generators</code> and <code>hom_generators</code> methods for a <code>FinCat</code> now each return a <code>FinSet</code> rather than an <code>AbstractVector</code>.</p>\n<h4>Module structure</h4>\n<p>Because the module structure of CategoricalAlgebra has changed, some code that makes reference to this module structure will need to be fixed:</p>\n<pre><code>using CategoricalAlgebra.Cats.FinCats, # instead of : using CategoricalAlgebra.FinCats\n</code></pre>\n<p>The main change is that <code>CategoricalAlgebra</code> got split into four pieces: <code>BasicSets</code> along with four submodules of the new <code>CategoricalAlgebra</code> (<code>Cats</code>, <code>SetCats</code>, <code>Pointwise</code>, and <code>Misc</code>).</p>\n<h3>Regressions</h3>\n<p>The <code>HomomorphismQuery</code> option for computing all the full hom set between two ACSets via a limit computation is currently not yet re-implemented in <code>v0.17</code>. This code is quite complex and will take some time to redo in the future.</p>\n<p>The category of ACSets and LooseACSetTransformations now is defined as having SetFunctions between TypeSets as the category for its attribute types. This means a certain kind of pullback of LooseACSetTransformations (where the components map between <em>finite sets</em>, rather than <code>TypeSet</code>s) is no longer supported.</p>\n<h3>Performance regressions</h3>\n<p>Performance regressions can be introduced in this migration by naive use of the <code>method[model](args...)</code> idiom. This is because this pattern uses dynamic dispatch and as such shouldn't be used in hot loops. If one wants to call a method associated with an interface in a more performant manner, the following style is required:</p>\n<pre><code>compose(WithModel(my_cat), f, g) # clunkier, but better performance than: compose[my_cat](f,g)\n</code></pre>\n<p>Also note the type of <code>my_cat</code> must be known statically.</p>\n<h3>Example migration: AlgebraicPetri</h3>\n<p>The process of updating <a href=\"https://github.com/AlgebraicJulia/AlgebraicPetri.jl\">AlgebraicPetri.jl</a> to work with Catlab 0.17 was addressed in <a href=\"https://github.com/AlgebraicJulia/AlgebraicPetri.jl/pull/181\">this PR</a>. The required changes were:</p>\n<ul>\n<li>No more <code>LooseACSetTransformation</code>: instead stratification limits are in a <code>LooseACSet</code> category of ACSets.</li>\n<li>Some uses of <code>==</code> in the tests replaced with <code>\u2243</code>.</li>\n<li>Components of ACSetTransformations no longer assumed to be <code>FinFunctionVector</code>: to get a vector out of a <code>FinFunction</code> we now call <code>collect(f)</code> instead of <code>f.func</code>.</li>\n<li><code>FinDomFunction</code> ob/hom mappings use presentation generators, not symbols.</li>\n</ul>\n<p>There was one logic error in the previous implementation that was revealed in the update process: when we call <code>flatten_labels</code> to take a stratified model (which has, for example, <code>Name</code> attributes valued in <em>pairs</em> of symbols) and convert it to a regular Petri net (<code>Name</code> valued in just symbols with a <code>_</code> in the middle of the pair), the code previously did not change the components of typing hom that is going out of the model into a typing petri net. This needed to be fixed because otherwise a type error would be encountered (trying to use a function with domain <code>Tuple{String,String}</code>  when a function with domain <code>String</code> was needed).</p>\n<p><strong>Merged pull requests:</strong></p>\n<ul>\n<li>Incorporating GATlab more deeply (#949) (@kris-brown)</li>\n<li>Reorganize CategoricalAlgebra file structure (#955) (@kris-brown)</li>\n<li>add DiagrammaticEquations.jl to downstream.yml (#968) (@jpfairbanks)</li>\n</ul>",
    "publication_date": "2025-07-31",
    "publisher": "Zenodo",
    "related_identifiers": [
      {
        "identifier": "https://github.com/AlgebraicJulia/Catlab.jl/tree/v0.17.0",
        "relation_type": {
          "id": "issupplementto",
          "title": {
            "de": "Erg\u00e4nzt",
            "en": "Is supplement to"
          }
        },
        "resource_type": {
          "id": "software",
          "title": {
            "de": "Software",
            "en": "Software"
          }
        },
        "scheme": "url"
      }
    ],
    "resource_type": {
      "id": "software",
      "title": {
        "de": "Software",
        "en": "Software"
      }
    },
    "rights": [
      {
        "description": {
          "en": "A short and simple permissive license with conditions only requiring preservation of copyright and license notices. Licensed works, modifications, and larger works may be distributed under different terms and without source code."
        },
        "id": "mit",
        "props": {
          "scheme": "spdx",
          "url": "https://opensource.org/licenses/MIT"
        },
        "title": {
          "en": "MIT License"
        }
      }
    ],
    "title": "AlgebraicJulia/Catlab.jl: v0.17.0",
    "version": "v0.17.0"
  },
  "parent": {
    "access": {
      "owned_by": {
        "user": "30943"
      },
      "settings": {
        "accept_conditions_text": null,
        "allow_guest_requests": false,
        "allow_user_requests": false,
        "secret_link_expiration": 0
      }
    },
    "communities": {},
    "id": "598366",
    "pids": {
      "doi": {
        "client": "datacite",
        "identifier": "10.5281/zenodo.598366",
        "provider": "datacite"
      }
    }
  },
  "pids": {
    "doi": {
      "client": "datacite",
      "identifier": "10.5281/zenodo.16649399",
      "provider": "datacite"
    },
    "oai": {
      "identifier": "oai:zenodo.org:16649399",
      "provider": "oai"
    }
  },
  "revision_id": 4,
  "stats": {
    "all_versions": {
      "data_volume": 356175165.0,
      "downloads": 976,
      "unique_downloads": 940,
      "unique_views": 5443,
      "views": 5620
    },
    "this_version": {
      "data_volume": 2630368.0,
      "downloads": 4,
      "unique_downloads": 4,
      "unique_views": 181,
      "views": 183
    }
  },
  "status": "published",
  "swh": {
    "swhid": "swh:1:dir:0784c69ff7e6a4ccd1d84e6306ce8b89e5be60e0;origin=https://doi.org/10.5281/zenodo.598366;visit=swh:1:snp:97089b9123a90bfa7eb67f2ca3f6d9016d69c5b5;anchor=swh:1:rel:2734655c88a1cb51fd0935b5c366c5179be634f7;path=AlgebraicJulia-Catlab.jl-5d6c68f"
  },
  "updated": "2025-07-31T19:11:09.879641+00:00",
  "versions": {
    "index": 100,
    "is_latest": false
  }
}