diff --git a/.github/workflows/gitext.yml b/.github/workflows/gitext.yml deleted file mode 100644 index 1c22a684..00000000 --- a/.github/workflows/gitext.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: Verify external files - -on: [push, pull_request] - -jobs: - verify: - runs-on: ubuntu-latest - strategy: - max-parallel: 5 - - steps: - - uses: actions/checkout@v3 - - name: Verify external files - run: | - ./big_gitext/verify_big.sh -A diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index a4b4efa3..00000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Lint - -on: [push, pull_request] - -jobs: - lint: - runs-on: ubuntu-latest - strategy: - max-parallel: 5 - - steps: - - uses: actions/checkout@v3 - - name: Install tox - id: install-tox - run: | - pip install tox - echo "tox_version=$(pip list | grep tox | tr -d ' ')" >> $GITHUB_OUTPUT - - name: Flake8 annotations matcher - uses: rbialon/flake8-annotations@v1 - - uses: actions/cache@v3 - with: - key: ${{ runner.os }}-${{ steps.install-tox.outputs.tox_version }}-lint-${{ hashFiles('environment.yml', 'tox.ini') }} - path: .tox - - name: Lint with flake8 - run: | - conda install flake8 - # exit-zero treats all errors as warnings. The line length is configured in tox.ini - tox -o -e lint -- --exit-zero --max-complexity=10 --statistics --show-source - # stop the build if there are Python syntax errors or undefined names - tox -o -e lint -- --count --select=E9,F63,F7,F82 --statistics >/dev/null diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7503ca42..c9aefeb3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,24 +1,28 @@ -name: Test +name: Python package -on: [push, pull_request] +on: [push,pull_request] jobs: - test: + build: runs-on: ubuntu-latest strategy: + matrix: + python-version: ["3.9"] max-parallel: 5 - steps: - - uses: actions/checkout@v3 - - name: Install tox - id: install-tox - run: | - pip install tox - echo "tox_version=$(pip list | grep tox | tr -d ' ')" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 - with: - key: ${{ runner.os }}-${{ steps.install-tox.outputs.tox_version }}-test-${{ hashFiles('environment.yml', 'tox.ini') }} - path: .tox - - name: Test with tox - run: | - tox -o + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Set up Conda + uses: conda-incubator/setup-miniconda@v2 + with: + environment-file: environment.yml + + - name: Test with pytest + run: | + wget https://files.dice-research.org/projects/Ontolearn/KGs.zip + unzip KGs.zip + conda run -n test pytest -p no:warnings -x \ No newline at end of file diff --git a/KGs/Biopax/biopax.owl b/KGs/Biopax/biopax.owl deleted file mode 100644 index 579c623c..00000000 --- a/KGs/Biopax/biopax.owl +++ /dev/null @@ -1,7504 +0,0 @@ - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - A cell type, e.g. 'HeLa'. This should reference a term in a controlled vocabulary of cell types. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The controlling entity, e.g., in a biochemical reaction, an enzyme is the controlling entity of the reaction. CONTROLLER is a sub-property of PARTICIPANTS. - - - - - - - - - - - A free text description of the source of this data, e.g. a database or person name. This property should be used to describe the source of the data. This is meant to be used by databases that export their data to the BioPAX format or by systems that are integrating data from multiple sources. The granularity of use (specifying the data source in many or few instances) is up to the user. It is intended that this property report the last data source, not all data sources that the data has passed through from creation. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The experimental forms associated with an evidence instance. - - - - - - - - - - Descriptor of this experimental form from a controlled vocabulary. - - - - - - - - - - Location of the feature on the sequence of the interactor. One feature may have more than one location, used e.g. for features which involve sequence positions close in the folded, three-dimensional state of a protein, but non-continuous along the sequence. - - - - - - - - - - - - - - - - - - - - - - - - - - - - This quantity is dimensionless and is usually a single number. The measured equilibrium constant for a biochemical reaction, encoded by the slot KEQ, is actually the apparent equilibrium constant, K'. Concentrations in the equilibrium constant equation refer to the total concentrations of all forms of particular biochemical reactants. For example, in the equilibrium constant equation for the biochemical reaction in which ATP is hydrolyzed to ADP and inorganic phosphate: - -K' = [ADP][P<sub>i</sub>]/[ATP], - -The concentration of ATP refers to the total concentration of all of the following species: - -[ATP] = [ATP<sup>4-</sup>] + [HATP<sup>3-</sup>] + [H<sub>2</sub>ATP<sup>2-</sup>] + [MgATP<sup>2-</sup>] + [MgHATP<sup>-</sup>] + [Mg<sub>2</sub>ATP]. - -The apparent equilibrium constant is formally dimensionless, and can be kept so by inclusion of as many of the terms (1 mol/dm<sup>3</sup>) in the numerator or denominator as necessary. It is a function of temperature (T), ionic strength (I), pH, and pMg (pMg = -log<sub>10</sub>[Mg<sup>2+</sup>]). Therefore, these quantities must be specified to be precise, and values for KEQ for biochemical reactions may be represented as 5-tuples of the form (K' T I pH pMg). This property may have multiple values, representing different measurements for K' obtained under the different experimental conditions listed in the 5-tuple. (This definition adapted from EcoCyc) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The end position of a sequence interval. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The authors of this publication, one per property value. - - - - - - - - - - Describes the availability of this data (e.g. a copyright statement). - - - - - - - - - - The chemical formula of the small molecule. Note: chemical formula can also be stored in the STRUCTURE property (in CML). In case of disagreement between the value of this property and that in the CML file, the CML value takes precedence. - - - - - - - - - - Comment on the data in the container class. This property should be used instead of the OWL documentation elements (rdfs:comment) for instances because information in COMMENT is data to be exchanged, whereas the rdfs:comment field is used for metadata about the structure of the BioPAX ontology. - - - - - - - - - - - - - - - - - The value of the confidence measure. - - - - - - - - - - - - - - - - ACTIVATION - - - - ACTIVATION-ALLOSTERIC - - - - ACTIVATION-NONALLOSTERIC - - - - INHIBITION - - - - INHIBITION-ALLOSTERIC - - - - INHIBITION-COMPETITIVE - - - - INHIBITION-IRREVERSIBLE - - - - INHIBITION-NONCOMPETITIVE - - - - INHIBITION-OTHER - - - - INHIBITION-UNCOMPETITIVE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The name of the external database to which this xref refers. - - - - - - - - - - The version of the external database in which this xref was last known to be valid. Resources may have recommendations for referencing dataset versions. For instance, the Gene Ontology recommends listing the date the GO terms were downloaded. - - - - - - - - - - For biochemical reactions, this property refers to the standard transformed Gibbs energy change for a reaction written in terms of biochemical reactants (sums of species), delta-G'<sup>o</sup>. - - delta-G'<sup>o</sup> = -RT lnK' -and - delta-G'<sup>o</sup> = delta-H'<sup>o</sup> - T delta-S'<sup>o</sup> - -delta-G'<sup>o</sup> has units of kJ/mol. Like K', it is a function of temperature (T), ionic strength (I), pH, and pMg (pMg = -log<sub>10</sub>[Mg<sup>2+</sup>]). Therefore, these quantities must be specified, and values for DELTA-G for biochemical reactions are represented as 5-tuples of the form (delta-G'<sup>o</sup> T I pH pMg). - -(This definition from EcoCyc) - - - - - - - - - - For biochemical reactions, this property refers to the standard transformed enthalpy change for a reaction written in terms of biochemical reactants (sums of species), delta-H'<sup>o</sup>. - - delta-G'<sup>o</sup> = delta-H'<sup>o</sup> - T delta-S'<sup>o</sup> - -Units: kJ/mole - -(This definition from EcoCyc) - - - - - - - - - - For biochemical reactions, this property refers to the standard transformed entropy change for a reaction written in terms of biochemical reactants (sums of species), delta-S'<sup>o</sup>. - - delta-G'<sup>o</sup> = delta-H'<sup>o</sup> - T delta-S'<sup>o</sup> - -(This definition from EcoCyc) - - - - - - - - - - Specifies the reaction direction of the interaction catalyzed by this instance of the catalysis class. - -Possible values of this slot are: - -REVERSIBLE: Interaction occurs in both directions in physiological settings. - -PHYSIOL-LEFT-TO-RIGHT -PHYSIOL-RIGHT-TO-LEFT -The interaction occurs in the specified direction in physiological settings, because of several possible factors including the energetics of the reaction, local concentrations -of reactants and products, and the regulation of the enzyme or its expression. - -IRREVERSIBLE-LEFT-TO-RIGHT -IRREVERSIBLE-RIGHT-TO-LEFT -For all practical purposes, the interactions occurs only in the specified direction in physiological settings, because of chemical properties of the reaction. - -(This definition from EcoCyc) - - - - - - - IRREVERSIBLE-LEFT-TO-RIGHT - - - - IRREVERSIBLE-RIGHT-TO-LEFT - - - - PHYSIOL-LEFT-TO-RIGHT - - - - PHYSIOL-RIGHT-TO-LEFT - - - - REVERSIBLE - - - - - - - - - - - - - - - - - - - - - The unique number assigned to a reaction by the Enzyme Commission of the International Union of Biochemistry and Molecular Biology. - -Note that not all biochemical reactions currently have EC numbers assigned to them. - - - - - - - - - - The primary identifier in the external database of the object to which this xref refers. - - - - - - - - - - The version number of the identifier (ID). E.g. The RefSeq accession number NM_005228.3 should be split into NM_005228 as the ID and 3 as the ID-VERSION. - - - - - - - - - - The ionic strength is defined as half of the total sum of the concentration (ci) of every ionic species (i) in the solution times the square of its charge (zi). For example, the ionic strength of a 0.1 M solution of CaCl2 is 0.5 x (0.1 x 22 + 0.2 x 12) = 0.3 M -(Definition from http://www.lsbu.ac.uk/biology/enztech/ph.html) - - - - - - - - - - - - - - - - - - - - - - - - - - Defines the molecular weight of the molecule, in daltons. - - - - - - - - - - The preferred full name for this entity. - - - - - - - - - - - - - - - - - - - A measure of acidity and alkalinity of a solution that is a number on a scale on which a value of 7 represents neutrality and lower numbers indicate increasing acidity and higher numbers increasing alkalinity and on which each unit of change represents a tenfold change in acidity or alkalinity and that is the negative logarithm of the effective hydrogen-ion concentration or hydrogen-ion activity in gram equivalents per liter of the solution. (Definition from Merriam-Webster Dictionary) - - - - - - - - - - - - - - - - - A measure of the concentration of magnesium (Mg) in solution. (pMg = -log<sub>10</sub>[Mg<sup>2+</sup>]) - - - - - - - - - - - - - - - - - The confidence status of the sequence position. This could be: -EQUAL: The SEQUENCE-POSITION is known to be at the SEQUENCE-POSITION. -GREATER-THAN: The site is greater than the SEQUENCE-POSITION. -LESS-THAN: The site is less than the SEQUENCE-POSITION. - - - - - - - EQUAL - - - - GREATER-THAN - - - - LESS-THAN - - - - - - - - - - - - - - - - - This property names the type of relationship between the BioPAX object linked from, and the external object linked to, such as 'gene of this protein', or 'protein with similar sequence'. - - - - - - - - - - Polymer sequence in uppercase letters. For DNA, usually A,C,G,T letters representing the nucleosides of adenine, cytosine, guanine and thymine, respectively; for RNA, usually A, C, U, G; for protein, usually the letters corresponding to the 20 letter IUPAC amino acid code. - - - - - - - - - - - - - - - - - - The integer listed gives the position. The first base or amino acid is position 1. In combination with the numeric value, the property 'POSITION-STATUS' allows to express fuzzy positions, e.g. 'less than 4'. - - - - - - - - - - An abbreviated name for this entity, preferably a name that is short enough to be used in a visualization application to label a graphical element that represents this entity. If no short name is available, an xref may be used for this purpose by the visualization application. - - - - - - - - - - - - - - - - - The source in which the reference was published, such as: a book title, or a journal title and volume and pages. - - - - - - - - - - Specifies whether a conversion occurs spontaneously (i.e. uncatalyzed, under biological conditions) left-to-right, right-to-left, or not at all. If the spontaneity is not known, the SPONTANEOUS property should be left empty. - - - - - - - L-R - - - - NOT-SPONTANEOUS - - - - R-L - - - - - - - - - - - - - - - - - Each value of this property represents the stoichiometric coefficient for one of the physical entities in an interaction or complex. For a given interaction, the stoichiometry should always be used where possible instead of representing the number of participants with separate instances of each participant. If there are three ATP molecules, one ATP molecule should be represented as a participant and the stoichiometry should be set to 3. - - - - - - - - - - This property holds a string of data defining chemical structure or other information, in either the CML or SMILES format, as specified in property Structure-Format. If, for example, the CML format is used, then the value of this property is a string containing the XML encoding of the CML data. - - - - - - - - - - This property specifies which format is used to define chemical structure data. - - - - - - - CML - - - - InChI - - - - SMILES - - - - - - - - - - - - - - - - - One or more synonyms for the name of this entity. This should include the values of the NAME and SHORT-NAME property so that it is easy to find all known names in one place. - - - - - - - - - - - - - - - - - Temperature in Celsius - - - - - - - - - - - - - - - - - The external controlled vocabulary term. - - - - - - - - - - The title of the publication. - - - - - - - - - - The URL at which the publication can be found, if it is available through the Web. - - - - - - - - - - The year in which this publication was published. - - - - - - - - - - - - - - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - - - Definition: The biological source of an entity (e.g. protein, RNA or DNA). Some entities are considered source-neutral (e.g. small molecules), and the biological source of others can be deduced from their constituentss (e.g. complex, pathway). -Examples: HeLa cells, human, and mouse liver tissue. - - - - - - - - - - Definition: A conversion interaction in which one or more entities (substrates) undergo covalent changes to become one or more other entities (products). The substrates of biochemical reactions are defined in terms of sums of species. This is convention in biochemistry, and, in principle, all of the EC reactions should be biochemical reactions. -Examples: ATP + H2O = ADP + Pi -Comment: In the example reaction above, ATP is considered to be an equilibrium mixture of several species, namely ATP4-, HATP3-, H2ATP2-, MgATP2-, MgHATP-, and Mg2ATP. Additional species may also need to be considered if other ions (e.g. Ca2+) that bind ATP are present. Similar considerations apply to ADP and to inorganic phosphate (Pi). When writing biochemical reactions, it is not necessary to attach charges to the biochemical reactants or to include ions such as H+ and Mg2+ in the equation. The reaction is written in the direction specified by the EC nomenclature system, if applicable, regardless of the physiological direction(s) in which the reaction proceeds. Polymerization reactions involving large polymers whose structure is not explicitly captured should generally be represented as unbalanced reactions in which the monomer is consumed but the polymer remains unchanged, e.g. glycogen + glucose = glycogen. - - - - - - - - - - - - - - - - - - 1 - - - - - - 1 - - - - - - ACTIVATION - - - - - - 1 - - - - Definition: A control interaction in which a physical entity (a catalyst) increases the rate of a conversion interaction by lowering its activation energy. Instances of this class describe a pairing between a catalyzing entity and a catalyzed conversion. -Comment: A separate catalysis instance should be created for each different conversion that a physicalEntity may catalyze and for each different physicalEntity that may catalyze a conversion. For example, a bifunctional enzyme that catalyzes two different biochemical reactions would be linked to each of those biochemical reactions by two separate instances of the catalysis class. Also, catalysis reactions from multiple different organisms could be linked to the same generic biochemical reaction (a biochemical reaction is generic if it only includes small molecules). Generally, the enzyme catalyzing a conversion is known and the use of this class is obvious. In the cases where a catalyzed reaction is known to occur but the enzyme is not known, a catalysis instance should be created without a controller specified (i.e. the CONTROLLER property should remain empty). -Synonyms: facilitation, acceleration. -Examples: The catalysis of a biochemical reaction by an enzyme, the enabling of a transport interaction by a membrane pore complex, and the facilitation of a complex assembly by a scaffold protein. Hexokinase -> (The "Glucose + ATP -> Glucose-6-phosphate +ADP" reaction). A plasma membrane Na+/K+ ATPase is an active transporter (antiport pump) using the energy of ATP to pump Na+ out of the cell and K+ in. Na+ from cytoplasm to extracellular space would be described in a transport instance. K+ from extracellular space to cytoplasm would be described in a transport instance. The ATPase pump would be stored in a catalysis instance controlling each of the above transport instances. A biochemical reaction that does not occur by itself under physiological conditions, but has been observed to occur in the presence of cell extract, likely via one or more unknown enzymes present in the extract, would be stored in the CONTROLLED property, with the CONTROLLER property empty. - - - - - - - - - - - - 1 - - - - - - 1 - - - - - - - - - - - - - Definition: Describes a small molecule structure. Structure information is stored in the property STRUCTURE-DATA, in one of three formats: the CML format (see URL www.xml-cml.org), the SMILES format (see URL www.daylight.com/dayhtml/smiles/) or the InChI format (http://www.iupac.org/inchi/). The STRUCTURE-FORMAT property specifies which format is used. -Comment: By virtue of the expressivity of CML, an instance of this class can also provide additional information about a small molecule, such as its chemical formula, names, and synonyms, if CML is used as the structure format. -Examples: The following SMILES string, which describes the structure of glucose-6-phosphate: -'C(OP(=O)(O)O)[CH]1([CH](O)[CH](O)[CH](O)[CH](O)O1)'. - - - - - - - - - - - - - Definition: A physical entity whose structure is comprised of other physical entities bound to each other non-covalently, at least one of which is a macromolecule (e.g. protein, DNA, or RNA). Complexes must be stable enough to function as a biological unit; in general, the temporary association of an enzyme with its substrate(s) should not be considered or represented as a complex. A complex is the physical product of an interaction (complexAssembly) and is not itself considered an interaction. -Comment: In general, complexes should not be defined recursively so that smaller complexes exist within larger complexes, i.e. a complex should not be a COMPONENT of another complex (see comments on the COMPONENT property). The boundaries on the size of complexes described by this class are not defined here, although elements of the cell as large and dynamic as, e.g., a mitochondrion would typically not be described using this class (later versions of this ontology may include a cellularComponent class to represent these). The strength of binding and the topology of the components cannot be described currently, but may be included in future versions of the ontology, depending on community need. -Examples: Ribosome, RNA polymerase II. Other examples of this class include complexes of multiple protein monomers and complexes of proteins and small molecules. - - - - - - - - - - Definition: A conversion interaction in which a set of physical entities, at least one being a macromolecule (e.g. protein, RNA, DNA), aggregate via non-covalent interactions. One of the participants of a complexAssembly must be an instance of the class complex (via a physicalEntityParticipant instance). -Comment: This class is also used to represent complex disassembly. The assembly or disassembly of a complex is often a spontaneous process, in which case the direction of the complexAssembly (toward either assembly or disassembly) should be specified via the SPONTANEOUS property. -Synonyms: aggregation, complex formation -Examples: Assembly of the TFB2 and TFB3 proteins into the TFIIH complex, and assembly of the ribosome through aggregation of its subunits. -Note: The following are not examples of complex assembly: Covalent phosphorylation of a protein (this is a biochemicalReaction); the TFIIH complex itself (this is an instance of the complex class, not the complexAssembly class). - - - - - - - - - - - - 1 - - - - - - 1 - - - - - - - - - - - - - - - - - - Definition: Confidence that the containing instance actually occurs or exists in vivo, usually a statistical measure. The xref must contain at least on publication that describes the method used to determine the confidence. There is currently no standard way of describing confidence values, so any string is valid for the confidence value. In the future, a controlled vocabulary of accepted confidence values could become available, in which case it will likely be adopted for use here to describe the value. -Examples: The statistical significance of a result, e.g. "p<0.05". - - - - - - - - - - - - 1 - - - - Definition: An interaction in which one entity regulates, modifies, or otherwise influences another. Two types of control interactions are defined: activation and inhibition. -Comment: In general, the targets of control processes (i.e. occupants of the CONTROLLED property) should be interactions. Conceptually, physical entities are involved in interactions (or events) and the events should be controlled or modified, not the physical entities themselves. For example, a kinase activating a protein is a frequent event in signaling pathways and is usually represented as an 'activation' arrow from the kinase to the substrate in signaling diagrams. This is an abstraction that can be ambiguous out of context. In BioPAX, this information should be captured as the kinase catalyzing (via an instance of the catalysis class) a reaction in which the substrate is phosphorylated, instead of as a control interaction in which the kinase activates the substrate. Since this class is a superclass for specific types of control, instances of the control class should only be created when none of its subclasses are applicable. -Synonyms: regulation, mediation -Examples: A small molecule that inhibits a pathway by an unknown mechanism controls the pathway. - - - - - - - - - - - - 1 - - - - - - - - - Definition: An interaction in which one or more entities is physically transformed into one or more other entities. -Comment: This class is designed to represent a simple, single-step transformation. Multi-step transformations, such as the conversion of glucose to pyruvate in the glycolysis pathway, should be represented as pathways, if known. Since it is a highly abstract class in the ontology, instances of the conversion class should never be created. -Examples: A biochemical reaction converts substrates to products, the process of complex assembly converts single molecules to a complex, transport converts entities in one compartment to the same entities in another compartment. - - - - - - - - - - - - - - - - - - - - - - - - Definition: The direct source of this data. This does not store the trail of sources from the generation of the data to this point, only the last known source, such as a database. The XREF property may contain a publicationXref referencing a publication describing the data source (e.g. a database publication). A unificationXref may be used e.g. when pointing to an entry in a database of databases describing this database. -Examples: A database or person name. - - - - - - - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - - - - - - - - Definition: For biochemical reactions, this property refers to the standard transformed Gibbs energy change for a reaction written in terms of biochemical reactants (sums of species), delta-G'<sup>o</sup>. - - delta-G'<sup>o</sup> = -RT lnK' -and - delta-G'<sup>o</sup> = delta-H'<sup>o</sup> - T delta-S'<sup>o</sup> - -delta-G'<sup>o</sup> has units of kJ/mol. Like K', it is a function of temperature (T), ionic strength (I), pH, and pMg (pMg = -log<sub>10</sub>[Mg<sup>2+</sup>]). Therefore, these quantities must be specified, and values for DELTA-G for biochemical reactions are represented as 5-tuples of the form (delta-G'<sup>o</sup> T I pH pMg). This property may have multiple values, representing different measurements for delta-G'<sup>o</sup> obtained under the different experimental conditions listed in the 5-tuple. - -(This definition from EcoCyc) - - - - - - - - - - - - Definition: A physical entity consisting of a sequence of deoxyribonucleotide monophosphates; a deoxyribonucleic acid. -Comment: This is not a 'gene', since gene is a genetic concept, not a physical entity. The concept of a gene may be added later in BioPAX. -Examples: a chromosome, a plasmid. A specific example is chromosome 7 of Homo sapiens. - - - - - - - - - - - - 1 - - - - - - 1 - - - - Definition: A discrete biological unit used when describing pathways. -Comment: This is the root class for all biological concepts in the ontology, which include pathways, interactions and physical entities. As the most abstract class in the ontology, instances of the entity class should never be created. Instead, more specific classes should be used. -Synonyms: thing, object, bioentity. - - - - - - - - - - - - - - 1 - - - - 1 - - - - 1 - - - - - - - - - - - - Definition: The support for a particular assertion, such as the existence of an interaction or pathway. At least one of CONFIDENCE, EVIDENCE-CODE, or EXPERIMENTAL-FORM must be instantiated when creating an evidence instance. XREF may reference a publication describing the experimental evidence using a publicationXref or may store a description of the experiment in an experimental description database using a unificationXref (if the referenced experiment is the same) or relationshipXref (if it is not identical, but similar in some way e.g. similar in protocol). Evidence is meant to provide more information than just an xref to the source paper. -Examples: A description of a molecular binding assay that was used to detect a protein-protein interaction. - - - - - - - - - - - - 1 - - - - - - 1 - - - - - - - - - Definition: The form of a physical entity in a particular experiment, as it may be modified for purposes of experimental design. -Examples: A His-tagged protein in a binding assay. A protein can be tagged by multiple tags, so can have more than 1 experimental form type terms - - - - - - - - - - - - - - Definition: A pointer to an external object, such as an entry in a database or a term in a controlled vocabulary. -Comment: This class is for organizational purposes only; direct instances of this class should not be created. - - - - - - - - - - - - - - - - - - - - - - - - Definition: A single biological relationship between two or more entities. An interaction cannot be defined without the entities it relates. -Comment: Since it is a highly abstract class in the ontology, instances of the interaction class should never be created. Instead, more specific classes should be used. Currently this class only has subclasses that define physical interactions; later levels of BioPAX may define other types of interactions, such as genetic (e.g. synthetic lethal). -Naming rationale: A number of names were considered for this concept, including "process", "synthesis" and "relationship"; Interaction was chosen as it is understood by biologists in a biological context and is compatible with PSI-MI. -Examples: protein-protein interaction, biochemical reaction, enzyme catalysis - - - - - - - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - - - - Definition: The apparent equilibrium constant, K', and associated values. Concentrations in the equilibrium constant equation refer to the total concentrations of all forms of particular biochemical reactants. For example, in the equilibrium constant equation for the biochemical reaction in which ATP is hydrolyzed to ADP and inorganic phosphate: - -K' = [ADP][P<sub>i</sub>]/[ATP], - -The concentration of ATP refers to the total concentration of all of the following species: - -[ATP] = [ATP<sup>4-</sup>] + [HATP<sup>3-</sup>] + [H<sub>2</sub>ATP<sup>2-</sup>] + [MgATP<sup>2-</sup>] + [MgHATP<sup>-</sup>] + [Mg<sub>2</sub>ATP]. - -The apparent equilibrium constant is formally dimensionless, and can be kept so by inclusion of as many of the terms (1 mol/dm<sup>3</sup>) in the numerator or denominator as necessary. It is a function of temperature (T), ionic strength (I), pH, and pMg (pMg = -log<sub>10</sub>[Mg<sup>2+</sup>]). Therefore, these quantities must be specified to be precise, and values for KEQ for biochemical reactions may be represented as 5-tuples of the form (K' T I pH pMg). This property may have multiple values, representing different measurements for K' obtained under the different experimental conditions listed in the 5-tuple. (This definition adapted from EcoCyc) - -See http://www.chem.qmul.ac.uk/iubmb/thermod/ for a thermodynamics tutorial. - - - - - - - - - - - - 1 - - - - - - - - - - - - 1 - - - Definition: A control interaction in which a physical entity modulates a catalysis interaction. Biologically, most modulation interactions describe an interaction in which a small molecule alters the ability of an enzyme to catalyze a specific reaction. Instances of this class describe a pairing between a modulating entity and a catalysis interaction. -Comment: A separate modulation instance should be created for each different catalysis instance that a physical entity may modulate and for each different physical entity that may modulate a catalysis instance. A typical modulation instance has a small molecule as the controller entity and a catalysis instance as the controlled entity. -Examples: Allosteric activation and competitive inhibition of an enzyme's ability to catalyze a specific reaction. - - - - - - - - - - - - - - - - Definition: Used to import terms from external controlled vocabularies (CVs) into the ontology. To support consistency and compatibility, open, freely available CVs should be used whenever possible, such as the Gene Ontology (GO) or other open biological CVs listed on the OBO website (http://obo.sourceforge.net/). -Comment: The ID property in unification xrefs to GO and other OBO ontologies should include the ontology name in the ID property (e.g. ID="GO:0005634" instead of ID="0005634"). - - - - - - - - - - - - 1 - - - - Definition: A set or series of interactions, often forming a network, which biologists have found useful to group together for organizational, historic, biophysical or other reasons. -Comment: It is possible to define a pathway without specifying the interactions within the pathway. In this case, the pathway instance could consist simply of a name and could be treated as a 'black box'. -Synonyms: network -Examples: glycolysis, valine biosynthesis - - - - - - - - - - - - 1 - - - - - - Definition: A step in a pathway. -Comment: Multiple interactions may occur in a pathway step, each should be listed in the STEP-INTERACTIONS property. Order relationships between pathway steps may be established with the NEXT-STEP slot. This order may not be temporally meaningful for specific steps, such as for a pathway loop or a reversible reaction, but represents a directed graph of step relationships that can be useful for describing the overall flow of a pathway, as may be useful in a pathway diagram. -Example: A metabolic pathway may contain a pathway step composed of one biochemical reaction (BR1) and one catalysis (CAT1) instance, where CAT1 describes the catalysis of BR1. - - - - - - - - - Definition: An entity with a physical structure. A pool of entities, not a specific molecular instance of an entity in a cell. -Comment: This class serves as the super-class for all physical entities, although its current set of subclasses is limited to molecules. As a highly abstract class in the ontology, instances of the physicalEntity class should never be created. Instead, more specific classes should be used. -Synonyms: part, interactor, object -Naming rationale: It's difficult to find a name that encompasses all of the subclasses of this class without being too general. E.g. PSI-MI uses 'interactor', BIND uses 'object', BioCyc uses 'chemicals'. physicalEntity seems to be a good name for this specialization of entity. -Examples: protein, small molecule, RNA - - - - - - - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - - Definition: Any additional special characteristics of a physical entity in the context of an interaction or complex. These currently include stoichiometric coefficient and cellular location, but this list may be expanded in later levels. -Comment: PhysicalEntityParticipants should not be used in multiple interaction or complex instances. Instead, each interaction and complex should reference its own unique set of physicalEntityParticipants. The reason for this is that a user may add new information about a physicalEntityParticipant for one interaction or complex, such as the presence of a previously unknown post-translational modification, and unwittingly invalidate the physicalEntityParticipant for the other interactions or complexes that make use of it. -Example: In the interaction describing the transport of L-arginine into the cytoplasm in E. coli, the LEFT property in the interaction would be filled with an instance of physicalEntityParticipant that specified the location of L-arginine as periplasm and the stoichiometric coefficient as one. - - - - - - - - - - - - - - - Definition: An interaction in which at least one participant is a physical entity, e.g. a binding event. -Comment: This class should be used by default for representing molecular interactions, such as those defined by PSI-MI level 2. The participants in a molecular interaction should be listed in the PARTICIPANTS slot. Note that this is one of the few cases in which the PARTICPANT slot should be directly populated with instances (see comments on the PARTICPANTS property in the interaction class description). If sufficient information on the nature of a molecular interaction is available, a more specific BioPAX interaction class should be used. -Example: Two proteins observed to interact in a yeast-two-hybrid experiment where there is not enough experimental evidence to suggest that the proteins are forming a complex by themselves without any indirect involvement of other proteins. This is the case for most large-scale yeast two-hybrid screens. - - - - - - - - - - - - 1 - - - - - - 1 - - - - - Definition: A physical entity consisting of a sequence of amino acids; a protein monomer; a single polypeptide chain. -Examples: The epidermal growth factor receptor (EGFR) protein. - - - - - - - - - - - - 1 - - - - - - 1 - - - - - Definition: An xref that defines a reference to a publication such as a book, journal article, web page, or software manual. The reference may or may not be in a database, although references to PubMed are preferred when possible. The publication should make a direct reference to the instance it is attached to. -Comment: Publication xrefs should make use of PubMed IDs wherever possible. The DB property of an xref to an entry in PubMed should use the string "PubMed" and not "MEDLINE". -Examples: PubMed:10234245 - - - - - - - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - Definition: An xref that defines a reference to an entity in an external resource that does not have the same biological identity as the referring entity. -Comment: There is currently no controlled vocabulary of relationship types for BioPAX, although one will be created in the future if a need develops. -Examples: A link between a gene G in a BioPAX data collection, and the protein product P of that gene in an external database. This is not a unification xref because G and P are different biological entities (one is a gene and one is a protein). Another example is a relationship xref for a protein that refers to the Gene Ontology biological process, e.g. 'immune response,' that the protein is involved in. - - - - - - - - - - - - 1 - - - - - - 1 - - - - Definition: A physical entity consisting of a sequence of ribonucleotide monophosphates; a ribonucleic acid. -Examples: messengerRNA, microRNA, ribosomalRNA. A specific example is the let-7 microRNA. - - - - - - - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - - - Definition: A feature on a sequence relevant to an interaction, such as a binding site or post-translational modification. -Examples: A phosphorylation on a protein. - - - - - - - - - - - - 1 - - - - - - 1 - - - - Definition: Describes an interval on a sequence. All of the sequence from the begin site to the end site (inclusive) is described, not any subset. - - - - - - - - - Definition: A location on a nucleotide or amino acid sequence. -Comment: For organizational purposes only; direct instances of this class should not be created. - - - - - - - - - Definition: A DNA, RNA or protein participant in an interaction. -Comment: See physicalEntityParticipant for more documentation. - - - - - - - - - - - - 1 - - - - - - 1 - - - Definition: Describes a site on a sequence, i.e. the position of a single nucleotide or amino acid. - - - - - - - - - - - - 1 - - - - - - 1 - - - Definition: Any bioactive molecule that is not a peptide, DNA, or RNA. Generally these are non-polymeric, but complex carbohydrates are not explicitly modeled as classes in this version of the ontology, thus are forced into this class. -Comment: Recently, a number of small molecule databases have become available to cross-reference from this class. -Examples: glucose, penicillin, phosphatidylinositol - - - - - - - - - Definition: A conversion interaction in which an entity (or set of entities) changes location within or with respect to the cell. A transport interaction does not include the transporter entity, even if one is required in order for the transport to occur. Instead, transporters are linked to transport interactions via the catalysis class. -Comment: Transport interactions do not involve chemical changes of the participant(s). These cases are handled by the transportWithBiochemicalReaction class. -Synonyms: translocation. -Examples: The movement of Na+ into the cell through an open voltage-gated channel. - - - - - - - - - - Definition: A conversion interaction that is both a biochemicalReaction and a transport. In transportWithBiochemicalReaction interactions, one or more of the substrates change both their location and their physical structure. Active transport reactions that use ATP as an energy source fall under this category, even if the only covalent change is the hydrolysis of ATP to ADP. -Comment: This class was added to support a large number of transport events in pathway databases that have a biochemical reaction during the transport process. It is not expected that other double inheritance subclasses will be added to the ontology at the same level as this class. -Examples: In the PEP-dependent phosphotransferase system, transportation of sugar into an E. coli cell is accompanied by the sugar's phosphorylation as it crosses the plasma membrane. - - - - - - - - - - - - 1 - - - - - - 1 - - - Definition: A unification xref defines a reference to an entity in an external resource that has the same biological identity as the referring entity. For example, if one wished to link from a database record, C, describing a chemical compound in a BioPAX data collection to a record, C', describing the same chemical compound in an external database, one would use a unification xref since records C and C' describe the same biological identity. Generally, unification xrefs should be used whenever possible, although there are cases where they might not be useful, such as application to application data exchange. -Comment: Unification xrefs in physical entities are essential for data integration, but are less important in interactions. This is because unification xrefs on the physical entities in an interaction can be used to compute the equivalence of two interactions of the same type. An xref in a protein pointing to a gene, e.g. in the LocusLink database17, would not be a unification xref since the two entities do not have the same biological identity (one is a protein, the other is a gene). Instead, this link should be a captured as a relationship xref. References to an external controlled vocabulary term within the OpenControlledVocabulary class should use a unification xref where possible (e.g. GO:0005737). -Examples: An xref in a protein instance pointing to an entry in the Swiss-Prot database, and an xref in an RNA instance pointing to the corresponding RNA sequence in the RefSeq database.. - - - - - - - - Definition: Utility classes are created when simple slots are insufficient to describe an aspect of an entity or to increase compatibility of this ontology with other standards. The utilityClass class is actually a metaclass and is only present to organize the other helper classes under one class hierarchy; instances of utilityClass should never be created. - - - - - - - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - - - - 1 - - - Definition: A reference from an instance of a class in this ontology to an object in an external resource. -Comment: Instances of the xref class should never be created and more specific classes should be used instead. - - - - - - - - - - - - - - Escherichia coli K-12 - - - - - - - - - - 2.7.1.40 - phosphoenolpyruvate dephosphorylation - pyruvate phosphorylation - - - - - - - - - - - - - - -3.4 - 2.7.1.11 - 6PFRUCTPHOS-RXN - This is a key control step in glycolysis |CITS: [79100775]| - fructose-6-phosphate phosphorylation - - - - - - - - - - - - - - - - 1.2.1.12 - 1.5 - GAPDH - TRIOSEPHOSPHATE DEHYDROGENASE - glyceraldehyde 3-phosphate oxidation - - - - - - - - - - - - - - - 2.7.2.3 - In this reaction a phosphoryl group is transferred from the acyl - phosphate of 1,3 diphosphoglycerate to ADP thereby forming ATP and - 3-phosphoglycerate.|CITS:[90336971]| - phosphoglycerate phosphorylation - - - - - - - - - - - - - 0.4 - 5.3.1.9 - HEXOSEPHOSPHATE ISOMERASE - OXOISOMERASE - PGLUCISOM-RXN - PHOSPHOGLUCOISOMERASE - PHOSPHOGLUCOSE ISOMERASE - PHOSPHOHEXOISOMERASE - PHOSPHOHEXOMUTASE - PHOSPHOHEXOSE ISOMERASE - PHOSPHOSACCHAROMUTASE - - - - - - - - - - - 4.1.2.13 - 5.7 - ALDOLASE - Dihydroxyacetone phosphate is also called glycerone -phosphate. -Of the total aldolase activity in cell-free extracts of E.coli grown on -pyruvate and lactate, approx. 60 % was accounted for by aldolase 1. On -the other hand, E.coli grown on glucose showed no aldolase 1 activity -but had an increased aldolase 2 activity. |CITS: [73229139]| -During growth with CO2 as a carbon source, only class I aldolase is -produced but when acetate replaces CO2 the class II aldolase is made. -Similarly, in E.coli the putative class I aldolase is only synthesized -during growth on C3 compounds and not on glucose, implying that a -class I aldolase is preferred for gluconeogenesis |CITS:[73229139]| - - - F16ALDOLASE-RXN - FRUCTOSE-1,6-BISPHOSPHATE TRIOSEPHOSPHATE-LYASE - - - - - - - - - - - - 5.3.1.1 - PHOSPHOTRIOSE ISOMERASE - TRIOSEPHOSPHATE MUTASE - triose phosphate isomerization - - - - - - - - - - - 1.1 - 3PGAREARR-RXN - 5.4.2.1 - PGAM - PHOSPHOGLYCERATE PHOSPHOMUTASE - PHOSPHOGLYCEROMUTASE - - - - - - - - - - - 0.4 - 2-PHOSPHOGLYCERATE DEHYDRATASE - 2-phosphoglycerate dehydration - 4.2.1.11 - ENOLASE - - - - - - - - - - - - Pyruvate kinase I is strongly activated by fructose 1,6 -bisphosphate and shows sigmoid kinetics with respect to the substrate -phophoenolpyruvate. The dependences of the reaction -rate on the concentrations of phosphoenolpyruvate, Mg<SUP>+2</SUP>, and Mn<SUP>+2</SUP> are -sigmoid. These dependences become hyperbolic on addition of fructose -1,6 bisphosphate. The dependences of the reaction rate on the -concentration of ADP are always hyperbolic. The catalytic active complex of -E. coli pyruvate kinase is formed by only one conformational state of -the enzyme, state R1. This state binds randomly the Mg<SUP>+2</SUP> free ligands -ADP or phosphoenolpyruvate. Thereafter, the active enzyme complex is -formed by binding Mg<SUP>+2</SUP>-PEP or Mg<SUP>+2</SUP>ADP respectively. State R2 of coli -pyruvate kinase binds randomly ADP and Mg<SUP>+2</SUP>. It is the only state in -which Mg<SUP>+2</SUP> can bind to the free enzyme. Mg<SUP>+2</SUP> is not necesary for the -binding of ADP, PEP an ATP. Mg<SUP>+2</SUP> can inhibit either by binding to the -state R2 or by lowering the concentration of Mg<SUP>+2</SUP>, free ADP and PEP -through complex formation. ATP inhibits by virtue of three effects: -increase in ionic strength, complex-formation with Mg<SUP>+2</SUP> when this metal -ion acts as an activator and binding to the state R3. However when -conditions are such that Mg<SUP>+2</SUP> is an inhibitor, then ATP is expected to -activate because of complex formation with Mg<SUP>+2</SUP>. In general, one can say -that the ligands Mg<SUP>+2</SUP> and ATP cannot be classified as inhibitors or -activators because their regulatory effect on the reaction rate depends -on the concentration of the other ligands.|CITS:[81159972]| By -addition of fructose-1,6-bisphosphate the sigmoid kinetics with respect to -phosphoenolpyruvate and Mg<SUP>+2</SUP> is abolished and the activity of the enzyme -is described by classical saturation kinetics. This is explained by -exclusive binding of fructose 1,6 bisphosphate at an allosteric site of -the conformational state that forms the active complex. Ca<SUP>+2</SUP> is an activator -of the enzyme at low Mg<SUP>+2</SUP> and Ca<SUP>+2</SUP> concentrations; -otherwise it is an inhibitor. These effects can be understood by -assuming that Ca<SUP>+2</SUP> has the same binding properties as Mg<SUP>+2</SUP>, although it -does not allow a catalytic turnover.|CITS:[83282602]| The enzyme requires both bivalent and monovalent cations. |CITS: [90336973]| - REVERSIBLE - phosphoenol transphosphorylase - phosphoenolpyruvate kinase - pyruvate 2-0-phosphotransferase - pyruvate kinase - pyruvate kinase F - pyruvate kinase I - type I pyruvate kinase - - - - - - - - - - - - - - Pyruvate kinase II displays only limited cooperativity amoung -phosphoenolpyruvate binding sites and is allosterically activated by -AMP and several sugar phosphates |CITS:[91315755]| -The enzyme requires both bivalent and monovalent cations. |CITS: [90336973]| - REVERSIBLE - pyruvate kinase A - pyruvate kinase II - type II pyruvate kinase - - - - - - - - - - - - - - BPG-dependent PGAM2 - D-phosphoglycerate 2,3-phosphomutase 2 - E. coli contains three phosphoglycerate mutases. -Two are 2,3-bisphosphoglyerate-dependent enzymes, -encoded by the gpmA and gpmB genes. The third is a -2,3-bisphosphoglyerate-independent enzyme encoded -by the pgmI gene. |CITS: [99364512]| - PGAM2 - REVERSIBLE - phosphoglycerate mutase 2 - phosphoglycerate phosphomutase 2 - phosphoglyceromutase 2 - - - - - - - - - - - GAPDH-A - REVERSIBLE - The E.coli sequence contains a certain number of amino - acids which are conserved in all GAPDHs so far sequenced and which are - postulated to be directly implicated in the NAD+ binding or in the - catalysis mechanism. |CITS:[85257641]| There appear to be only two - active sites per molecule.|CITS:[79255500]| NAD required for the -phosphorylation as well as the oxidation |CITS:[79255500]| - glyceraldehyde 3-phosphate dehydrogenase-A complex - triosephosphate dehydrogenase - - - - - - - - - - - - - 6-phosphofructokinase-1 - 90% of the activity present in the wild type strain is pfk-1. -|CITS: [83294514]| -The enzyme shows cooperative kinetics with the substrate -fructose-6-phosphate but not with the other -substrate ATP. |CITS: [85203917]| The reverse reaction does -not participate in gluconeogenesis: fdp phosphatase mutants -are deficient in gluconeogenesis.|CITS: [78194149]| -Studies on phosphfructokinase-1 include subunit structure -|CITS:[91255189]|, ligand binding |CITS: [91355204]| and pH -dependence |CITS: [91255189]|. The allosteric properties of -phosphofructokinase-1 are due in part to ligand binding and in -part to the kinetics of the reaction. |CITS: [92144584]| - PFK I - REVERSIBLE - fructose-6-p-1-kinase - fructose-6-phosphate-1-phosphotransferase - - - - - - - - - - - - - - - - - - - 2,3-diphospho-D-glycerate - 2-phospho-D-glycerate phosphotransferase - 3-phosphoglycerate kinase - Glycerate 3-P kinase - REVERSIBLE - The structure of Pgk determined crystallographically is best -described as an open bi-lobal molecule. The active site of the enzyme lies -deep in the cleft formed between the two lobes.|CITS:[90336971]| -When purified enzymes -were employed there was absolute dependence upon the respective -substrates of the glycolytic pathway. There was no activity unless -ATP and glycerate-3-P were both included.|CITS:[71230170]| - phosphoglycerate kinase - - - - - - - - - - - 6-phosphofructokinase-2 - PFK II - Pfk-2 is somewhat sensitive to inhibition by -fructose-1,6-diphosphate and ATP. Pfk-2,unlike pfk-1, does not -show cooperative interaction with fructose-6-phosphate, inhibition by -PEP or activation by ADP. |CITS:[84262485]| MgATP is an inhibitor of -pfk-2 and it provokes the tetramerization of the dimeric native -enzyme.|CITS: [85289307],[88292964]| Its normal function is not -known and in strains with pfk-1, pfkB may be -deleted without apparent effect. |CITS: [83294514]| However in the -absence of pfk-1, slow growth on sugars depends on pfk-2. Its loss -causes complete inability to grow. |CITS: [84262485]| -The distribution of the two phosphofructokinases is variable -among enterobacteria and also among E.coli strains |CITS: [82027179]| - REVERSIBLE - fructose-6-p-1-kinase - fructose-6-phosphate-1-phosphotransferase - - - - - - - - - - - - - REVERSIBLE - When E. coli K-12 is grown on C-3 carbon sources both classes of aldolase are -present. However the Class I enzyme is present only under these conditions. -Therefore it is likely that the Class I enzyme is involved in gluconeogenesis -and the class II enzyme in glycolysis. |CITS: [81000551]| -The class I enzymes function by imine formation between the - substrate and a catalytically essential lysine residue in the active - site, which acts to stabilize the intermediate carbanion. |CITS:[89193446]| - They form a Schiff base betwen the E-amino group of a specific lysine - residue in the active site and the carbonyl group of the substrate. - This imine may be reduced by borohydride which therefore irreversibly - inhibits class 1 aldolases in the presence of substrate. |CITS:[73229139]| - The enzyme's activity was unaffected by EDTA, but it was inhibited by - borohydride reduction in the presence of Fru-1,6-P2 or - dihydroxyacetone phosphate. Like mammalian aldolases, it cleaved - fructose 1-phosphate, albeit slowly and had a low Km for Fru-1,6-P2. - Its fructose 1,6 bisphosphate cleavage activity was greatly enhanced - by citrate, PEP, 2-oxoglutarate and sn-glycerol 3-phosphate. Aldolase I - is very efficient at Fru-1,6-P2 cleavage when fully activated. - Only a limited range of metabolites has been tested as - possible activators. In contrast, its fructose 1-phosphate cleavage - activity was unaffected by these compounds. The enhancement - exhibited a strong dependence on pH. - These novel kinetic properties do not seem to be shared by any other - fructose 1,6 bisphosphate aldolase. In view of its unusual properties, - it is unlikely that aldolase I from E.coli is closely related to the - class-1 aldolases that have been detected in several other prokaryotes, - or to the typical class I enzymes from eukaryote. |CITS: [78165652]| - fructose bisphosphate aldolase class I - - - - - - - - - - - - REVERSIBLE - TIM - The amino acid sequence around the active site is perfectly -conserved in all known triose phosphate isomerases and can be -used as a signature pattern -for this type of enzyme.|CITS: [Prosite]| - phosphotriose isomerase - triose phosphate isomerase - triosephosphate isomerase - triosephosphate mutase - - - - - - - - - - - Class II enzymes utilize a divalent metal ion to act as the -electron sink at the active site in what appears to be an otherwise -similar catalytic mechanism to Class I. |CITS: [89193446]| -The metal ion in the active site varies, but several metals including -zinc, cobalt, iron, nickel and manganese can form an active -metallo-protein complex |CITS: [73229139]| -In Crookes strain of E. coli it was found that the kinetic behavior is not -typical of a class-II aldolase; the enzyme has no requirement for -thiol compounds either for stability or activity, added K+ ions have -no effect, and the high pH optimum of 9 is unusual for a class II -enzyme. |CITS: [78165651]| Aldolase II is relatively insensitive to -compounds that react with thiol groups.|CITS: [78165651]| It is -strongly inhibited by metal-chelating agents and is reactivated by -bivalent metal ions.|CITS: [73229139]| When E. coli K-12 is grown on C-3 carbon -sources both classes of aldolase are present. However the Class I enzyme is -present only under these conditions. Therefore the Class I enzyme is most -likely involved in gluconeogenesis and the Class II enzyme with glycolysis. -|CITS: [81000551]| - REVERSIBLE - fructose bisphosphate aldolase class II - fructose-1,6-bisphosphate aldolase - fructose-1,6-bisphosphate triosephosphate lyase - - - - - - - - - - - - - - 2-deoxyglucose-6-p is a known inhibitor in mammalian - systems. E.coli cells with mutated pgi gene apparently utilize - glucose primarily by the pentose phosphate pathway and to a - lesser extent by the Entner-Duodoroff pathway. |CITS:[89364675]| - D-glucose-6-phosphate-ketol-isomerase - REVERSIBLE - glucose-6-phosphate isomerase - phosphoglucose isomerase - - - - - - - - - - - - - BPG-independent PGAM - D-phosphoglycerate 2,3-phosphomutase - E. coli contains three phosphoglycerate mutases. -Two are 2,3-bisphosphoglycerate-dependent enzymes, -encoded by the gpmA and gpmB genes. The third is a -2,3-bisphosphoglycerate-independent enzyme encoded -by the pgmI gene. The two cofactor-dependent enzymes -are similar in sequence while the cofactor-independent -enzyme is unrelated. The cofactor-dependent enzymes -have ten times higher specific activity compared to the -cofactor-independent enzyme. |CITS: [99364512]| - PGAM, cofactor independent - REVERSIBLE - iPGM - phosphoglycerate mutase, 2,3-bisphosphoglycerate-independent - phosphoglycerate mutase, BPG-independent - phosphoglycerate mutase, cofactor independent - phosphoglycerate phosphomutase - phosphoglyceromutase - - - - - - - - - - - - BPG-dependent PGAM1 - D-phosphoglycerate 2,3-phosphomutase 1 - E. coli contains three phosphoglycerate mutases. -Two are 2,3-bisphosphoglyerate-dependent enzymes, -encoded by the gpmA and gpmB genes. The third is a -2,3-bisphosphoglyerate-independent enzyme encoded -by the pgmI gene. |CITS: [99364512]| - PGAM 1 - REVERSIBLE - phosphoglycerate mutase 1 - phosphoglycerate phosphomutase 1 - phosphoglyceromutase 1 - - - - - - - - - - - 2,3-diphospho-D-glycerate - 2-phospho-D glycerate phosphotransferase - 2-phospho-D-glycerate hydrolyase - 2-phosphoglycerate dehydratase - REVERSIBLE - There are two active sites per active dimer. Functionally -there are many similarities between E. coli enolase and other enolases -studied. Thus the dependence on Mg for activity and the inhibition by -fluoride in the presence of phosphate are quantitatively very similar -for all enolases. Other catalytic parameters are also similar but minor -quantitative distinctions indicate that E. coli enolase is more closely -related to yeast enolase than to enolases from vertebrate muscle. -The pH optimum of 8.1 is significantly higher than that for vertebrate -enolases and even somewhat above that of yeast and plant enolases. -|CITS:[72060411]| - enolase - phosphopyruvate hydratase - - - - - - - - - - - - - <cml> <molecule id="K+" title="K+" dictRef="dictK+"> - <atomArray> - <atom id="K+-atom1" elementType="K" x2="-1.0" y2="-1.0" formalCharge="1"/> - </atomArray> - <bondArray> - </bondArray> - <formula concise="K 1" formalCharge="1"/> - <float title="molecularWeight" units="g/mol">39.098</float> - <string title="smiles">[K+1]</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="PYRUVATE" title="pyruvate" dictRef="dictPYRUVATE"> - <atomArray> - <atom id="PYRUVATE-atom1" elementType="C" x2="0.36301" y2="-0.2363"/> - <atom id="PYRUVATE-atom2" elementType="C" x2="-1.0" y2="-0.2774"/> - <atom id="PYRUVATE-atom3" elementType="O" x2="-0.34247" y2="0.87329"/> - <atom id="PYRUVATE-atom4" elementType="C" x2="-0.34247" y2="0.10959"/> - <atom id="PYRUVATE-atom5" elementType="O" x2="0.36301" y2="-1.0"/> - <atom id="PYRUVATE-atom6" elementType="O" x2="0.99658" y2="0.18836"/> - </atomArray> - <bondArray> - <bond id="PYRUVATE-bond1" atomRefs="PYRUVATE-atom6 PYRUVATE-atom1" order="1"/> - <bond id="PYRUVATE-bond2" atomRefs="PYRUVATE-atom5 PYRUVATE-atom1" order="2"/> - <bond id="PYRUVATE-bond3" atomRefs="PYRUVATE-atom4 PYRUVATE-atom1" order="1"/> - <bond id="PYRUVATE-bond4" atomRefs="PYRUVATE-atom3 PYRUVATE-atom4" order="2"/> - <bond id="PYRUVATE-bond5" atomRefs="PYRUVATE-atom2 PYRUVATE-atom4" order="1"/> - </bondArray> - <formula concise="C 3 H 4 O 3" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">88.063</float> - <string title="smiles">C(=O)(O)C(=O)C</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="CA+2" title="Ca2+" dictRef="dictCA+2"> - <atomArray> - <atom id="CA+2-atom1" elementType="CA" x2="-1.0" y2="-1.0" formalCharge="2"/> - </atomArray> - <bondArray> - </bondArray> - <formula concise="CA 1" formalCharge="2"/> - <float title="molecularWeight" units="g/mol">40.08</float> - <string title="smiles">[Ca+2]</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="SUC-COA" title="succinyl-CoA" dictRef="dictSUC-COA"> - <atomArray> - <atom id="SUC-COA-atom1" elementType="C" x2="0.88294" y2="-0.23077"/> - <atom id="SUC-COA-atom2" elementType="N" x2="-1.0" y2="-0.14381"/> - <atom id="SUC-COA-atom3" elementType="C" x2="0.8194" y2="-0.35452"/> - <atom id="SUC-COA-atom4" elementType="C" x2="-0.60535" y2="0.11371"/> - <atom id="SUC-COA-atom5" elementType="N" x2="0.60535" y2="0.05017"/> - <atom id="SUC-COA-atom6" elementType="O" x2="-0.86622" y2="0.11371"/> - <atom id="SUC-COA-atom7" elementType="P" x2="0.8194" y2="-0.82274"/> - <atom id="SUC-COA-atom8" elementType="C" x2="-0.86622" y2="-0.06355"/> - <atom id="SUC-COA-atom9" elementType="O" x2="0.8194" y2="-0.46154"/> - <atom id="SUC-COA-atom10" elementType="C" x2="0.98662" y2="0.21405"/> - <atom id="SUC-COA-atom11" elementType="O" x2="0.8194" y2="-1.0"/> - <atom id="SUC-COA-atom12" elementType="N" x2="0.45151" y2="0.29097"/> - <atom id="SUC-COA-atom13" elementType="C" x2="0.22408" y2="-0.57525"/> - <atom id="SUC-COA-atom14" elementType="O" x2="0.71572" y2="-0.14047"/> - <atom id="SUC-COA-atom15" elementType="O" x2="-0.66221" y2="-0.41472"/> - <atom id="SUC-COA-atom16" elementType="N" x2="-0.52843" y2="-0.6689"/> - <atom id="SUC-COA-atom17" elementType="O" x2="-0.31773" y2="-0.04013"/> - <atom id="SUC-COA-atom18" elementType="C" x2="0.08696" y2="-0.67559"/> - <atom id="SUC-COA-atom19" elementType="O" x2="0.48829" y2="-0.39799"/> - <atom id="SUC-COA-atom20" elementType="C" x2="0.48829" y2="-0.57525"/> - <atom id="SUC-COA-atom21" elementType="O" x2="0.21405" y2="0.13712"/> - <atom id="SUC-COA-atom22" elementType="C" x2="-0.66221" y2="-0.59197"/> - <atom id="SUC-COA-atom23" elementType="H" x2="0.8194" y2="-0.24749"/> - <atom id="SUC-COA-atom24" elementType="C" x2="0.58863" y2="0.37793"/> - <atom id="SUC-COA-atom25" elementType="O" x2="0.21405" y2="-0.21739"/> - <atom id="SUC-COA-atom26" elementType="C" x2="-0.60535" y2="-0.06355"/> - <atom id="SUC-COA-atom27" elementType="N" x2="0.88294" y2="0.05686"/> - <atom id="SUC-COA-atom28" elementType="C" x2="-0.60535" y2="-0.2408"/> - <atom id="SUC-COA-atom29" elementType="O" x2="0.8194" y2="-0.62542"/> - <atom id="SUC-COA-atom30" elementType="O" x2="-0.11371" y2="0.13712"/> - <atom id="SUC-COA-atom31" elementType="H" x2="0.61873" y2="-0.24749"/> - <atom id="SUC-COA-atom32" elementType="C" x2="-0.47492" y2="-0.14381"/> - <atom id="SUC-COA-atom33" elementType="O" x2="0.04013" y2="-0.04013"/> - <atom id="SUC-COA-atom34" elementType="O" x2="-0.11371" y2="-0.21739"/> - <atom id="SUC-COA-atom35" elementType="O" x2="0.99666" y2="-0.82274"/> - <atom id="SUC-COA-atom36" elementType="S" x2="-0.06355" y2="-0.56522"/> - <atom id="SUC-COA-atom37" elementType="C" x2="-0.20401" y2="-0.6689"/> - <atom id="SUC-COA-atom38" elementType="O" x2="0.64548" y2="-0.65552"/> - <atom id="SUC-COA-atom39" elementType="C" x2="0.7291" y2="0.29766"/> - <atom id="SUC-COA-atom40" elementType="C" x2="-0.35452" y2="-0.57525"/> - <atom id="SUC-COA-atom41" elementType="O" x2="0.08696" y2="-0.85284"/> - <atom id="SUC-COA-atom42" elementType="C" x2="0.35786" y2="-0.66555"/> - <atom id="SUC-COA-atom43" elementType="O" x2="0.38462" y2="-0.04013"/> - <atom id="SUC-COA-atom44" elementType="C" x2="-0.86957" y2="-0.67559"/> - <atom id="SUC-COA-atom45" elementType="N" x2="0.87291" y2="0.3612"/> - <atom id="SUC-COA-atom46" elementType="H" x2="0.55184" y2="-0.33779"/> - <atom id="SUC-COA-atom47" elementType="P" x2="0.21405" y2="-0.04013"/> - <atom id="SUC-COA-atom48" elementType="C" x2="0.7291" y2="0.14047"/> - <atom id="SUC-COA-atom49" elementType="O" x2="-0.74916" y2="-0.32107"/> - <atom id="SUC-COA-atom50" elementType="P" x2="-0.11371" y2="-0.04013"/> - <atom id="SUC-COA-atom51" elementType="C" x2="0.45151" y2="0.13378"/> - <atom id="SUC-COA-atom52" elementType="C" x2="-1.0" y2="-0.59197"/> - <atom id="SUC-COA-atom53" elementType="C" x2="-0.74916" y2="-0.14381"/> - <atom id="SUC-COA-atom54" elementType="C" x2="0.55184" y2="-0.04013"/> - <atom id="SUC-COA-atom55" elementType="C" x2="0.55184" y2="-0.23077"/> - <atom id="SUC-COA-atom56" elementType="O" x2="0.64214" y2="-0.82274"/> - <atom id="SUC-COA-atom57" elementType="C" x2="0.61873" y2="-0.35452"/> - <atom id="SUC-COA-atom58" elementType="N" x2="0.58863" y2="0.55518"/> - <atom id="SUC-COA-atom59" elementType="H" x2="0.88294" y2="-0.33779"/> - </atomArray> - <bondArray> - <bond id="SUC-COA-bond1" atomRefs="SUC-COA-atom59 SUC-COA-atom1" order="1"/> - <bond id="SUC-COA-bond2" atomRefs="SUC-COA-atom58 SUC-COA-atom24" order="1"/> - <bond id="SUC-COA-bond3" atomRefs="SUC-COA-atom57 SUC-COA-atom29" order="1"/> - <bond id="SUC-COA-bond4" atomRefs="SUC-COA-atom57 SUC-COA-atom3" order="1"/> - <bond id="SUC-COA-bond5" atomRefs="SUC-COA-atom56 SUC-COA-atom7" order="2"/> - <bond id="SUC-COA-bond6" atomRefs="SUC-COA-atom55 SUC-COA-atom14" order="1"/> - <bond id="SUC-COA-bond7" atomRefs="SUC-COA-atom55 SUC-COA-atom57" order="1"/> - <bond id="SUC-COA-bond8" atomRefs="SUC-COA-atom54 SUC-COA-atom55" order="1"/> - <bond id="SUC-COA-bond9" atomRefs="SUC-COA-atom53 SUC-COA-atom26" order="1"/> - <bond id="SUC-COA-bond10" atomRefs="SUC-COA-atom52 SUC-COA-atom2" order="1"/> - <bond id="SUC-COA-bond11" atomRefs="SUC-COA-atom51 SUC-COA-atom5" order="A"/> - <bond id="SUC-COA-bond12" atomRefs="SUC-COA-atom50 SUC-COA-atom33" order="1"/> - <bond id="SUC-COA-bond13" atomRefs="SUC-COA-atom49 SUC-COA-atom53" order="1"/> - <bond id="SUC-COA-bond14" atomRefs="SUC-COA-atom27 SUC-COA-atom48" order="A"/> - <bond id="SUC-COA-bond15" atomRefs="SUC-COA-atom47 SUC-COA-atom43" order="1"/> - <bond id="SUC-COA-bond16" atomRefs="SUC-COA-atom46 SUC-COA-atom55" order="1"/> - <bond id="SUC-COA-bond17" atomRefs="SUC-COA-atom45 SUC-COA-atom10" order="A"/> - <bond id="SUC-COA-bond18" atomRefs="SUC-COA-atom39 SUC-COA-atom45" order="A"/> - <bond id="SUC-COA-bond19" atomRefs="SUC-COA-atom44 SUC-COA-atom52" order="1"/> - <bond id="SUC-COA-bond20" atomRefs="SUC-COA-atom43 SUC-COA-atom54" order="1"/> - <bond id="SUC-COA-bond21" atomRefs="SUC-COA-atom42 SUC-COA-atom13" order="1"/> - <bond id="SUC-COA-bond22" atomRefs="SUC-COA-atom41 SUC-COA-atom18" order="2"/> - <bond id="SUC-COA-bond23" atomRefs="SUC-COA-atom40 SUC-COA-atom16" order="1"/> - <bond id="SUC-COA-bond24" atomRefs="SUC-COA-atom48 SUC-COA-atom39" order="A"/> - <bond id="SUC-COA-bond25" atomRefs="SUC-COA-atom38 SUC-COA-atom20" order="1"/> - <bond id="SUC-COA-bond26" atomRefs="SUC-COA-atom37 SUC-COA-atom40" order="1"/> - <bond id="SUC-COA-bond27" atomRefs="SUC-COA-atom36 SUC-COA-atom37" order="1"/> - <bond id="SUC-COA-bond28" atomRefs="SUC-COA-atom35 SUC-COA-atom7" order="1"/> - <bond id="SUC-COA-bond29" atomRefs="SUC-COA-atom34 SUC-COA-atom50" order="1"/> - <bond id="SUC-COA-bond30" atomRefs="SUC-COA-atom33 SUC-COA-atom47" order="1"/> - <bond id="SUC-COA-bond31" atomRefs="SUC-COA-atom32 SUC-COA-atom17" order="1"/> - <bond id="SUC-COA-bond32" atomRefs="SUC-COA-atom31 SUC-COA-atom57" order="1"/> - <bond id="SUC-COA-bond33" atomRefs="SUC-COA-atom30 SUC-COA-atom50" order="2"/> - <bond id="SUC-COA-bond34" atomRefs="SUC-COA-atom28 SUC-COA-atom26" order="1"/> - <bond id="SUC-COA-bond35" atomRefs="SUC-COA-atom26 SUC-COA-atom32" order="1"/> - <bond id="SUC-COA-bond36" atomRefs="SUC-COA-atom25 SUC-COA-atom47" order="1"/> - <bond id="SUC-COA-bond37" atomRefs="SUC-COA-atom39 SUC-COA-atom24" order="A"/> - <bond id="SUC-COA-bond38" atomRefs="SUC-COA-atom24 SUC-COA-atom12" order="A"/> - <bond id="SUC-COA-bond39" atomRefs="SUC-COA-atom23 SUC-COA-atom3" order="1"/> - <bond id="SUC-COA-bond40" atomRefs="SUC-COA-atom22 SUC-COA-atom44" order="1"/> - <bond id="SUC-COA-bond41" atomRefs="SUC-COA-atom21 SUC-COA-atom47" order="2"/> - <bond id="SUC-COA-bond42" atomRefs="SUC-COA-atom20 SUC-COA-atom42" order="1"/> - <bond id="SUC-COA-bond43" atomRefs="SUC-COA-atom19 SUC-COA-atom20" order="2"/> - <bond id="SUC-COA-bond44" atomRefs="SUC-COA-atom18 SUC-COA-atom36" order="1"/> - <bond id="SUC-COA-bond45" atomRefs="SUC-COA-atom17 SUC-COA-atom50" order="1"/> - <bond id="SUC-COA-bond46" atomRefs="SUC-COA-atom16 SUC-COA-atom22" order="1"/> - <bond id="SUC-COA-bond47" atomRefs="SUC-COA-atom15 SUC-COA-atom22" order="2"/> - <bond id="SUC-COA-bond48" atomRefs="SUC-COA-atom14 SUC-COA-atom1" order="1"/> - <bond id="SUC-COA-bond49" atomRefs="SUC-COA-atom13 SUC-COA-atom18" order="1"/> - <bond id="SUC-COA-bond50" atomRefs="SUC-COA-atom12 SUC-COA-atom51" order="A"/> - <bond id="SUC-COA-bond51" atomRefs="SUC-COA-atom11 SUC-COA-atom7" order="1"/> - <bond id="SUC-COA-bond52" atomRefs="SUC-COA-atom10 SUC-COA-atom27" order="A"/> - <bond id="SUC-COA-bond53" atomRefs="SUC-COA-atom9 SUC-COA-atom3" order="1"/> - <bond id="SUC-COA-bond54" atomRefs="SUC-COA-atom8 SUC-COA-atom53" order="1"/> - <bond id="SUC-COA-bond55" atomRefs="SUC-COA-atom7 SUC-COA-atom29" order="1"/> - <bond id="SUC-COA-bond56" atomRefs="SUC-COA-atom6 SUC-COA-atom8" order="2"/> - <bond id="SUC-COA-bond57" atomRefs="SUC-COA-atom5 SUC-COA-atom48" order="A"/> - <bond id="SUC-COA-bond58" atomRefs="SUC-COA-atom4 SUC-COA-atom26" order="1"/> - <bond id="SUC-COA-bond59" atomRefs="SUC-COA-atom2 SUC-COA-atom8" order="1"/> - <bond id="SUC-COA-bond60" atomRefs="SUC-COA-atom1 SUC-COA-atom27" order="1"/> - <bond id="SUC-COA-bond61" atomRefs="SUC-COA-atom1 SUC-COA-atom3" order="1"/> - </bondArray> - <formula concise="C 25 H 40 N 7 O 19 P 3 S 1" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">867.608</float> - <string title="smiles">[CH]3(n1(c2(c(nc1)c(N)ncn2)))(O[CH]([CH]([CH](O)3)OP(O)(=O)O)COP(=O)(O)OP(=O)(O)OCC(C)(C)C(O)C(=O)NCCC(=O)NCCSC(=O)CCC(O)=O)</string> - <string title="systematicName">Coenzyme A, S-(hydrogen butanedioate)</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="AMP" title="AMP" dictRef="dictAMP"> - <atomArray> - <atom id="AMP-atom1" elementType="O" x2="0.45706" y2="-1.0"/> - <atom id="AMP-atom2" elementType="O" x2="0.25153" y2="0.00307"/> - <atom id="AMP-atom3" elementType="C" x2="0.41718" y2="-0.2362"/> - <atom id="AMP-atom4" elementType="N" x2="-1.0" y2="-0.25767"/> - <atom id="AMP-atom5" elementType="N" x2="-0.15951" y2="-0.25767"/> - <atom id="AMP-atom6" elementType="H" x2="0.56442" y2="-0.32822"/> - <atom id="AMP-atom7" elementType="N" x2="-0.16258" y2="0.2454"/> - <atom id="AMP-atom8" elementType="C" x2="0.70859" y2="0.15031"/> - <atom id="AMP-atom9" elementType="C" x2="-0.57055" y2="-0.0184"/> - <atom id="AMP-atom10" elementType="C" x2="0.42025" y2="0.2454"/> - <atom id="AMP-atom11" elementType="C" x2="0.70859" y2="-0.14417"/> - <atom id="AMP-atom12" elementType="N" x2="-0.57669" y2="-0.49693"/> - <atom id="AMP-atom13" elementType="O" x2="0.09509" y2="-0.58282"/> - <atom id="AMP-atom14" elementType="C" x2="-0.41718" y2="0.41104"/> - <atom id="AMP-atom15" elementType="O" x2="0.99693" y2="-0.14417"/> - <atom id="AMP-atom16" elementType="O" x2="0.98466" y2="0.23006"/> - <atom id="AMP-atom17" elementType="C" x2="-0.30061" y2="-0.0184"/> - <atom id="AMP-atom18" elementType="C" x2="-0.71166" y2="-0.25767"/> - <atom id="AMP-atom19" elementType="P" x2="0.26994" y2="-0.78221"/> - <atom id="AMP-atom20" elementType="N" x2="-0.67485" y2="0.22086"/> - <atom id="AMP-atom21" elementType="H" x2="0.42025" y2="0.41718"/> - <atom id="AMP-atom22" elementType="C" x2="-0.29755" y2="-0.49693"/> - <atom id="AMP-atom23" elementType="O" x2="0.5" y2="-0.60736"/> - <atom id="AMP-atom24" elementType="C" x2="0.09509" y2="-0.33742"/> - <atom id="AMP-atom25" elementType="O" x2="0.02761" y2="-0.93865"/> - </atomArray> - <bondArray> - <bond id="AMP-bond1" atomRefs="AMP-atom25 AMP-atom19" order="1"/> - <bond id="AMP-bond2" atomRefs="AMP-atom23 AMP-atom19" order="2"/> - <bond id="AMP-bond3" atomRefs="AMP-atom22 AMP-atom5" order="A"/> - <bond id="AMP-bond4" atomRefs="AMP-atom9 AMP-atom20" order="A"/> - <bond id="AMP-bond5" atomRefs="AMP-atom20 AMP-atom14" order="A"/> - <bond id="AMP-bond6" atomRefs="AMP-atom19 AMP-atom13" order="1"/> - <bond id="AMP-bond7" atomRefs="AMP-atom18 AMP-atom12" order="A"/> - <bond id="AMP-bond8" atomRefs="AMP-atom9 AMP-atom18" order="A"/> - <bond id="AMP-bond9" atomRefs="AMP-atom7 AMP-atom17" order="A"/> - <bond id="AMP-bond10" atomRefs="AMP-atom14 AMP-atom7" order="A"/> - <bond id="AMP-bond11" atomRefs="AMP-atom13 AMP-atom24" order="1"/> - <bond id="AMP-bond12" atomRefs="AMP-atom12 AMP-atom22" order="A"/> - <bond id="AMP-bond13" atomRefs="AMP-atom11 AMP-atom15" order="1"/> - <bond id="AMP-bond14" atomRefs="AMP-atom11 AMP-atom8" order="1"/> - <bond id="AMP-bond15" atomRefs="AMP-atom10 AMP-atom21" order="1"/> - <bond id="AMP-bond16" atomRefs="AMP-atom10 AMP-atom7" order="1"/> - <bond id="AMP-bond17" atomRefs="AMP-atom17 AMP-atom9" order="A"/> - <bond id="AMP-bond18" atomRefs="AMP-atom8 AMP-atom16" order="1"/> - <bond id="AMP-bond19" atomRefs="AMP-atom8 AMP-atom10" order="1"/> - <bond id="AMP-bond20" atomRefs="AMP-atom5 AMP-atom17" order="A"/> - <bond id="AMP-bond21" atomRefs="AMP-atom4 AMP-atom18" order="1"/> - <bond id="AMP-bond22" atomRefs="AMP-atom3 AMP-atom11" order="1"/> - <bond id="AMP-bond23" atomRefs="AMP-atom3 AMP-atom6" order="1"/> - <bond id="AMP-bond24" atomRefs="AMP-atom3 AMP-atom24" order="1"/> - <bond id="AMP-bond25" atomRefs="AMP-atom3 AMP-atom2" order="1"/> - <bond id="AMP-bond26" atomRefs="AMP-atom2 AMP-atom10" order="1"/> - <bond id="AMP-bond27" atomRefs="AMP-atom1 AMP-atom19" order="1"/> - </bondArray> - <formula concise="C 10 H 14 N 5 O 7 P 1" formalCharge="-2"/> - <float title="molecularWeight" units="g/mol">347.224</float> - <string title="smiles">[CH]1(O[CH](C(O)C(O)1)COP(=O)(O)O)n2(c3(c(nc2)c(N)ncn3))</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="Pi" title="phosphate" dictRef="dictPi"> - <atomArray> - <atom id="Pi-atom1" elementType="P" x2="-0.00166" y2="-0.00166"/> - <atom id="Pi-atom2" elementType="O" x2="0.99667" y2="-0.00166" formalCharge="-1"/> - <atom id="Pi-atom3" elementType="O" x2="-0.00166" y2="0.99667" formalCharge="-1"/> - <atom id="Pi-atom4" elementType="O" x2="-0.00166" y2="-1.0" formalCharge="-1"/> - <atom id="Pi-atom5" elementType="O" x2="-1.0" y2="-0.00166"/> - </atomArray> - <bondArray> - <bond id="Pi-bond1" atomRefs="Pi-atom5 Pi-atom1" order="2"/> - <bond id="Pi-bond2" atomRefs="Pi-atom4 Pi-atom1" order="1"/> - <bond id="Pi-bond3" atomRefs="Pi-atom3 Pi-atom1" order="1"/> - <bond id="Pi-bond4" atomRefs="Pi-atom2 Pi-atom1" order="1"/> - </bondArray> - <formula concise="O 4 P 1" formalCharge="-3"/> - <float title="molecularWeight" units="g/mol">94.971</float> - <string title="smiles">P([O-1])([O-1])(=O)[O-1]</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="NADH" title="NADH" dictRef="dictNADH"> - <atomArray> - <atom id="NADH-atom1" elementType="C" x2="0.34285715" y2="-0.7542857"/> - <atom id="NADH-atom2" elementType="C" x2="0.92" y2="-0.45142856"/> - <atom id="NADH-atom3" elementType="H" x2="0.37142858" y2="-0.89428574"/> - <atom id="NADH-atom4" elementType="O" x2="0.08285714" y2="-0.64"/> - <atom id="NADH-atom5" elementType="O" x2="0.08285714" y2="-0.8657143"/> - <atom id="NADH-atom6" elementType="C" x2="0.42857143" y2="-0.93142855"/> - <atom id="NADH-atom7" elementType="C" x2="-0.5914286" y2="-0.36"/> - <atom id="NADH-atom8" elementType="C" x2="-0.78571427" y2="-0.4342857"/> - <atom id="NADH-atom9" elementType="H" x2="-0.48857144" y2="-0.70285714"/> - <atom id="NADH-atom10" elementType="H" x2="0.7" y2="-0.34285715"/> - <atom id="NADH-atom11" elementType="O" x2="0.42857143" y2="-1.0"/> - <atom id="NADH-atom12" elementType="C" x2="0.52" y2="-0.46285716"/> - <atom id="NADH-atom13" elementType="C" x2="-1.0" y2="-0.4342857"/> - <atom id="NADH-atom14" elementType="H" x2="0.42857143" y2="-0.86285716"/> - <atom id="NADH-atom15" elementType="H" x2="-0.68" y2="-0.7542857"/> - <atom id="NADH-atom16" elementType="H" x2="0.6028572" y2="-0.34571427"/> - <atom id="NADH-atom17" elementType="C" x2="-0.42285714" y2="-0.68285716"/> - <atom id="NADH-atom18" elementType="C" x2="0.7714286" y2="-0.45142856"/> - <atom id="NADH-atom19" elementType="H" x2="0.6457143" y2="-0.89428574"/> - <atom id="NADH-atom20" elementType="O" x2="-0.5542857" y2="-0.61142856"/> - <atom id="NADH-atom21" elementType="C" x2="0.6457143" y2="-0.82857144"/> - <atom id="NADH-atom22" elementType="O" x2="-0.48857144" y2="-0.8428571"/> - <atom id="NADH-atom23" elementType="C" x2="0.37142858" y2="-0.82857144"/> - <atom id="NADH-atom24" elementType="C" x2="0.52" y2="-0.6085714"/> - <atom id="NADH-atom25" elementType="C" x2="-0.48857144" y2="-0.77428573"/> - <atom id="NADH-atom26" elementType="C" x2="-0.61714286" y2="-0.77428573"/> - <atom id="NADH-atom27" elementType="O" x2="0.5" y2="-0.7457143"/> - <atom id="NADH-atom28" elementType="N" x2="-0.8971428" y2="-0.13142857"/> - <atom id="NADH-atom29" elementType="O" x2="0.21428572" y2="-0.7542857"/> - <atom id="NADH-atom30" elementType="O" x2="-0.17714286" y2="-0.64"/> - <atom id="NADH-atom31" elementType="N" x2="-1.0" y2="-0.31142858"/> - <atom id="NADH-atom32" elementType="N" x2="-0.68" y2="-0.48285714"/> - <atom id="NADH-atom33" elementType="N" x2="0.9942857" y2="-0.5342857"/> - <atom id="NADH-atom34" elementType="C" x2="0.7714286" y2="-0.6085714"/> - <atom id="NADH-atom35" elementType="C" x2="-0.78571427" y2="-0.31142858"/> - <atom id="NADH-atom36" elementType="H" x2="0.5714286" y2="-0.86285716"/> - <atom id="NADH-atom37" elementType="P" x2="0.08285714" y2="-0.7542857"/> - <atom id="NADH-atom38" elementType="O" x2="-0.61714286" y2="-0.8428571"/> - <atom id="NADH-atom39" elementType="N" x2="-0.68" y2="-0.25714287"/> - <atom id="NADH-atom40" elementType="P" x2="-0.17714286" y2="-0.7542857"/> - <atom id="NADH-atom41" elementType="C" x2="-0.68" y2="-0.68285716"/> - <atom id="NADH-atom42" elementType="N" x2="0.6457143" y2="-0.67714286"/> - <atom id="NADH-atom43" elementType="H" x2="-0.61714286" y2="-0.70285714"/> - <atom id="NADH-atom44" elementType="O" x2="0.99714285" y2="-0.37142858"/> - <atom id="NADH-atom45" elementType="N" x2="-0.8971428" y2="-0.48857144"/> - <atom id="NADH-atom46" elementType="C" x2="-0.36857143" y2="-0.7657143"/> - <atom id="NADH-atom47" elementType="O" x2="0.5714286" y2="-1.0"/> - <atom id="NADH-atom48" elementType="O" x2="-0.17714286" y2="-0.8657143"/> - <atom id="NADH-atom49" elementType="C" x2="-0.8971428" y2="-0.24857143"/> - <atom id="NADH-atom50" elementType="O" x2="-0.2742857" y2="-0.7542857"/> - <atom id="NADH-atom51" elementType="H" x2="-0.42285714" y2="-0.61714286"/> - <atom id="NADH-atom52" elementType="O" x2="-0.042857144" y2="-0.7542857"/> - <atom id="NADH-atom53" elementType="C" x2="0.5714286" y2="-0.93142855"/> - <atom id="NADH-atom54" elementType="C" x2="0.6542857" y2="-0.39142856"/> - </atomArray> - <bondArray> - <bond id="NADH-bond1" atomRefs="NADH-atom54 NADH-atom18" order="1"/> - <bond id="NADH-bond2" atomRefs="NADH-atom53 NADH-atom6" order="1"/> - <bond id="NADH-bond3" atomRefs="NADH-atom52 NADH-atom40" order="1"/> - <bond id="NADH-bond4" atomRefs="NADH-atom51 NADH-atom17" order="1"/> - <bond id="NADH-bond5" atomRefs="NADH-atom50 NADH-atom46" order="1"/> - <bond id="NADH-bond6" atomRefs="NADH-atom49 NADH-atom31" order="A"/> - <bond id="NADH-bond7" atomRefs="NADH-atom48 NADH-atom40" order="1"/> - <bond id="NADH-bond8" atomRefs="NADH-atom47 NADH-atom53" order="1"/> - <bond id="NADH-bond9" atomRefs="NADH-atom46 NADH-atom17" order="1"/> - <bond id="NADH-bond10" atomRefs="NADH-atom45 NADH-atom8" order="A"/> - <bond id="NADH-bond11" atomRefs="NADH-atom44 NADH-atom2" order="2"/> - <bond id="NADH-bond12" atomRefs="NADH-atom43 NADH-atom26" order="1"/> - <bond id="NADH-bond13" atomRefs="NADH-atom42 NADH-atom21" order="1"/> - <bond id="NADH-bond14" atomRefs="NADH-atom42 NADH-atom24" order="1"/> - <bond id="NADH-bond15" atomRefs="NADH-atom41 NADH-atom32" order="1"/> - <bond id="NADH-bond16" atomRefs="NADH-atom41 NADH-atom26" order="1"/> - <bond id="NADH-bond17" atomRefs="NADH-atom40 NADH-atom50" order="1"/> - <bond id="NADH-bond18" atomRefs="NADH-atom39 NADH-atom35" order="A"/> - <bond id="NADH-bond19" atomRefs="NADH-atom38 NADH-atom26" order="1"/> - <bond id="NADH-bond20" atomRefs="NADH-atom37 NADH-atom52" order="1"/> - <bond id="NADH-bond21" atomRefs="NADH-atom36 NADH-atom53" order="1"/> - <bond id="NADH-bond22" atomRefs="NADH-atom35 NADH-atom49" order="A"/> - <bond id="NADH-bond23" atomRefs="NADH-atom35 NADH-atom8" order="A"/> - <bond id="NADH-bond24" atomRefs="NADH-atom34 NADH-atom42" order="1"/> - <bond id="NADH-bond25" atomRefs="NADH-atom33 NADH-atom2" order="1"/> - <bond id="NADH-bond26" atomRefs="NADH-atom32 NADH-atom7" order="A"/> - <bond id="NADH-bond27" atomRefs="NADH-atom31 NADH-atom13" order="A"/> - <bond id="NADH-bond28" atomRefs="NADH-atom30 NADH-atom40" order="2"/> - <bond id="NADH-bond29" atomRefs="NADH-atom29 NADH-atom37" order="1"/> - <bond id="NADH-bond30" atomRefs="NADH-atom28 NADH-atom49" order="1"/> - <bond id="NADH-bond31" atomRefs="NADH-atom27 NADH-atom23" order="1"/> - <bond id="NADH-bond32" atomRefs="NADH-atom25 NADH-atom26" order="1"/> - <bond id="NADH-bond33" atomRefs="NADH-atom23 NADH-atom1" order="1"/> - <bond id="NADH-bond34" atomRefs="NADH-atom23 NADH-atom6" order="1"/> - <bond id="NADH-bond35" atomRefs="NADH-atom22 NADH-atom25" order="1"/> - <bond id="NADH-bond36" atomRefs="NADH-atom21 NADH-atom27" order="1"/> - <bond id="NADH-bond37" atomRefs="NADH-atom21 NADH-atom53" order="1"/> - <bond id="NADH-bond38" atomRefs="NADH-atom20 NADH-atom41" order="1"/> - <bond id="NADH-bond39" atomRefs="NADH-atom19 NADH-atom21" order="1"/> - <bond id="NADH-bond40" atomRefs="NADH-atom18 NADH-atom34" order="2"/> - <bond id="NADH-bond41" atomRefs="NADH-atom17 NADH-atom20" order="1"/> - <bond id="NADH-bond42" atomRefs="NADH-atom17 NADH-atom25" order="1"/> - <bond id="NADH-bond43" atomRefs="NADH-atom16 NADH-atom54" order="1"/> - <bond id="NADH-bond44" atomRefs="NADH-atom15 NADH-atom41" order="1"/> - <bond id="NADH-bond45" atomRefs="NADH-atom14 NADH-atom6" order="1"/> - <bond id="NADH-bond46" atomRefs="NADH-atom13 NADH-atom45" order="A"/> - <bond id="NADH-bond47" atomRefs="NADH-atom12 NADH-atom24" order="2"/> - <bond id="NADH-bond48" atomRefs="NADH-atom12 NADH-atom54" order="1"/> - <bond id="NADH-bond49" atomRefs="NADH-atom11 NADH-atom6" order="1"/> - <bond id="NADH-bond50" atomRefs="NADH-atom10 NADH-atom54" order="1"/> - <bond id="NADH-bond51" atomRefs="NADH-atom9 NADH-atom25" order="1"/> - <bond id="NADH-bond52" atomRefs="NADH-atom8 NADH-atom32" order="A"/> - <bond id="NADH-bond53" atomRefs="NADH-atom7 NADH-atom39" order="A"/> - <bond id="NADH-bond54" atomRefs="NADH-atom5 NADH-atom37" order="1"/> - <bond id="NADH-bond55" atomRefs="NADH-atom4 NADH-atom37" order="2"/> - <bond id="NADH-bond56" atomRefs="NADH-atom3 NADH-atom23" order="1"/> - <bond id="NADH-bond57" atomRefs="NADH-atom2 NADH-atom18" order="1"/> - <bond id="NADH-bond58" atomRefs="NADH-atom1 NADH-atom29" order="1"/> - </bondArray> - <formula concise="C 21 H 29 N 7 O 14 P 2" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">665.446</float> - <string title="smiles">C([CH]1(O[CH]([CH](O)[CH]1O)N2(C=C(C(=O)N)[CH2]C=C2)))OP(=O)(O)OP(=O)(O)OC[CH]3(O[CH]([CH](O)[CH](O)3)n4(c5(c(nc4)c(N)ncn5)))</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="GAP" title="glyceraldehyde-3-phosphate" dictRef="dictGAP"> - <atomArray> - <atom id="GAP-atom1" elementType="C" x2="-1.0" y2="-0.54088"/> - <atom id="GAP-atom2" elementType="P" x2="-0.1478" y2="0.53774"/> - <atom id="GAP-atom3" elementType="O" x2="-0.13836" y2="-0.2044"/> - <atom id="GAP-atom4" elementType="O" x2="0.31132" y2="0.53774"/> - <atom id="GAP-atom5" elementType="O" x2="-0.1478" y2="0.07862"/> - <atom id="GAP-atom6" elementType="O" x2="-1.0" y2="-1.0"/> - <atom id="GAP-atom7" elementType="O" x2="-0.1478" y2="0.99686"/> - <atom id="GAP-atom8" elementType="C" x2="-1.0" y2="0.1761"/> - <atom id="GAP-atom9" elementType="O" x2="-0.59748" y2="0.53774"/> - <atom id="GAP-atom10" elementType="C" x2="-0.59748" y2="-0.2044"/> - </atomArray> - <bondArray> - <bond id="GAP-bond1" atomRefs="GAP-atom10 GAP-atom3" order="1"/> - <bond id="GAP-bond2" atomRefs="GAP-atom10 GAP-atom8" order="1"/> - <bond id="GAP-bond3" atomRefs="GAP-atom9 GAP-atom2" order="1"/> - <bond id="GAP-bond4" atomRefs="GAP-atom8 GAP-atom9" order="1"/> - <bond id="GAP-bond5" atomRefs="GAP-atom6 GAP-atom1" order="2"/> - <bond id="GAP-bond6" atomRefs="GAP-atom2 GAP-atom5" order="1"/> - <bond id="GAP-bond7" atomRefs="GAP-atom2 GAP-atom7" order="1"/> - <bond id="GAP-bond8" atomRefs="GAP-atom2 GAP-atom4" order="2"/> - <bond id="GAP-bond9" atomRefs="GAP-atom1 GAP-atom10" order="1"/> - </bondArray> - <formula concise="C 3 H 7 O 6 P 1" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">170.058</float> - <string title="smiles">C(=O)C(O)COP(O)(O)=O</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="NAD" title="NAD" dictRef="dictNAD"> - <atomArray> - <atom id="NAD-atom1" elementType="C" x2="-0.35491604" y2="-0.73141485"/> - <atom id="NAD-atom2" elementType="N" x2="0.6834533" y2="-0.64028776" formalCharge="1"/> - <atom id="NAD-atom3" elementType="C" x2="-0.7793765" y2="-0.2589928"/> - <atom id="NAD-atom4" elementType="N" x2="-0.67146283" y2="-0.41246998"/> - <atom id="NAD-atom5" elementType="H" x2="-0.6618705" y2="-0.7050359"/> - <atom id="NAD-atom6" elementType="C" x2="0.45803356" y2="-0.9256595"/> - <atom id="NAD-atom7" elementType="O" x2="-0.016786575" y2="-0.71702635"/> - <atom id="NAD-atom8" elementType="O" x2="0.6139089" y2="-1.0"/> - <atom id="NAD-atom9" elementType="O" x2="-0.58752996" y2="-0.7865707"/> - <atom id="NAD-atom10" elementType="C" x2="0.6906475" y2="-0.34532374"/> - <atom id="NAD-atom11" elementType="C" x2="-1.0" y2="-0.3860911"/> - <atom id="NAD-atom12" elementType="O" x2="-0.5467626" y2="-0.5707434"/> - <atom id="NAD-atom13" elementType="C" x2="0.37649882" y2="-0.71702635"/> - <atom id="NAD-atom14" elementType="P" x2="-0.15347719" y2="-0.71702635"/> - <atom id="NAD-atom15" elementType="O" x2="0.24460435" y2="-0.71702635"/> - <atom id="NAD-atom16" elementType="C" x2="-0.8920863" y2="-0.1966427"/> - <atom id="NAD-atom17" elementType="C" x2="-0.4028777" y2="-0.6522782"/> - <atom id="NAD-atom18" elementType="O" x2="-0.15347719" y2="-0.5971223"/> - <atom id="NAD-atom19" elementType="O" x2="-0.47961628" y2="-0.7865707"/> - <atom id="NAD-atom20" elementType="C" x2="0.6139089" y2="-0.9256595"/> - <atom id="NAD-atom21" elementType="N" x2="-0.8920863" y2="-0.076738596"/> - <atom id="NAD-atom22" elementType="H" x2="0.6139089" y2="-0.853717"/> - <atom id="NAD-atom23" elementType="H" x2="-0.58752996" y2="-0.64028776"/> - <atom id="NAD-atom24" elementType="C" x2="-0.5851319" y2="-0.31414866"/> - <atom id="NAD-atom25" elementType="H" x2="0.45803356" y2="-0.853717"/> - <atom id="NAD-atom26" elementType="C" x2="0.96642685" y2="-0.40527576"/> - <atom id="NAD-atom27" elementType="C" x2="-0.67146283" y2="-0.6354916"/> - <atom id="NAD-atom28" elementType="C" x2="0.556355" y2="-0.5683453"/> - <atom id="NAD-atom29" elementType="H" x2="-0.4028777" y2="-0.5779376"/> - <atom id="NAD-atom30" elementType="N" x2="-1.0" y2="-0.2589928"/> - <atom id="NAD-atom31" elementType="C" x2="0.6834533" y2="-0.8057554"/> - <atom id="NAD-atom32" elementType="C" x2="0.37649882" y2="-0.8057554"/> - <atom id="NAD-atom33" elementType="H" x2="0.37649882" y2="-0.8800959"/> - <atom id="NAD-atom34" elementType="O" x2="-0.25659472" y2="-0.71702635"/> - <atom id="NAD-atom35" elementType="O" x2="-0.15347719" y2="-0.83693045"/> - <atom id="NAD-atom36" elementType="O" x2="0.53237414" y2="-0.7505995"/> - <atom id="NAD-atom37" elementType="C" x2="-0.58752996" y2="-0.7146283"/> - <atom id="NAD-atom38" elementType="C" x2="0.8153478" y2="-0.42206234"/> - <atom id="NAD-atom39" elementType="C" x2="0.8153478" y2="-0.5683453"/> - <atom id="NAD-atom40" elementType="O" x2="0.45803356" y2="-1.0"/> - <atom id="NAD-atom41" elementType="O" x2="0.10791373" y2="-0.83693045" formalCharge="-1"/> - <atom id="NAD-atom42" elementType="O" x2="0.96642685" y2="-0.28537166"/> - <atom id="NAD-atom43" elementType="P" x2="0.10791373" y2="-0.71702635"/> - <atom id="NAD-atom44" elementType="N" x2="-0.8920863" y2="-0.4484412"/> - <atom id="NAD-atom45" elementType="C" x2="-0.47961628" y2="-0.7146283"/> - <atom id="NAD-atom46" elementType="H" x2="-0.47961628" y2="-0.64028776"/> - <atom id="NAD-atom47" elementType="O" x2="0.10791373" y2="-0.5971223"/> - <atom id="NAD-atom48" elementType="H" x2="0.6834533" y2="-0.8800959"/> - <atom id="NAD-atom49" elementType="C" x2="0.556355" y2="-0.4172662"/> - <atom id="NAD-atom50" elementType="N" x2="-0.67146283" y2="-0.20383692"/> - <atom id="NAD-atom51" elementType="C" x2="-0.7793765" y2="-0.3860911"/> - <atom id="NAD-atom52" elementType="N" x2="0.997602" y2="-0.5203837"/> - </atomArray> - <bondArray> - <bond id="NAD-bond1" atomRefs="NAD-atom52 NAD-atom26" order="1"/> - <bond id="NAD-bond2" atomRefs="NAD-atom51 NAD-atom3" order="A"/> - <bond id="NAD-bond3" atomRefs="NAD-atom50 NAD-atom24" order="A"/> - <bond id="NAD-bond4" atomRefs="NAD-atom49 NAD-atom10" order="A"/> - <bond id="NAD-bond5" atomRefs="NAD-atom48 NAD-atom31" order="1"/> - <bond id="NAD-bond6" atomRefs="NAD-atom47 NAD-atom43" order="2"/> - <bond id="NAD-bond7" atomRefs="NAD-atom46 NAD-atom45" order="1"/> - <bond id="NAD-bond8" atomRefs="NAD-atom45 NAD-atom37" order="1"/> - <bond id="NAD-bond9" atomRefs="NAD-atom44 NAD-atom51" order="A"/> - <bond id="NAD-bond10" atomRefs="NAD-atom43 NAD-atom7" order="1"/> - <bond id="NAD-bond11" atomRefs="NAD-atom42 NAD-atom26" order="2"/> - <bond id="NAD-bond12" atomRefs="NAD-atom41 NAD-atom43" order="1"/> - <bond id="NAD-bond13" atomRefs="NAD-atom40 NAD-atom6" order="1"/> - <bond id="NAD-bond14" atomRefs="NAD-atom39 NAD-atom2" order="A"/> - <bond id="NAD-bond15" atomRefs="NAD-atom38 NAD-atom39" order="A"/> - <bond id="NAD-bond16" atomRefs="NAD-atom36 NAD-atom32" order="1"/> - <bond id="NAD-bond17" atomRefs="NAD-atom35 NAD-atom14" order="1"/> - <bond id="NAD-bond18" atomRefs="NAD-atom34 NAD-atom1" order="1"/> - <bond id="NAD-bond19" atomRefs="NAD-atom33 NAD-atom32" order="1"/> - <bond id="NAD-bond20" atomRefs="NAD-atom32 NAD-atom6" order="1"/> - <bond id="NAD-bond21" atomRefs="NAD-atom32 NAD-atom13" order="1"/> - <bond id="NAD-bond22" atomRefs="NAD-atom31 NAD-atom20" order="1"/> - <bond id="NAD-bond23" atomRefs="NAD-atom31 NAD-atom36" order="1"/> - <bond id="NAD-bond24" atomRefs="NAD-atom30 NAD-atom11" order="A"/> - <bond id="NAD-bond25" atomRefs="NAD-atom29 NAD-atom17" order="1"/> - <bond id="NAD-bond26" atomRefs="NAD-atom28 NAD-atom49" order="A"/> - <bond id="NAD-bond27" atomRefs="NAD-atom27 NAD-atom37" order="1"/> - <bond id="NAD-bond28" atomRefs="NAD-atom27 NAD-atom4" order="1"/> - <bond id="NAD-bond29" atomRefs="NAD-atom26 NAD-atom38" order="1"/> - <bond id="NAD-bond30" atomRefs="NAD-atom25 NAD-atom6" order="1"/> - <bond id="NAD-bond31" atomRefs="NAD-atom24 NAD-atom4" order="A"/> - <bond id="NAD-bond32" atomRefs="NAD-atom23 NAD-atom37" order="1"/> - <bond id="NAD-bond33" atomRefs="NAD-atom22 NAD-atom20" order="1"/> - <bond id="NAD-bond34" atomRefs="NAD-atom21 NAD-atom16" order="1"/> - <bond id="NAD-bond35" atomRefs="NAD-atom20 NAD-atom6" order="1"/> - <bond id="NAD-bond36" atomRefs="NAD-atom19 NAD-atom45" order="1"/> - <bond id="NAD-bond37" atomRefs="NAD-atom18 NAD-atom14" order="2"/> - <bond id="NAD-bond38" atomRefs="NAD-atom17 NAD-atom45" order="1"/> - <bond id="NAD-bond39" atomRefs="NAD-atom17 NAD-atom12" order="1"/> - <bond id="NAD-bond40" atomRefs="NAD-atom16 NAD-atom30" order="A"/> - <bond id="NAD-bond41" atomRefs="NAD-atom15 NAD-atom43" order="1"/> - <bond id="NAD-bond42" atomRefs="NAD-atom14 NAD-atom34" order="1"/> - <bond id="NAD-bond43" atomRefs="NAD-atom13 NAD-atom15" order="1"/> - <bond id="NAD-bond44" atomRefs="NAD-atom12 NAD-atom27" order="1"/> - <bond id="NAD-bond45" atomRefs="NAD-atom11 NAD-atom44" order="A"/> - <bond id="NAD-bond46" atomRefs="NAD-atom10 NAD-atom38" order="A"/> - <bond id="NAD-bond47" atomRefs="NAD-atom9 NAD-atom37" order="1"/> - <bond id="NAD-bond48" atomRefs="NAD-atom8 NAD-atom20" order="1"/> - <bond id="NAD-bond49" atomRefs="NAD-atom7 NAD-atom14" order="1"/> - <bond id="NAD-bond50" atomRefs="NAD-atom5 NAD-atom27" order="1"/> - <bond id="NAD-bond51" atomRefs="NAD-atom4 NAD-atom51" order="A"/> - <bond id="NAD-bond52" atomRefs="NAD-atom3 NAD-atom50" order="A"/> - <bond id="NAD-bond53" atomRefs="NAD-atom3 NAD-atom16" order="A"/> - <bond id="NAD-bond54" atomRefs="NAD-atom2 NAD-atom31" order="1"/> - <bond id="NAD-bond55" atomRefs="NAD-atom2 NAD-atom28" order="A"/> - <bond id="NAD-bond56" atomRefs="NAD-atom1 NAD-atom17" order="1"/> - </bondArray> - <formula concise="C 21 H 27 N 7 O 14 P 2" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">663.43</float> - <string title="smiles">C([CH]1(O[CH]([CH](O)[CH](O)1)n2(c3(c(nc2)c(N)ncn3))))OP(=O)(O)OP([O-1])(=O)OC[CH]4(O[CH]([CH](O)[CH](O)4)[n+1]5(cc(C(N)=O)ccc5))</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="ADP" title="ADP" dictRef="dictADP"> - <atomArray> - <atom id="ADP-atom1" elementType="C" x2="0.6623" y2="-0.17049"/> - <atom id="ADP-atom2" elementType="N" x2="0.28197" y2="0.02295"/> - <atom id="ADP-atom3" elementType="N" x2="0.46557" y2="-0.26885"/> - <atom id="ADP-atom4" elementType="O" x2="-0.77705" y2="-0.78689"/> - <atom id="ADP-atom5" elementType="O" x2="-0.36721" y2="-0.34098"/> - <atom id="ADP-atom6" elementType="C" x2="0.46557" y2="-0.65902"/> - <atom id="ADP-atom7" elementType="C" x2="0.22951" y2="-0.54426"/> - <atom id="ADP-atom8" elementType="C" x2="0.87541" y2="-0.61967"/> - <atom id="ADP-atom9" elementType="O" x2="-1.0" y2="-0.54426"/> - <atom id="ADP-atom10" elementType="O" x2="-0.77705" y2="-0.34098"/> - <atom id="ADP-atom11" elementType="O" x2="0.88525" y2="-0.97705"/> - <atom id="ADP-atom12" elementType="P" x2="-0.36721" y2="-0.54426"/> - <atom id="ADP-atom13" elementType="N" x2="0.46557" y2="0.34426"/> - <atom id="ADP-atom14" elementType="N" x2="0.87541" y2="-0.21639"/> - <atom id="ADP-atom15" elementType="P" x2="-0.77705" y2="-0.54426"/> - <atom id="ADP-atom16" elementType="C" x2="0.99672" y2="-0.04262"/> - <atom id="ADP-atom17" elementType="O" x2="0.53115" y2="-1.0"/> - <atom id="ADP-atom18" elementType="O" x2="-0.57049" y2="-0.54426"/> - <atom id="ADP-atom19" elementType="O" x2="-0.1541" y2="-0.54426"/> - <atom id="ADP-atom20" elementType="C" x2="0.46557" y2="0.12131"/> - <atom id="ADP-atom21" elementType="O" x2="0.65574" y2="-0.47541"/> - <atom id="ADP-atom22" elementType="C" x2="0.6623" y2="0.02295"/> - <atom id="ADP-atom23" elementType="C" x2="0.81311" y2="-0.86557"/> - <atom id="ADP-atom24" elementType="H" x2="0.39344" y2="-0.77377"/> - <atom id="ADP-atom25" elementType="N" x2="0.85246" y2="0.10492"/> - <atom id="ADP-atom26" elementType="C" x2="0.28197" y2="-0.17049"/> - <atom id="ADP-atom27" elementType="O" x2="-0.36721" y2="-0.78689"/> - <atom id="ADP-atom28" elementType="C" x2="0.53115" y2="-0.86557"/> - <atom id="ADP-atom29" elementType="H" x2="0.77377" y2="-0.7377"/> - <atom id="ADP-atom30" elementType="H" x2="0.92459" y2="-0.74426"/> - <atom id="ADP-atom31" elementType="H" x2="0.60328" y2="-0.75082"/> - </atomArray> - <bondArray> - <bond id="ADP-bond1" atomRefs="ADP-atom31 ADP-atom28" order="1"/> - <bond id="ADP-bond2" atomRefs="ADP-atom30 ADP-atom8" order="1"/> - <bond id="ADP-bond3" atomRefs="ADP-atom29 ADP-atom23" order="1"/> - <bond id="ADP-bond4" atomRefs="ADP-atom28 ADP-atom23" order="1"/> - <bond id="ADP-bond5" atomRefs="ADP-atom27 ADP-atom12" order="1"/> - <bond id="ADP-bond6" atomRefs="ADP-atom26 ADP-atom3" order="A"/> - <bond id="ADP-bond7" atomRefs="ADP-atom25 ADP-atom16" order="A"/> - <bond id="ADP-bond8" atomRefs="ADP-atom24 ADP-atom6" order="1"/> - <bond id="ADP-bond9" atomRefs="ADP-atom1 ADP-atom22" order="A"/> - <bond id="ADP-bond10" atomRefs="ADP-atom22 ADP-atom25" order="A"/> - <bond id="ADP-bond11" atomRefs="ADP-atom21 ADP-atom8" order="1"/> - <bond id="ADP-bond12" atomRefs="ADP-atom22 ADP-atom20" order="A"/> - <bond id="ADP-bond13" atomRefs="ADP-atom19 ADP-atom7" order="1"/> - <bond id="ADP-bond14" atomRefs="ADP-atom18 ADP-atom12" order="1"/> - <bond id="ADP-bond15" atomRefs="ADP-atom17 ADP-atom28" order="1"/> - <bond id="ADP-bond16" atomRefs="ADP-atom16 ADP-atom14" order="A"/> - <bond id="ADP-bond17" atomRefs="ADP-atom15 ADP-atom18" order="1"/> - <bond id="ADP-bond18" atomRefs="ADP-atom13 ADP-atom20" order="1"/> - <bond id="ADP-bond19" atomRefs="ADP-atom12 ADP-atom19" order="1"/> - <bond id="ADP-bond20" atomRefs="ADP-atom11 ADP-atom23" order="1"/> - <bond id="ADP-bond21" atomRefs="ADP-atom10 ADP-atom15" order="2"/> - <bond id="ADP-bond22" atomRefs="ADP-atom9 ADP-atom15" order="1"/> - <bond id="ADP-bond23" atomRefs="ADP-atom8 ADP-atom14" order="1"/> - <bond id="ADP-bond24" atomRefs="ADP-atom8 ADP-atom23" order="1"/> - <bond id="ADP-bond25" atomRefs="ADP-atom7 ADP-atom6" order="1"/> - <bond id="ADP-bond26" atomRefs="ADP-atom6 ADP-atom21" order="1"/> - <bond id="ADP-bond27" atomRefs="ADP-atom6 ADP-atom28" order="1"/> - <bond id="ADP-bond28" atomRefs="ADP-atom5 ADP-atom12" order="2"/> - <bond id="ADP-bond29" atomRefs="ADP-atom4 ADP-atom15" order="1"/> - <bond id="ADP-bond30" atomRefs="ADP-atom3 ADP-atom1" order="A"/> - <bond id="ADP-bond31" atomRefs="ADP-atom2 ADP-atom26" order="A"/> - <bond id="ADP-bond32" atomRefs="ADP-atom20 ADP-atom2" order="A"/> - <bond id="ADP-bond33" atomRefs="ADP-atom14 ADP-atom1" order="A"/> - </bondArray> - <formula concise="C 10 H 15 N 5 O 10 P 2" formalCharge="-3"/> - <float title="molecularWeight" units="g/mol">427.203</float> - <string title="smiles">c12(n(cnc(c(N)ncn1)2)[CH]3(O[CH]([CH](O)[CH](O)3)COP(=O)(O)OP(O)(=O)O))</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="ARSENATE" title="arsenate" dictRef="dictARSENATE"> - <atomArray> - <atom id="ARSENATE-atom1" elementType="AS" x2="0.0" y2="0.0"/> - <atom id="ARSENATE-atom2" elementType="O" x2="0.9961977" y2="0.0" formalCharge="-1"/> - <atom id="ARSENATE-atom3" elementType="O" x2="0.0" y2="0.9961977" formalCharge="-1"/> - <atom id="ARSENATE-atom4" elementType="O" x2="0.0" y2="-1.0" formalCharge="-1"/> - <atom id="ARSENATE-atom5" elementType="O" x2="-1.0" y2="0.0"/> - </atomArray> - <bondArray> - <bond id="ARSENATE-bond1" atomRefs="ARSENATE-atom5 ARSENATE-atom1" order="2"/> - <bond id="ARSENATE-bond2" atomRefs="ARSENATE-atom4 ARSENATE-atom1" order="1"/> - <bond id="ARSENATE-bond3" atomRefs="ARSENATE-atom3 ARSENATE-atom1" order="1"/> - <bond id="ARSENATE-bond4" atomRefs="ARSENATE-atom2 ARSENATE-atom1" order="1"/> - </bondArray> - <formula concise="O 4 AS 1" formalCharge="-3"/> - <float title="molecularWeight" units="g/mol">138.919</float> - <string title="smiles">[As]([O-1])([O-1])(=O)[O-1]</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="DIHYDROXY-ACETONE-PHOSPHATE" title="dihydroxy-acetone-phosphate" dictRef="dictDIHYDROXY-ACETONE-PHOSPHATE"> - <atomArray> - <atom id="DIHYDROXY-ACETONE-PHOSPHATE-atom1" elementType="O" x2="0.60784" y2="-1.0"/> - <atom id="DIHYDROXY-ACETONE-PHOSPHATE-atom2" elementType="O" x2="-1.0" y2="-0.53922"/> - <atom id="DIHYDROXY-ACETONE-PHOSPHATE-atom3" elementType="P" x2="0.60784" y2="-0.61111"/> - <atom id="DIHYDROXY-ACETONE-PHOSPHATE-atom4" elementType="O" x2="-0.38562" y2="-0.21242"/> - <atom id="DIHYDROXY-ACETONE-PHOSPHATE-atom5" elementType="C" x2="-0.38562" y2="-0.60131"/> - <atom id="DIHYDROXY-ACETONE-PHOSPHATE-atom6" elementType="O" x2="0.19608" y2="-0.61111"/> - <atom id="DIHYDROXY-ACETONE-PHOSPHATE-atom7" elementType="C" x2="-0.68954" y2="-0.77451"/> - <atom id="DIHYDROXY-ACETONE-PHOSPHATE-atom8" elementType="O" x2="0.99673" y2="-0.61111"/> - <atom id="DIHYDROXY-ACETONE-PHOSPHATE-atom9" elementType="O" x2="0.60784" y2="-0.22222"/> - <atom id="DIHYDROXY-ACETONE-PHOSPHATE-atom10" elementType="C" x2="-0.07843" y2="-0.77451"/> - </atomArray> - <bondArray> - <bond id="DIHYDROXY-ACETONE-PHOSPHATE-bond1" atomRefs="DIHYDROXY-ACETONE-PHOSPHATE-atom10 DIHYDROXY-ACETONE-PHOSPHATE-atom6" order="1"/> - <bond id="DIHYDROXY-ACETONE-PHOSPHATE-bond2" atomRefs="DIHYDROXY-ACETONE-PHOSPHATE-atom9 DIHYDROXY-ACETONE-PHOSPHATE-atom3" order="2"/> - <bond id="DIHYDROXY-ACETONE-PHOSPHATE-bond3" atomRefs="DIHYDROXY-ACETONE-PHOSPHATE-atom8 DIHYDROXY-ACETONE-PHOSPHATE-atom3" order="1"/> - <bond id="DIHYDROXY-ACETONE-PHOSPHATE-bond4" atomRefs="DIHYDROXY-ACETONE-PHOSPHATE-atom7 DIHYDROXY-ACETONE-PHOSPHATE-atom5" order="1"/> - <bond id="DIHYDROXY-ACETONE-PHOSPHATE-bond5" atomRefs="DIHYDROXY-ACETONE-PHOSPHATE-atom6 DIHYDROXY-ACETONE-PHOSPHATE-atom3" order="1"/> - <bond id="DIHYDROXY-ACETONE-PHOSPHATE-bond6" atomRefs="DIHYDROXY-ACETONE-PHOSPHATE-atom5 DIHYDROXY-ACETONE-PHOSPHATE-atom10" order="1"/> - <bond id="DIHYDROXY-ACETONE-PHOSPHATE-bond7" atomRefs="DIHYDROXY-ACETONE-PHOSPHATE-atom4 DIHYDROXY-ACETONE-PHOSPHATE-atom5" order="2"/> - <bond id="DIHYDROXY-ACETONE-PHOSPHATE-bond8" atomRefs="DIHYDROXY-ACETONE-PHOSPHATE-atom2 DIHYDROXY-ACETONE-PHOSPHATE-atom7" order="1"/> - <bond id="DIHYDROXY-ACETONE-PHOSPHATE-bond9" atomRefs="DIHYDROXY-ACETONE-PHOSPHATE-atom1 DIHYDROXY-ACETONE-PHOSPHATE-atom3" order="1"/> - </bondArray> - <formula concise="C 3 H 7 O 6 P 1" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">170.058</float> - <string title="smiles">C(O)C(=O)COP(O)(=O)O</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="GDP" title="GDP" dictRef="dictGDP"> - <atomArray> - <atom id="GDP-atom1" elementType="N" x2="-0.05666667" y2="0.06666667"/> - <atom id="GDP-atom2" elementType="H" x2="0.99666667" y2="-0.7366667"/> - <atom id="GDP-atom3" elementType="N" x2="0.99666667" y2="0.2"/> - <atom id="GDP-atom4" elementType="N" x2="0.4" y2="0.046666667"/> - <atom id="GDP-atom5" elementType="N" x2="0.18" y2="0.44"/> - <atom id="GDP-atom6" elementType="C" x2="0.26666668" y2="-0.39333335"/> - <atom id="GDP-atom7" elementType="C" x2="0.99666667" y2="0.42333335"/> - <atom id="GDP-atom8" elementType="O" x2="-0.7266667" y2="-0.12"/> - <atom id="GDP-atom9" elementType="N" x2="0.81666666" y2="0.5466667"/> - <atom id="GDP-atom10" elementType="O" x2="0.41333333" y2="-1.0"/> - <atom id="GDP-atom11" elementType="C" x2="0.62" y2="0.44"/> - <atom id="GDP-atom12" elementType="H" x2="0.41333333" y2="-0.67333335"/> - <atom id="GDP-atom13" elementType="O" x2="-0.25333333" y2="-0.6666667"/> - <atom id="GDP-atom14" elementType="O" x2="0.85333335" y2="-1.0"/> - <atom id="GDP-atom15" elementType="O" x2="-0.25333333" y2="-0.12"/> - <atom id="GDP-atom16" elementType="H" x2="0.0" y2="0.54333335"/> - <atom id="GDP-atom17" elementType="O" x2="0.4" y2="0.85"/> - <atom id="GDP-atom18" elementType="H" x2="0.85333335" y2="-0.67333335"/> - <atom id="GDP-atom19" elementType="C" x2="0.26666668" y2="-0.5733333"/> - <atom id="GDP-atom20" elementType="C" x2="0.4" y2="0.57666665"/> - <atom id="GDP-atom21" elementType="O" x2="-0.7266667" y2="-0.6666667"/> - <atom id="GDP-atom22" elementType="H" x2="0.26666668" y2="-0.7366667"/> - <atom id="GDP-atom23" elementType="P" x2="-0.25333333" y2="-0.39333335"/> - <atom id="GDP-atom24" elementType="C" x2="0.85333335" y2="-0.83666664"/> - <atom id="GDP-atom25" elementType="O" x2="-1.0" y2="-0.39333335"/> - <atom id="GDP-atom26" elementType="O" x2="-0.45" y2="-0.39333335"/> - <atom id="GDP-atom27" elementType="C" x2="0.99666667" y2="-0.5733333"/> - <atom id="GDP-atom28" elementType="C" x2="0.18" y2="0.2"/> - <atom id="GDP-atom29" elementType="C" x2="0.41333333" y2="-0.83666664"/> - <atom id="GDP-atom30" elementType="C" x2="0.62" y2="0.2"/> - <atom id="GDP-atom31" elementType="O" x2="0.62666667" y2="-0.35666665"/> - <atom id="GDP-atom32" elementType="P" x2="-0.7266667" y2="-0.39333335"/> - <atom id="GDP-atom33" elementType="O" x2="0.02" y2="-0.39333335"/> - </atomArray> - <bondArray> - <bond id="GDP-bond1" atomRefs="GDP-atom33 GDP-atom6" order="1"/> - <bond id="GDP-bond2" atomRefs="GDP-atom32 GDP-atom26" order="1"/> - <bond id="GDP-bond3" atomRefs="GDP-atom31 GDP-atom27" order="1"/> - <bond id="GDP-bond4" atomRefs="GDP-atom30 GDP-atom4" order="A"/> - <bond id="GDP-bond5" atomRefs="GDP-atom30 GDP-atom3" order="A"/> - <bond id="GDP-bond6" atomRefs="GDP-atom29 GDP-atom24" order="1"/> - <bond id="GDP-bond7" atomRefs="GDP-atom28 GDP-atom5" order="A"/> - <bond id="GDP-bond8" atomRefs="GDP-atom27 GDP-atom24" order="1"/> - <bond id="GDP-bond9" atomRefs="GDP-atom27 GDP-atom3" order="1"/> - <bond id="GDP-bond10" atomRefs="GDP-atom26 GDP-atom23" order="1"/> - <bond id="GDP-bond11" atomRefs="GDP-atom25 GDP-atom32" order="2"/> - <bond id="GDP-bond12" atomRefs="GDP-atom23 GDP-atom33" order="1"/> - <bond id="GDP-bond13" atomRefs="GDP-atom22 GDP-atom19" order="1"/> - <bond id="GDP-bond14" atomRefs="GDP-atom21 GDP-atom32" order="1"/> - <bond id="GDP-bond15" atomRefs="GDP-atom20 GDP-atom11" order="A"/> - <bond id="GDP-bond16" atomRefs="GDP-atom19 GDP-atom29" order="1"/> - <bond id="GDP-bond17" atomRefs="GDP-atom19 GDP-atom31" order="1"/> - <bond id="GDP-bond18" atomRefs="GDP-atom18 GDP-atom24" order="1"/> - <bond id="GDP-bond19" atomRefs="GDP-atom17 GDP-atom20" order="2"/> - <bond id="GDP-bond20" atomRefs="GDP-atom16 GDP-atom5" order="1"/> - <bond id="GDP-bond21" atomRefs="GDP-atom15 GDP-atom23" order="2"/> - <bond id="GDP-bond22" atomRefs="GDP-atom14 GDP-atom24" order="1"/> - <bond id="GDP-bond23" atomRefs="GDP-atom13 GDP-atom23" order="1"/> - <bond id="GDP-bond24" atomRefs="GDP-atom12 GDP-atom29" order="1"/> - <bond id="GDP-bond25" atomRefs="GDP-atom11 GDP-atom30" order="A"/> - <bond id="GDP-bond26" atomRefs="GDP-atom10 GDP-atom29" order="1"/> - <bond id="GDP-bond27" atomRefs="GDP-atom9 GDP-atom11" order="A"/> - <bond id="GDP-bond28" atomRefs="GDP-atom8 GDP-atom32" order="1"/> - <bond id="GDP-bond29" atomRefs="GDP-atom7 GDP-atom9" order="A"/> - <bond id="GDP-bond30" atomRefs="GDP-atom6 GDP-atom19" order="1"/> - <bond id="GDP-bond31" atomRefs="GDP-atom5 GDP-atom20" order="A"/> - <bond id="GDP-bond32" atomRefs="GDP-atom4 GDP-atom28" order="A"/> - <bond id="GDP-bond33" atomRefs="GDP-atom3 GDP-atom7" order="A"/> - <bond id="GDP-bond34" atomRefs="GDP-atom2 GDP-atom27" order="1"/> - <bond id="GDP-bond35" atomRefs="GDP-atom1 GDP-atom28" order="1"/> - </bondArray> - <formula concise="C 10 H 15 N 5 O 11 P 2" formalCharge="-3"/> - <float title="molecularWeight" units="g/mol">443.203</float> - <string title="smiles">C(OP(O)(=O)OP(O)(=O)O)[CH]1(O[CH]([CH](O)[CH]1O)n2(c3(c(nc2)c(=O)[nH]c(n3)N)))</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="FRUCTOSE-6P" title="fructose-6-phosphate" dictRef="dictFRUCTOSE-6P"> - <atomArray> - <atom id="FRUCTOSE-6P-atom1" elementType="O" x2="-0.41525424" y2="-0.3079096"/> - <atom id="FRUCTOSE-6P-atom2" elementType="C" x2="-0.124293804" y2="-0.3079096"/> - <atom id="FRUCTOSE-6P-atom3" elementType="H" x2="0.028248549" y2="-0.65254235"/> - <atom id="FRUCTOSE-6P-atom4" elementType="C" x2="-0.124293804" y2="-0.519774"/> - <atom id="FRUCTOSE-6P-atom5" elementType="H" x2="-0.124293804" y2="-0.6949153"/> - <atom id="FRUCTOSE-6P-atom6" elementType="O" x2="0.6751412" y2="-0.279661"/> - <atom id="FRUCTOSE-6P-atom7" elementType="O" x2="0.028248549" y2="-1.0"/> - <atom id="FRUCTOSE-6P-atom8" elementType="O" x2="0.27966106" y2="-0.29378533"/> - <atom id="FRUCTOSE-6P-atom9" elementType="O" x2="0.9971751" y2="-0.7485876"/> - <atom id="FRUCTOSE-6P-atom10" elementType="P" x2="-0.70903957" y2="-0.3079096"/> - <atom id="FRUCTOSE-6P-atom11" elementType="C" x2="0.67231643" y2="-0.519774"/> - <atom id="FRUCTOSE-6P-atom12" elementType="H" x2="0.52259886" y2="-1.0"/> - <atom id="FRUCTOSE-6P-atom13" elementType="O" x2="-0.70903957" y2="-0.60169494"/> - <atom id="FRUCTOSE-6P-atom14" elementType="C" x2="0.52259886" y2="-0.8248588"/> - <atom id="FRUCTOSE-6P-atom15" elementType="O" x2="-1.0" y2="-0.3079096"/> - <atom id="FRUCTOSE-6P-atom16" elementType="O" x2="-0.70903957" y2="-0.005649686"/> - <atom id="FRUCTOSE-6P-atom17" elementType="C" x2="0.67231643" y2="-0.7485876"/> - <atom id="FRUCTOSE-6P-atom18" elementType="C" x2="0.028248549" y2="-0.8248588"/> - <atom id="FRUCTOSE-6P-atom19" elementType="O" x2="0.52259886" y2="-0.65254235"/> - </atomArray> - <bondArray> - <bond id="FRUCTOSE-6P-bond1" atomRefs="FRUCTOSE-6P-atom19 FRUCTOSE-6P-atom14" order="1"/> - <bond id="FRUCTOSE-6P-bond2" atomRefs="FRUCTOSE-6P-atom18 FRUCTOSE-6P-atom14" order="1"/> - <bond id="FRUCTOSE-6P-bond3" atomRefs="FRUCTOSE-6P-atom17 FRUCTOSE-6P-atom11" order="1"/> - <bond id="FRUCTOSE-6P-bond4" atomRefs="FRUCTOSE-6P-atom15 FRUCTOSE-6P-atom10" order="1"/> - <bond id="FRUCTOSE-6P-bond5" atomRefs="FRUCTOSE-6P-atom13 FRUCTOSE-6P-atom10" order="1"/> - <bond id="FRUCTOSE-6P-bond6" atomRefs="FRUCTOSE-6P-atom12 FRUCTOSE-6P-atom14" order="1"/> - <bond id="FRUCTOSE-6P-bond7" atomRefs="FRUCTOSE-6P-atom11 FRUCTOSE-6P-atom14" order="1"/> - <bond id="FRUCTOSE-6P-bond8" atomRefs="FRUCTOSE-6P-atom10 FRUCTOSE-6P-atom16" order="2"/> - <bond id="FRUCTOSE-6P-bond9" atomRefs="FRUCTOSE-6P-atom10 FRUCTOSE-6P-atom1" order="1"/> - <bond id="FRUCTOSE-6P-bond10" atomRefs="FRUCTOSE-6P-atom9 FRUCTOSE-6P-atom17" order="1"/> - <bond id="FRUCTOSE-6P-bond11" atomRefs="FRUCTOSE-6P-atom8 FRUCTOSE-6P-atom11" order="1"/> - <bond id="FRUCTOSE-6P-bond12" atomRefs="FRUCTOSE-6P-atom7 FRUCTOSE-6P-atom18" order="1"/> - <bond id="FRUCTOSE-6P-bond13" atomRefs="FRUCTOSE-6P-atom6 FRUCTOSE-6P-atom11" order="1"/> - <bond id="FRUCTOSE-6P-bond14" atomRefs="FRUCTOSE-6P-atom5 FRUCTOSE-6P-atom4" order="1"/> - <bond id="FRUCTOSE-6P-bond15" atomRefs="FRUCTOSE-6P-atom4 FRUCTOSE-6P-atom18" order="1"/> - <bond id="FRUCTOSE-6P-bond16" atomRefs="FRUCTOSE-6P-atom4 FRUCTOSE-6P-atom8" order="1"/> - <bond id="FRUCTOSE-6P-bond17" atomRefs="FRUCTOSE-6P-atom3 FRUCTOSE-6P-atom18" order="1"/> - <bond id="FRUCTOSE-6P-bond18" atomRefs="FRUCTOSE-6P-atom2 FRUCTOSE-6P-atom4" order="1"/> - <bond id="FRUCTOSE-6P-bond19" atomRefs="FRUCTOSE-6P-atom1 FRUCTOSE-6P-atom2" order="1"/> - </bondArray> - <formula concise="C 6 H 13 O 9 P 1" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">260.137</float> - <string title="smiles">C(OP(O)(O)=O)[CH]1([CH](O)[CH](O)C(O)(O1)CO)</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="CIT" title="citrate" dictRef="dictCIT"> - <atomArray> - <atom id="CIT-atom1" elementType="O" x2="-0.62098" y2="0.17428"/> - <atom id="CIT-atom2" elementType="O" x2="0.6176" y2="0.20135"/> - <atom id="CIT-atom3" elementType="O" x2="-1.0" y2="-0.20474"/> - <atom id="CIT-atom4" elementType="C" x2="-0.022" y2="-0.45516"/> - <atom id="CIT-atom5" elementType="C" x2="-0.62098" y2="-0.20474"/> - <atom id="CIT-atom6" elementType="C" x2="-0.022" y2="-0.7665"/> - <atom id="CIT-atom7" elementType="C" x2="-0.47885" y2="-0.45516"/> - <atom id="CIT-atom8" elementType="O" x2="-0.022" y2="-0.07614"/> - <atom id="CIT-atom9" elementType="O" x2="0.27919" y2="-1.0"/> - <atom id="CIT-atom10" elementType="C" x2="0.36379" y2="-0.45516"/> - <atom id="CIT-atom11" elementType="O" x2="0.99662" y2="-0.17766"/> - <atom id="CIT-atom12" elementType="O" x2="-0.3198" y2="-1.0"/> - <atom id="CIT-atom13" elementType="C" x2="0.6176" y2="-0.17766"/> - </atomArray> - <bondArray> - <bond id="CIT-bond1" atomRefs="CIT-atom13 CIT-atom10" order="1"/> - <bond id="CIT-bond2" atomRefs="CIT-atom12 CIT-atom6" order="1"/> - <bond id="CIT-bond3" atomRefs="CIT-atom11 CIT-atom13" order="1"/> - <bond id="CIT-bond4" atomRefs="CIT-atom10 CIT-atom4" order="1"/> - <bond id="CIT-bond5" atomRefs="CIT-atom9 CIT-atom6" order="2"/> - <bond id="CIT-bond6" atomRefs="CIT-atom8 CIT-atom4" order="1"/> - <bond id="CIT-bond7" atomRefs="CIT-atom7 CIT-atom4" order="1"/> - <bond id="CIT-bond8" atomRefs="CIT-atom6 CIT-atom4" order="1"/> - <bond id="CIT-bond9" atomRefs="CIT-atom5 CIT-atom7" order="1"/> - <bond id="CIT-bond10" atomRefs="CIT-atom3 CIT-atom5" order="1"/> - <bond id="CIT-bond11" atomRefs="CIT-atom2 CIT-atom13" order="2"/> - <bond id="CIT-bond12" atomRefs="CIT-atom1 CIT-atom5" order="2"/> - </bondArray> - <formula concise="C 6 H 8 O 7" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">192.125</float> - <string title="smiles">C(=O)(O)CC(C(O)=O)(O)CC(O)=O</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="GLC-6-P" title="glucose-6-phosphate" dictRef="dictGLC-6-P"> - <atomArray> - <atom id="GLC-6-P-atom1" elementType="H" x2="-1.0" y2="-0.13312"/> - <atom id="GLC-6-P-atom2" elementType="C" x2="-0.68182" y2="0.32792"/> - <atom id="GLC-6-P-atom3" elementType="O" x2="-0.37338" y2="0.62013"/> - <atom id="GLC-6-P-atom4" elementType="O" x2="0.00974" y2="0.24351"/> - <atom id="GLC-6-P-atom5" elementType="C" x2="-0.06494" y2="-0.77273"/> - <atom id="GLC-6-P-atom6" elementType="P" x2="0.00974" y2="0.62013"/> - <atom id="GLC-6-P-atom7" elementType="C" x2="0.26299" y2="-0.36039"/> - <atom id="GLC-6-P-atom8" elementType="C" x2="-0.68182" y2="-0.77273"/> - <atom id="GLC-6-P-atom9" elementType="O" x2="0.00974" y2="0.99675"/> - <atom id="GLC-6-P-atom10" elementType="O" x2="-0.68182" y2="-0.54545"/> - <atom id="GLC-6-P-atom11" elementType="H" x2="0.26299" y2="-0.13312"/> - <atom id="GLC-6-P-atom12" elementType="C" x2="-1.0" y2="-0.36039"/> - <atom id="GLC-6-P-atom13" elementType="H" x2="-0.06494" y2="-0.54545"/> - <atom id="GLC-6-P-atom14" elementType="O" x2="-0.06494" y2="0.06494"/> - <atom id="GLC-6-P-atom15" elementType="O" x2="0.38636" y2="0.62013"/> - <atom id="GLC-6-P-atom16" elementType="O" x2="-0.06494" y2="-1.0"/> - <atom id="GLC-6-P-atom17" elementType="C" x2="-0.68182" y2="0.06494"/> - <atom id="GLC-6-P-atom18" elementType="O" x2="0.26299" y2="-0.58766"/> - <atom id="GLC-6-P-atom19" elementType="H" x2="-0.68182" y2="-1.0"/> - <atom id="GLC-6-P-atom20" elementType="O" x2="-1.0" y2="-0.58766"/> - <atom id="GLC-6-P-atom21" elementType="H" x2="-0.68182" y2="-0.16234"/> - </atomArray> - <bondArray> - <bond id="GLC-6-P-bond1" atomRefs="GLC-6-P-atom21 GLC-6-P-atom17" order="1"/> - <bond id="GLC-6-P-bond2" atomRefs="GLC-6-P-atom20 GLC-6-P-atom12" order="1"/> - <bond id="GLC-6-P-bond3" atomRefs="GLC-6-P-atom19 GLC-6-P-atom8" order="1"/> - <bond id="GLC-6-P-bond4" atomRefs="GLC-6-P-atom18 GLC-6-P-atom7" order="1"/> - <bond id="GLC-6-P-bond5" atomRefs="GLC-6-P-atom17 GLC-6-P-atom12" order="1"/> - <bond id="GLC-6-P-bond6" atomRefs="GLC-6-P-atom16 GLC-6-P-atom5" order="1"/> - <bond id="GLC-6-P-bond7" atomRefs="GLC-6-P-atom15 GLC-6-P-atom6" order="1"/> - <bond id="GLC-6-P-bond8" atomRefs="GLC-6-P-atom14 GLC-6-P-atom17" order="1"/> - <bond id="GLC-6-P-bond9" atomRefs="GLC-6-P-atom14 GLC-6-P-atom7" order="1"/> - <bond id="GLC-6-P-bond10" atomRefs="GLC-6-P-atom13 GLC-6-P-atom5" order="1"/> - <bond id="GLC-6-P-bond11" atomRefs="GLC-6-P-atom12 GLC-6-P-atom8" order="1"/> - <bond id="GLC-6-P-bond12" atomRefs="GLC-6-P-atom11 GLC-6-P-atom7" order="1"/> - <bond id="GLC-6-P-bond13" atomRefs="GLC-6-P-atom10 GLC-6-P-atom8" order="1"/> - <bond id="GLC-6-P-bond14" atomRefs="GLC-6-P-atom9 GLC-6-P-atom6" order="2"/> - <bond id="GLC-6-P-bond15" atomRefs="GLC-6-P-atom8 GLC-6-P-atom5" order="1"/> - <bond id="GLC-6-P-bond16" atomRefs="GLC-6-P-atom7 GLC-6-P-atom5" order="1"/> - <bond id="GLC-6-P-bond17" atomRefs="GLC-6-P-atom6 GLC-6-P-atom3" order="1"/> - <bond id="GLC-6-P-bond18" atomRefs="GLC-6-P-atom4 GLC-6-P-atom6" order="1"/> - <bond id="GLC-6-P-bond19" atomRefs="GLC-6-P-atom3 GLC-6-P-atom2" order="1"/> - <bond id="GLC-6-P-bond20" atomRefs="GLC-6-P-atom2 GLC-6-P-atom17" order="1"/> - <bond id="GLC-6-P-bond21" atomRefs="GLC-6-P-atom1 GLC-6-P-atom12" order="1"/> - </bondArray> - <formula concise="C 6 H 13 O 9 P 1" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">260.137</float> - <string title="smiles">C(OP(=O)(O)O)[CH]1([CH](O)[CH](O)[CH](O)[CH](O)O1)</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="GLYCEROL-3P" title="glycerol-3-phosphate" dictRef="dictGLYCEROL-3P"> - <atomArray> - <atom id="GLYCEROL-3P-atom1" elementType="O" x2="-0.06931" y2="0.43564"/> - <atom id="GLYCEROL-3P-atom2" elementType="O" x2="-1.0" y2="-0.29703"/> - <atom id="GLYCEROL-3P-atom3" elementType="P" x2="0.63036" y2="-0.63036"/> - <atom id="GLYCEROL-3P-atom4" elementType="O" x2="0.25413" y2="-0.88779"/> - <atom id="GLYCEROL-3P-atom5" elementType="C" x2="-0.07261" y2="-0.26073"/> - <atom id="GLYCEROL-3P-atom6" elementType="O" x2="0.36964" y2="-0.26073"/> - <atom id="GLYCEROL-3P-atom7" elementType="C" x2="-0.72277" y2="0.06271"/> - <atom id="GLYCEROL-3P-atom8" elementType="C" x2="-0.33003" y2="0.06271"/> - <atom id="GLYCEROL-3P-atom9" elementType="O" x2="0.9967" y2="-0.35974"/> - <atom id="GLYCEROL-3P-atom10" elementType="O" x2="0.90099" y2="-1.0"/> - </atomArray> - <bondArray> - <bond id="GLYCEROL-3P-bond1" atomRefs="GLYCEROL-3P-atom10 GLYCEROL-3P-atom3" order="1"/> - <bond id="GLYCEROL-3P-bond2" atomRefs="GLYCEROL-3P-atom9 GLYCEROL-3P-atom3" order="2"/> - <bond id="GLYCEROL-3P-bond3" atomRefs="GLYCEROL-3P-atom8 GLYCEROL-3P-atom5" order="1"/> - <bond id="GLYCEROL-3P-bond4" atomRefs="GLYCEROL-3P-atom7 GLYCEROL-3P-atom8" order="1"/> - <bond id="GLYCEROL-3P-bond5" atomRefs="GLYCEROL-3P-atom6 GLYCEROL-3P-atom3" order="1"/> - <bond id="GLYCEROL-3P-bond6" atomRefs="GLYCEROL-3P-atom5 GLYCEROL-3P-atom6" order="1"/> - <bond id="GLYCEROL-3P-bond7" atomRefs="GLYCEROL-3P-atom4 GLYCEROL-3P-atom3" order="1"/> - <bond id="GLYCEROL-3P-bond8" atomRefs="GLYCEROL-3P-atom2 GLYCEROL-3P-atom7" order="1"/> - <bond id="GLYCEROL-3P-bond9" atomRefs="GLYCEROL-3P-atom1 GLYCEROL-3P-atom8" order="1"/> - </bondArray> - <formula concise="C 3 H 9 O 6 P 1" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">172.074</float> - <string title="smiles">C(C(O)CO)OP(=O)(O)O</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="PROTON" title="H+" dictRef="dictPROTON"> - <atomArray> - <atom id="PROTON-atom1" elementType="H" x2="-1.0" y2="-1.0" formalCharge="1"/> - </atomArray> - <bondArray> - </bondArray> - <formula concise="H 1" formalCharge="1"/> - <float title="molecularWeight" units="g/mol">1.008</float> - <string title="smiles">[H+1]</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="FRUCTOSE-16-DIPHOSPHATE" title="fructose-1,6-bisphosphate" dictRef="dictFRUCTOSE-16-DIPHOSPHATE"> - <atomArray> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom1" elementType="H" x2="0.16364" y2="-0.97355"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom2" elementType="C" x2="0.28595" y2="-0.7686"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom3" elementType="C" x2="-0.34876" y2="-0.42149"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom4" elementType="H" x2="-0.34876" y2="-0.72893"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom5" elementType="O" x2="0.76529" y2="-0.53719"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom6" elementType="C" x2="0.28595" y2="-0.59008"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom7" elementType="P" x2="0.76529" y2="-0.7686"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom8" elementType="C" x2="-0.34876" y2="-0.59008"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom9" elementType="C" x2="0.16364" y2="-0.83471"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom10" elementType="O" x2="0.5405" y2="-0.7686"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom11" elementType="O" x2="0.28595" y2="-0.35868"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom12" elementType="O" x2="0.99669" y2="-0.7686"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom13" elementType="P" x2="-0.7686" y2="-0.42149"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom14" elementType="H" x2="-0.22645" y2="-0.69587"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom15" elementType="O" x2="-1.0" y2="-0.42149"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom16" elementType="O" x2="-0.0281" y2="-0.41157"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom17" elementType="O" x2="-0.7686" y2="-0.2"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom18" elementType="O" x2="-0.53388" y2="-0.42149"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom19" elementType="C" x2="-0.22645" y2="-0.83471"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom20" elementType="O" x2="0.76529" y2="-1.0"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom21" elementType="O" x2="-0.7686" y2="-0.66281"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom22" elementType="O" x2="0.16364" y2="-0.69587"/> - <atom id="FRUCTOSE-16-DIPHOSPHATE-atom23" elementType="O" x2="-0.22645" y2="-0.97355"/> - </atomArray> - <bondArray> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond1" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom23 FRUCTOSE-16-DIPHOSPHATE-atom19" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond2" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom22 FRUCTOSE-16-DIPHOSPHATE-atom9" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond3" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom21 FRUCTOSE-16-DIPHOSPHATE-atom13" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond4" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom20 FRUCTOSE-16-DIPHOSPHATE-atom7" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond5" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom19 FRUCTOSE-16-DIPHOSPHATE-atom9" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond6" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom18 FRUCTOSE-16-DIPHOSPHATE-atom3" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond7" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom17 FRUCTOSE-16-DIPHOSPHATE-atom13" order="2"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond8" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom16 FRUCTOSE-16-DIPHOSPHATE-atom6" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond9" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom15 FRUCTOSE-16-DIPHOSPHATE-atom13" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond10" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom14 FRUCTOSE-16-DIPHOSPHATE-atom19" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond11" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom13 FRUCTOSE-16-DIPHOSPHATE-atom18" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond12" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom12 FRUCTOSE-16-DIPHOSPHATE-atom7" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond13" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom11 FRUCTOSE-16-DIPHOSPHATE-atom6" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond14" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom10 FRUCTOSE-16-DIPHOSPHATE-atom2" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond15" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom8 FRUCTOSE-16-DIPHOSPHATE-atom19" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond16" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom8 FRUCTOSE-16-DIPHOSPHATE-atom16" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond17" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom7 FRUCTOSE-16-DIPHOSPHATE-atom10" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond18" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom6 FRUCTOSE-16-DIPHOSPHATE-atom9" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond19" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom5 FRUCTOSE-16-DIPHOSPHATE-atom7" order="2"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond20" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom4 FRUCTOSE-16-DIPHOSPHATE-atom8" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond21" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom3 FRUCTOSE-16-DIPHOSPHATE-atom8" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond22" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom2 FRUCTOSE-16-DIPHOSPHATE-atom6" order="1"/> - <bond id="FRUCTOSE-16-DIPHOSPHATE-bond23" atomRefs="FRUCTOSE-16-DIPHOSPHATE-atom1 FRUCTOSE-16-DIPHOSPHATE-atom9" order="1"/> - </bondArray> - <formula concise="C 6 H 14 O 12 P 2" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">340.117</float> - <string title="smiles">C(OP(O)(O)=O)C1(O)(O[CH]([CH](O)[CH](O)1)COP(=O)(O)O)</string> - <string title="systematicName">D-Fructose 1,6-bis(dihydrogenphosphate)</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="ATP" title="ATP" dictRef="dictATP"> - <atomArray> - <atom id="ATP-atom1" elementType="C" x2="0.9971347" y2="-0.16905439"/> - <atom id="ATP-atom2" elementType="P" x2="-0.4641834" y2="-0.68767905"/> - <atom id="ATP-atom3" elementType="O" x2="-1.0" y2="-0.68767905"/> - <atom id="ATP-atom4" elementType="N" x2="0.8767909" y2="-0.022922575"/> - <atom id="ATP-atom5" elementType="O" x2="-0.12320912" y2="-0.5071633"/> - <atom id="ATP-atom6" elementType="H" x2="0.5616046" y2="-0.8538682"/> - <atom id="ATP-atom7" elementType="H" x2="0.6418339" y2="-0.7851003"/> - <atom id="ATP-atom8" elementType="O" x2="-0.12320912" y2="-0.8653295"/> - <atom id="ATP-atom9" elementType="O" x2="-0.4641834" y2="-0.8653295"/> - <atom id="ATP-atom10" elementType="C" x2="0.5616046" y2="-0.7449857"/> - <atom id="ATP-atom11" elementType="N" x2="0.8939829" y2="-0.3409742"/> - <atom id="ATP-atom12" elementType="C" x2="0.6418339" y2="-0.89111745"/> - <atom id="ATP-atom13" elementType="O" x2="-0.4641834" y2="-0.5071633"/> - <atom id="ATP-atom14" elementType="C" x2="0.8939829" y2="-0.739255"/> - <atom id="ATP-atom15" elementType="C" x2="0.82234967" y2="-0.89111745"/> - <atom id="ATP-atom16" elementType="N" x2="0.4068768" y2="-0.10315186"/> - <atom id="ATP-atom17" elementType="C" x2="0.4068768" y2="-0.29226357"/> - <atom id="ATP-atom18" elementType="N" x2="0.5587393" y2="-0.3925501"/> - <atom id="ATP-atom19" elementType="N" x2="0.5587393" y2="0.17478514"/> - <atom id="ATP-atom20" elementType="O" x2="0.82234967" y2="-1.0"/> - <atom id="ATP-atom21" elementType="C" x2="0.72206306" y2="-0.10315186"/> - <atom id="ATP-atom22" elementType="C" x2="0.72206306" y2="-0.29226357"/> - <atom id="ATP-atom23" elementType="C" x2="0.5587393" y2="-0.0028653145"/> - <atom id="ATP-atom24" elementType="O" x2="0.6418339" y2="-1.0"/> - <atom id="ATP-atom25" elementType="P" x2="-0.12320912" y2="-0.68767905"/> - <atom id="ATP-atom26" elementType="H" x2="0.82234967" y2="-0.7851003"/> - <atom id="ATP-atom27" elementType="O" x2="-0.81948423" y2="-0.8653295"/> - <atom id="ATP-atom28" elementType="H" x2="0.8939829" y2="-0.8481375"/> - <atom id="ATP-atom29" elementType="C" x2="0.36389685" y2="-0.68767905"/> - <atom id="ATP-atom30" elementType="O" x2="0.7306591" y2="-0.66762173"/> - <atom id="ATP-atom31" elementType="O" x2="-0.29226357" y2="-0.68767905"/> - <atom id="ATP-atom32" elementType="O" x2="-0.81948423" y2="-0.5071633"/> - <atom id="ATP-atom33" elementType="O" x2="0.05157602" y2="-0.68767905"/> - <atom id="ATP-atom34" elementType="P" x2="-0.81948423" y2="-0.68767905"/> - <atom id="ATP-atom35" elementType="O" x2="-0.63610315" y2="-0.68767905"/> - </atomArray> - <bondArray> - <bond id="ATP-bond1" atomRefs="ATP-atom35 ATP-atom2" order="1"/> - <bond id="ATP-bond2" atomRefs="ATP-atom34 ATP-atom35" order="1"/> - <bond id="ATP-bond3" atomRefs="ATP-atom33 ATP-atom29" order="1"/> - <bond id="ATP-bond4" atomRefs="ATP-atom32 ATP-atom34" order="2"/> - <bond id="ATP-bond5" atomRefs="ATP-atom31 ATP-atom25" order="1"/> - <bond id="ATP-bond6" atomRefs="ATP-atom30 ATP-atom14" order="1"/> - <bond id="ATP-bond7" atomRefs="ATP-atom29 ATP-atom10" order="1"/> - <bond id="ATP-bond8" atomRefs="ATP-atom28 ATP-atom14" order="1"/> - <bond id="ATP-bond9" atomRefs="ATP-atom27 ATP-atom34" order="1"/> - <bond id="ATP-bond10" atomRefs="ATP-atom26 ATP-atom15" order="1"/> - <bond id="ATP-bond11" atomRefs="ATP-atom25 ATP-atom33" order="1"/> - <bond id="ATP-bond12" atomRefs="ATP-atom24 ATP-atom12" order="1"/> - <bond id="ATP-bond13" atomRefs="ATP-atom23 ATP-atom16" order="A"/> - <bond id="ATP-bond14" atomRefs="ATP-atom22 ATP-atom21" order="A"/> - <bond id="ATP-bond15" atomRefs="ATP-atom21 ATP-atom4" order="A"/> - <bond id="ATP-bond16" atomRefs="ATP-atom21 ATP-atom23" order="A"/> - <bond id="ATP-bond17" atomRefs="ATP-atom20 ATP-atom15" order="1"/> - <bond id="ATP-bond18" atomRefs="ATP-atom19 ATP-atom23" order="1"/> - <bond id="ATP-bond19" atomRefs="ATP-atom18 ATP-atom22" order="A"/> - <bond id="ATP-bond20" atomRefs="ATP-atom17 ATP-atom18" order="A"/> - <bond id="ATP-bond21" atomRefs="ATP-atom16 ATP-atom17" order="A"/> - <bond id="ATP-bond22" atomRefs="ATP-atom14 ATP-atom15" order="1"/> - <bond id="ATP-bond23" atomRefs="ATP-atom14 ATP-atom11" order="1"/> - <bond id="ATP-bond24" atomRefs="ATP-atom13 ATP-atom2" order="2"/> - <bond id="ATP-bond25" atomRefs="ATP-atom12 ATP-atom15" order="1"/> - <bond id="ATP-bond26" atomRefs="ATP-atom11 ATP-atom22" order="A"/> - <bond id="ATP-bond27" atomRefs="ATP-atom10 ATP-atom12" order="1"/> - <bond id="ATP-bond28" atomRefs="ATP-atom10 ATP-atom30" order="1"/> - <bond id="ATP-bond29" atomRefs="ATP-atom9 ATP-atom2" order="1"/> - <bond id="ATP-bond30" atomRefs="ATP-atom8 ATP-atom25" order="1"/> - <bond id="ATP-bond31" atomRefs="ATP-atom7 ATP-atom12" order="1"/> - <bond id="ATP-bond32" atomRefs="ATP-atom6 ATP-atom10" order="1"/> - <bond id="ATP-bond33" atomRefs="ATP-atom5 ATP-atom25" order="2"/> - <bond id="ATP-bond34" atomRefs="ATP-atom4 ATP-atom1" order="A"/> - <bond id="ATP-bond35" atomRefs="ATP-atom3 ATP-atom34" order="1"/> - <bond id="ATP-bond36" atomRefs="ATP-atom2 ATP-atom31" order="1"/> - <bond id="ATP-bond37" atomRefs="ATP-atom1 ATP-atom11" order="A"/> - </bondArray> - <formula concise="C 10 H 16 N 5 O 13 P 3" formalCharge="-4"/> - <float title="molecularWeight" units="g/mol">507.183</float> - <string title="smiles">[CH]3(n1(c2(c(nc1)c(N)ncn2)))(O[CH]([CH](O)[CH](O)3)COP(=O)(O)OP(O)(=O)OP(O)(=O)O)</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="DPG" title="3-phospho-D-glyceroyl-phosphate" dictRef="dictDPG"> - <atomArray> - <atom id="DPG-atom1" elementType="C" x2="-0.02174" y2="-0.73602"/> - <atom id="DPG-atom2" elementType="P" x2="0.73292" y2="-0.48137"/> - <atom id="DPG-atom3" elementType="O" x2="0.73292" y2="-0.21739"/> - <atom id="DPG-atom4" elementType="P" x2="-0.73602" y2="-0.48137"/> - <atom id="DPG-atom5" elementType="O" x2="0.49379" y2="-0.48137"/> - <atom id="DPG-atom6" elementType="O" x2="-0.73602" y2="-0.21739"/> - <atom id="DPG-atom7" elementType="O" x2="-0.52484" y2="-0.48137"/> - <atom id="DPG-atom8" elementType="O" x2="-0.02174" y2="-1.0"/> - <atom id="DPG-atom9" elementType="C" x2="-0.25776" y2="-0.48137"/> - <atom id="DPG-atom10" elementType="O" x2="0.99689" y2="-0.48137"/> - <atom id="DPG-atom11" elementType="O" x2="-0.25776" y2="-0.21739"/> - <atom id="DPG-atom12" elementType="O" x2="-0.73602" y2="-0.74534"/> - <atom id="DPG-atom13" elementType="O" x2="0.73292" y2="-0.74534"/> - <atom id="DPG-atom14" elementType="O" x2="-1.0" y2="-0.48137"/> - <atom id="DPG-atom15" elementType="C" x2="0.21739" y2="-0.48137"/> - </atomArray> - <bondArray> - <bond id="DPG-bond1" atomRefs="DPG-atom15 DPG-atom5" order="1"/> - <bond id="DPG-bond2" atomRefs="DPG-atom9 DPG-atom1" order="1"/> - <bond id="DPG-bond3" atomRefs="DPG-atom9 DPG-atom11" order="2"/> - <bond id="DPG-bond4" atomRefs="DPG-atom7 DPG-atom9" order="1"/> - <bond id="DPG-bond5" atomRefs="DPG-atom5 DPG-atom2" order="1"/> - <bond id="DPG-bond6" atomRefs="DPG-atom4 DPG-atom7" order="1"/> - <bond id="DPG-bond7" atomRefs="DPG-atom4 DPG-atom6" order="1"/> - <bond id="DPG-bond8" atomRefs="DPG-atom4 DPG-atom12" order="1"/> - <bond id="DPG-bond9" atomRefs="DPG-atom4 DPG-atom14" order="2"/> - <bond id="DPG-bond10" atomRefs="DPG-atom2 DPG-atom3" order="1"/> - <bond id="DPG-bond11" atomRefs="DPG-atom2 DPG-atom13" order="1"/> - <bond id="DPG-bond12" atomRefs="DPG-atom2 DPG-atom10" order="2"/> - <bond id="DPG-bond13" atomRefs="DPG-atom1 DPG-atom15" order="1"/> - <bond id="DPG-bond14" atomRefs="DPG-atom1 DPG-atom8" order="1"/> - </bondArray> - <formula concise="C 3 H 8 O 10 P 2" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">266.038</float> - <string title="smiles">C(OP(O)(O)=O)(=O)C(O)COP(O)(O)=O</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="G3P" title="3-phosphoglycerate" dictRef="dictG3P"> - <atomArray> - <atom id="G3P-atom1" elementType="C" x2="5.7" y2="-0.5"/> - <atom id="G3P-atom2" elementType="C" x2="5.7" y2="-1.25"/> - <atom id="G3P-atom3" elementType="C" x2="5.6995" y2="0.25"/> - <atom id="G3P-atom4" elementType="O" x2="6.3499" y2="0.6232"/> - <atom id="G3P-atom5" elementType="O" x2="5.0484" y2="0.6225"/> - <atom id="G3P-atom6" elementType="O" x2="6.45" y2="-0.4998"/> - <atom id="G3P-atom7" elementType="P" x2="7.0977" y2="-1.6376"/> - <atom id="G3P-atom8" elementType="O" x2="7.0887" y2="-2.3709"/> - <atom id="G3P-atom9" elementType="O" x2="7.8767" y2="-1.6513"/> - <atom id="G3P-atom10" elementType="O" x2="7.1108" y2="-0.9002"/> - <atom id="G3P-atom11" elementType="O" x2="6.3477" y2="-1.6285"/> - </atomArray> - <bondArray> - <bond id="G3P-bond1" atomRefs="G3P-atom7 G3P-atom11" order="1"/> - <bond id="G3P-bond2" atomRefs="G3P-atom7 G3P-atom10" order="1"/> - <bond id="G3P-bond3" atomRefs="G3P-atom7 G3P-atom9" order="2"/> - <bond id="G3P-bond4" atomRefs="G3P-atom7 G3P-atom8" order="1"/> - <bond id="G3P-bond5" atomRefs="G3P-atom2 G3P-atom11" order="1"/> - <bond id="G3P-bond6" atomRefs="G3P-atom1 G3P-atom6" order="1"/> - <bond id="G3P-bond7" atomRefs="G3P-atom1 G3P-atom3" order="1"/> - <bond id="G3P-bond8" atomRefs="G3P-atom3 G3P-atom5" order="2"/> - <bond id="G3P-bond9" atomRefs="G3P-atom3 G3P-atom4" order="1"/> - <bond id="G3P-bond10" atomRefs="G3P-atom1 G3P-atom2" order="1"/> - </bondArray> - <formula concise="C 3 H 7 O 7 P 1" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">186.058</float> - <string title="smiles">C(OP(=O)(O)O)C(O)C(=O)O</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="2-PG" title="2-phosphoglycerate" dictRef="dict2-PG"> - <atomArray> - <atom id="2-PG-atom1" elementType="C" x2="2.8208" y2="-1.4"/> - <atom id="2-PG-atom2" elementType="C" x2="2.8208" y2="-0.65"/> - <atom id="2-PG-atom3" elementType="O" x2="2.1713" y2="-1.775"/> - <atom id="2-PG-atom4" elementType="O" x2="3.4704" y2="-1.775"/> - <atom id="2-PG-atom5" elementType="C" x2="2.8208" y2="0.1"/> - <atom id="2-PG-atom6" elementType="O" x2="3.4704" y2="0.475"/> - <atom id="2-PG-atom7" elementType="P" x2="1.2603" y2="-0.6662"/> - <atom id="2-PG-atom8" elementType="O" x2="1.2502" y2="0.0671"/> - <atom id="2-PG-atom9" elementType="O" x2="0.452" y2="-0.652"/> - <atom id="2-PG-atom10" elementType="O" x2="1.2663" y2="-1.4037"/> - <atom id="2-PG-atom11" elementType="O" x2="2.0727" y2="-0.6505"/> - </atomArray> - <bondArray> - <bond id="2-PG-bond1" atomRefs="2-PG-atom7 2-PG-atom11" order="1"/> - <bond id="2-PG-bond2" atomRefs="2-PG-atom7 2-PG-atom10" order="1"/> - <bond id="2-PG-bond3" atomRefs="2-PG-atom7 2-PG-atom9" order="2"/> - <bond id="2-PG-bond4" atomRefs="2-PG-atom7 2-PG-atom8" order="1"/> - <bond id="2-PG-bond5" atomRefs="2-PG-atom5 2-PG-atom6" order="1"/> - <bond id="2-PG-bond6" atomRefs="2-PG-atom2 2-PG-atom5" order="1"/> - <bond id="2-PG-bond7" atomRefs="2-PG-atom2 2-PG-atom11" order="1"/> - <bond id="2-PG-bond8" atomRefs="2-PG-atom1 2-PG-atom4" order="2"/> - <bond id="2-PG-bond9" atomRefs="2-PG-atom1 2-PG-atom3" order="1"/> - <bond id="2-PG-bond10" atomRefs="2-PG-atom1 2-PG-atom2" order="1"/> - </bondArray> - <formula concise="C 3 H 7 O 7 P 1" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">186.058</float> - <string title="smiles">C(O)(=O)C(CO)OP(=O)(O)O</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="MG+2" title="Mg2+" dictRef="dictMG+2"> - <atomArray> - <atom id="MG+2-atom1" elementType="MG" x2="-1.0" y2="-1.0" formalCharge="2"/> - </atomArray> - <bondArray> - </bondArray> - <formula concise="MG 1" formalCharge="2"/> - <float title="molecularWeight" units="g/mol">24.305</float> - <string title="smiles">[Mg+2]</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="PHOSPHO-ENOL-PYRUVATE" title="phosphoenolpyruvate" dictRef="dictPHOSPHO-ENOL-PYRUVATE"> - <atomArray> - <atom id="PHOSPHO-ENOL-PYRUVATE-atom1" elementType="O" x2="-0.57576" y2="-0.15789"/> - <atom id="PHOSPHO-ENOL-PYRUVATE-atom2" elementType="O" x2="0.24721" y2="0.33652"/> - <atom id="PHOSPHO-ENOL-PYRUVATE-atom3" elementType="O" x2="-1.0" y2="-0.57576"/> - <atom id="PHOSPHO-ENOL-PYRUVATE-atom4" elementType="C" x2="-0.57576" y2="0.26635"/> - <atom id="PHOSPHO-ENOL-PYRUVATE-atom5" elementType="C" x2="-0.9075" y2="0.52791"/> - <atom id="PHOSPHO-ENOL-PYRUVATE-atom6" elementType="O" x2="-0.15152" y2="-0.57576"/> - <atom id="PHOSPHO-ENOL-PYRUVATE-atom7" elementType="O" x2="-0.57576" y2="-1.0"/> - <atom id="PHOSPHO-ENOL-PYRUVATE-atom8" elementType="O" x2="-0.10686" y2="0.99681"/> - <atom id="PHOSPHO-ENOL-PYRUVATE-atom9" elementType="P" x2="-0.57576" y2="-0.57576"/> - <atom id="PHOSPHO-ENOL-PYRUVATE-atom10" elementType="C" x2="-0.10686" y2="0.57257"/> - </atomArray> - <bondArray> - <bond id="PHOSPHO-ENOL-PYRUVATE-bond1" atomRefs="PHOSPHO-ENOL-PYRUVATE-atom10 PHOSPHO-ENOL-PYRUVATE-atom4" order="1"/> - <bond id="PHOSPHO-ENOL-PYRUVATE-bond2" atomRefs="PHOSPHO-ENOL-PYRUVATE-atom8 PHOSPHO-ENOL-PYRUVATE-atom10" order="2"/> - <bond id="PHOSPHO-ENOL-PYRUVATE-bond3" atomRefs="PHOSPHO-ENOL-PYRUVATE-atom7 PHOSPHO-ENOL-PYRUVATE-atom9" order="2"/> - <bond id="PHOSPHO-ENOL-PYRUVATE-bond4" atomRefs="PHOSPHO-ENOL-PYRUVATE-atom6 PHOSPHO-ENOL-PYRUVATE-atom9" order="1"/> - <bond id="PHOSPHO-ENOL-PYRUVATE-bond5" atomRefs="PHOSPHO-ENOL-PYRUVATE-atom5 PHOSPHO-ENOL-PYRUVATE-atom4" order="2"/> - <bond id="PHOSPHO-ENOL-PYRUVATE-bond6" atomRefs="PHOSPHO-ENOL-PYRUVATE-atom4 PHOSPHO-ENOL-PYRUVATE-atom1" order="1"/> - <bond id="PHOSPHO-ENOL-PYRUVATE-bond7" atomRefs="PHOSPHO-ENOL-PYRUVATE-atom3 PHOSPHO-ENOL-PYRUVATE-atom9" order="1"/> - <bond id="PHOSPHO-ENOL-PYRUVATE-bond8" atomRefs="PHOSPHO-ENOL-PYRUVATE-atom2 PHOSPHO-ENOL-PYRUVATE-atom10" order="1"/> - <bond id="PHOSPHO-ENOL-PYRUVATE-bond9" atomRefs="PHOSPHO-ENOL-PYRUVATE-atom1 PHOSPHO-ENOL-PYRUVATE-atom9" order="1"/> - </bondArray> - <formula concise="C 3 H 5 O 6 P 1" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">168.043</float> - <string title="smiles">C=C(C(=O)O)OP(O)(=O)O</string> - </molecule> - </cml> - CML - - - - - - - - - <cml> <molecule id="WATER" title="H2O" dictRef="dictWATER"> - <atomArray> - <atom id="WATER-atom1" elementType="O" x2="0.08287" y2="-0.19337"/> - <atom id="WATER-atom2" elementType="H" x2="-1.0" y2="-0.74586"/> - <atom id="WATER-atom3" elementType="H" x2="0.99448" y2="-1.0"/> - </atomArray> - <bondArray> - <bond id="WATER-bond1" atomRefs="WATER-atom3 WATER-atom1" order="1"/> - <bond id="WATER-bond2" atomRefs="WATER-atom2 WATER-atom1" order="1"/> - </bondArray> - <formula concise="H 2 O 1" formalCharge="0"/> - <float title="molecularWeight" units="g/mol">18.015</float> - <string title="smiles">[OH2]</string> - </molecule> - </cml> - CML - - - - - - - - - PKI-COMPLEX - Pyruvate kinase I and pyruvate kinase II differ in physical and chemical properties as -well as in their kinetic behavior. Although the two forms are under -independent genetic control they do coexist in a wide range of -nutritional and metabolic states. The two forms are -not interconvertible. Both show positive cooperative effects with -respect to the substrate phosphoenolpyruvate.|CITS:[83114522]| The -enzyme has a low nucleotide specificity and the 5'-diphosphates of -guanosine, inosine, uridine and cytidine can all serve as phospho -acceptors.|CITS: [90336973]| Form I from E coli unlike form II is remarkably -stable. |CITS:[91315755]| - - - - - - - - - - - PKII-CPLX - - - - - - - - - - - E.coli is unusual in having two glyceraldehyde-3-phosphate dehydrogenases. -The protein GAPDH-A has a sequence that is more similar to eukaryotic -sequences than it is to prokaryotic types |CITS:[91087241]|. GapA is required -for glycolysis, while Epd (GapB) is not |CITS: [9260967]|. GapA and Epd may be involved -in production of pyridoxal 5'-phosphate (PLP) |CITS: [9696782]|. - GAPDH-A-CPLX - - - - - - - - - - - - - - - 6PFK-2-CPX - This enzyme is an isozyme with phosphofructokinase-1. The -nucleotide sequences of the genes are not similar.|CITS: [85203917]| - - - - - - - - - - - - - TPI - - - - - - - - - - - FRUCBISALD-CLASSII - In relation to the Class I enzymes (primarily studied and found in - eukaryotes) comparatively little is known about the class II enzymes. - The Class II aldolases of Sacc. cer. and E. coli are the best - characterized.|CITS: [89193446]| It resembles the typical class II - aldolase from yeast in size and amino acid composition. This is a - strong suggestion that they are related. |CITS:[78165651]| These less - well studied aldolases are found both in the eukaryotic green algae - and fungi, and in the prokaryotic blue-green algae and bacteria. - |CITS:[78165651]| - The gene pgk, encoding the enzyme phosphoglycerate - kinase, was carried on plasmid pLC33-5 of the collection of Clarke and - Carbon. It was also noted that E.coli cells tansformed with this - plasmid exhibited raised levels of Class II fructose 1,6 bisphosphate - aldolase activity, suggesting that the same plasmid might also carry - the structural gene (fba) for this enzyme. |CITS: [89193446]| - - - - - - - - - - - - - FRUCBISALD-CLASSI - The typical class I aldolases of plants and animals have been -throroughly studied |CITS: [78165651]| Fructose-1,6-bisphosphate -aldolases can be divided into two -classes on the basis of their catalytic and structural properties. -|CITS: [78165651]| Class I fructose 1,6 bisphosphate aldolases were -once thought -to be confined to eukaryotic organisms but have since been detected in -several bacterial species. |CITS: [78165652]| The occurence of such -an aldolase in bacteria was unexpected in light of the -phylogenetic distribution of aldolases. |CITS: [73229139]| The -enzymes of eukaryotes generally fall into Class I and are tetramers of -identical polypeptide chains. |CITS: [89193446]| -In earlier studies |CITS: [73229139]| it was thought that the class I E. coli -aldolase was typical in that it was tetrameric with a mol. wt. -of approx. 140K. In 1978 new purification techniques were used.The true aldolase 1 -activity could be measured by using Fru-1,6-P<SUB>2</SUB> that had been purified -by chromatography on DEAE-cellulose to remove the -fructose-6-phosphate. Using these methods the enzyme appeared to be -larger than was previously supposed and may be a decamer with a mol. wt. -of approx. 340,000. The size of aldolase 1 and the effect of cross-linking reagents -on it, indicate that its structure must differ significantly from that -of the typical tetrameric class-I enzymes from eukaryotes. |CITS: [78165652] -[73229139]| - - - - - - - - - - - - - 6PFK-1-CPX - This enzyme is an isozyme with phosphofructokinase-2. The -nucleotide sequences of the genes are not similar |CITS: [85203917]|. The -tetrameric species is the only one which can bind both substrates and -effectors, and thus have both catalytic and regulatory properties. The -C terminal end of the peptide is required for allosteric -properties.|CITS: [90276415]| Crystal structures have been solved -with and without activators and inhibitors. |CITS: [89342465], [89125622]| - - - - - - - - - - - - - - - PHOSGLYCMUTASE - - - - - - - - - - - ENOLASE-CPLX - The enzyme denatures in the absence of Mg. When E. coli enolase was -treated with EDTA in attempts to remove all residual activity prior to -the Mg activation studies, it was found that the enzyme was unstable in -the absence of Mg and that substantial and irreversible loss of -activity was observed after very short exposure of the enzyme to EDTA. -|CITS:[72060411]| - - - - - - - - - - - EcoCyc Database (http://ecocyc.org) - - - - - - - - - ACTIVATION-NONALLOSTERIC - - - - - - - - - - - INHIBITION - - - - - - - - - - - INHIBITION - high concentrations of Mg+2 and ADP |CITS:[89228557]| - - - - - - - - - - - ACTIVATION - An activator only at low Mg<SUP>+2</SUP> and Ca<SUP>+2</SUP> concentrations, -otherwise it is an inhibitor. |CITS: [83282602]| - - - - - - - - - - - INHIBITION - high concentrations of Mg+2 and ADP |CITS:[89228557]| - - - - - - - - - - - INHIBITION - high concentrations of Mg+2 and ADP |CITS:[89228557]| - - - - - - - - - - - ACTIVATION-ALLOSTERIC - - - - - - - - - - - ACTIVATION-ALLOSTERIC - - - - - - - - - - - INHIBITION - Vanadate strongly inhibits the enzyme. |CITS: [99364512]| - - - - - - - - - - - ACTIVATION - - - - - - - - - - - ACTIVATION - - - - - - - - - - - ACTIVATION - - - - - - - - - - - - ACTIVATION-ALLOSTERIC - - - - - - - - - - - INHIBITION - - - - - - - - - - - - INHIBITION - - - - - - - - - - - INHIBITION - - - - - - - - - - - ACTIVATION-ALLOSTERIC - - - - - - - - - - - ACTIVATION - - - - - - - - - - - ACTIVATION - - - - - - - - - - - INHIBITION - - - - - - - - - - - ACTIVATION - - - - - - - - - - - INHIBITION-ALLOSTERIC - - - - - - - - - - - INHIBITION - - - - - - - - - - - - ACTIVATION - - - - - - - - - - - cytoplasm - - - - - - - - - - cellular_component unknown - - - - - - - - - - Embden-Meyerhof pathway - Pyruvate from glycolysis proceeds to the pyruvate dehydrogenase multienzyme complex, and the acetyl CoA produced then proceeds on to the superpathway of glyoxylate bypass and TCA. - This pathway is freely available to all users and may be redistributed in whole or in part provided proper source attribution is made. See http://biocyc.org/open-reg.shtml for more information. - glucose degradation - glycolysis I - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.0 - - - - - - - - - - 1.0 - - - - - - - - - - 1.0 - - - - - - - - - - - - - - - - - - - - 4.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - - - - - - - - - 4.0 - - - - - - - - - - - 1.0 - - - - - - - - - - 1.0 - - - - - - - - - - - 1.0 - - - - - - - - - - 1.0 - - - - - - - - - - - - - - - - - - - - 1.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - - - - - - - - - - 4.0 - - - - - - - - - - - - - - - - - - - - 1.0 - - - - - - - - - - 1.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - - - - - - - - - - 2.0 - - - - - - - - - - - 2.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - - - - - - - - - - 2.0 - - - - - - - - - - - - - - - - - - - - 10.0 - - - - - - - - - - - - - - - - - - - - 1.0 - - - - - - - - - - - 1.0 - - - - - - - - - - 1.0 - - - - - - - - - - 1.0 - - - - - - - - - - 1.0 - - - - - - - - - - - - - - - - - - - 1.0 - - - - - - - - - - - - - - - - - - - - 4.0 - - - - - - - - - - - 1.0 - - - - - - - - - - 1.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - - - - - - - - - - 1.0 - - - - - - - - - - - - - - - - - - - 2.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - 1.0 - - - - - - - - - - - - - - - - - - - - 2.0 - - - - - - - - - - - B1676 - MKKTKIVCTIGPKTESEEMLAKMLDAGMNVMRLNFSHGDYAEHGQRIQNLRNVMSKTGKTAAILLDTKGPEIRTMKLEGGNDVSLKAGQTFTFTTDKSVIGNSEMVAVTYEGFTTDLSVGNTVLVDDGLIGMEVTAIEGNKVICKVLNNGDLGENKGVNLPGVSIALPALAEKDKQDLIFGCEQGVDFVAASFIRKRSDVIEIREHLKAHGGENIHIISKIENQEGLNNFDEILEASDGIMVARGDLGVEIPVEEVIFAQKMMIEKCIRARKVVITATQMLDSMIKNPRPTRAEAGDVANAILDGTDAVMLSGESAKGKYPLEAVSIMATICERTDRVMNSRLEFNNDNRKLRITEAVCRGAVETAEKLDAPLIVVATQGGKSARAVRKYFPDATILALTTNEKTAHQLVLSKGVVPQLVKEITSTDDFYRLGKELALQSGLAHKGDVVVMVSGALVPSGTTNTASVHVL - PykF - Type I pyruvate kinase is made up of 522 amino acids. -Neither type I nor II contains tryptophan. The two forms of the enzyme, I and II are -different proteins.|CITS:[83114522]| Pyruvate kinase F was previously -referred to as pyruvate kinase B, now as I |CITS:[84029179]| A free N-terminal -amino acid can be detected in both forms of pyruvate kinase it -corresponds to methionine for type I and serine for type -II.|CITS:[83114522]| Comparison with the known primary structures shows that -bacterial enzymes lack a substantial portion of the N-terminal -sequence with respect to pyruvate kinases from vertebrates. |CITS:[91315755]| - pyruvate kinase I monomer - - - - - - - - - - - - - - - - - - B1854 - MSRRLRRTKIVTTLGPATDRDNNLEKVIAAGANVVRMNFSHGSPEDHKMRADKVREIAAKLGRHVAILGDLQGPKIRVSTFKEGKVFLNIGDKFLLDANLGKGEGDKEKVGIDYKGLPADVVPGDILLLDDGRVQLKVLEVQGMKVFTEVTVGGPLSNNKGINKLGGGLSAEALTEKDKADIKTAALIGVDYLAVSFPRCGEDLNYARRLARDAGCDAKIVAKVERAEAVCSQDAMDDIILASDVVMVARGDLGVEIGDPELVGIQKALIRRARQLNRAVITATQMMESMITNPMPTRAEVMDVANAVLDGTDAVMLSAETAAGQYPSETVAAMARVCLGAEKIPSINVSKHRLDVQFDNVEEAIAMSAMYAANHLKGVTAIITMTESGRTALMTSRISSGLPIFAMSRHERTLNLTALYRGVTPVHFDSANDGVAAASEAVNLLRDKGYLMSGDLVIVTQGDVMSTVGSTNTTRILTVE - PykA - There are 2 genes, pykA and pykF, for 2 isozymes - pyruvate kinase II monomer - - - - - - - - - - - - - - - B4395 - GpmB - MLQVYLVRHGETQWNAERRIQGQSDSPLTAKGEQQAMQVATRAKELGITHIISSDLGRTRRTAEIIAQACGCDIIFDSRLRELNMGVLEKRHIDSLTEEEENWRRQLVNGTVDGRIPEGESMQELSDRVNAALESCRDLPQGSRPLLVSHGIALGCLVSTILGLPAWAERRLRLRNCSISRVDYQESLWLASGWVVETAGDISHLDAPALDELQR - PGAM2-MONOMER - The enzyme has not been characterized and the subunit -structure is unknown. However, phosphoglycerate mutase 1 is a -homodimer. - YtjC - - - - - - - - - - - - - - - A higher degree of sequence homology exists between E.coli -and eucaryotic enzymes than betwen E. coli and the thermophilic bacterial -enzyme |CITS:[85257641]|. Mutant exhibits a growth defect and also exhibits -increased aggregation and lysis that are rescued by high-salt media |CITS: [9260967]|. - -Regulation has been described |CITS: [12672900]|. The regulation of the fkpA, gapA, and hslT genes is affected by evolution under conditions of chronic heat stress |CITS: [12672900]|. - B1779 - Gad - Gap1 - GapA - MTIKVGINGFGRIGRIVFRAAQKRSDIEIVAINDLLDADYMAYMLKYDSTHGRFDGTVEVKDGHLIVNGKKIRVTAERDPANLKWDEVGVDVVAEATGLFLTDETARKHITAGAKKVVMTGPSKDNTPMFVKGANFDKYAGQDIVSNASCTTNCLAPLAKVINDNFGIIEGLMTTVHATTATQKTVDGPSHKDWRGGRGASQNIIPSSTGAAKAVGKVLPELNGKLTGMAFRVPTPNVSVVDLTVRLEKAATYEQIKAAVKAAAEGEMKGVLGYTEDDVVSTDFNGEVCTSVFDAKAGIALNDNFVKLVSWYDNETGYSNKVLDLIAHISK - glyceraldehyde 3-phosphate dehydrogenase-A monomer - - - - - - - - - - - - - - - - - - - B2926 - MSVIKMTDLDLAGKRVFIRADLNVPVKDGKVTSDARIRASLPTIELALKQGAKVMVTSHLGRPTEGEYNEEFSLLPVVNYLKDKLSNPVRLVKDYLDGVDVAEGELVVLENVRFNKGEKKDDETLSKKYAALCDVFVMDAFGTAHRAQASTHGIGKFADVACAGPLLAAELDALGKALKEPARPMVAIVGGSKVSTKLTVLDSLSKIADQLIVGGGIANTFIAAQGHDVGKSLYEADLVDEAKRLLTTCNIPVPSDVRVATEFSETAPATLKSVNDVKADEQILDIGDASAQELAEILKNAKTILWNGPVGVFEFPNFRKGTEIVANAIADSEAFSIAGGGDTLAAIDLFGIADKISYISTGGGAFLEFVEGKVLPAVAMLEERAKK - PGK - Pgk - Phosphoglycerate kinase is one of the proteins induced by anaerobiosis. -|CITS:[89306676]| The gene is transcribed from two promoters, one immediately -in front of an upstream gene coding for a 38-kDa polypeptide of -unknown function. The pgk gene was also found to show growth phase regulation. A -structural determinant for glycerate 3-P kinase is located near serA. -The map order is speB-pgk-serA-lysA-argA-eno-cysC.|CITS:[76195925]| - -Pgk has similarity to an <i>Edwardsiella ictaluri</i> protein |CITS: [12542086]|. - - - - - - - - - - - - - - - 6-phosphofructokinase-2 monomer - B1723 - MVRIYTLTLAPSLDSATITPQIYPEGKLRCTAPVFEPGGGGINVARAIAHLGGSATAIFPAGGATGEHLVSLLADENVPVATVEAKDWTRQNLHVHVEASGEQYRFVMPGAALNEDEFRQLEEQVLEIESGAILVISGSLPPGVKLEKLTQLISAAQKQGIRCIVDSSGEALSAALAIGNIELVKPNQKELSALVNRELTQPDDVRKAAQEIVNSGKAKRVVVSLGPQGALGVDSENCIQVVPPPVKSQSTVGAGDSMVGAMTLKLAENASLEEMVRFGVAAGSAATLNQGTRLCSHDDTQKIYAYLSR - PfkB - - - - - - - - - - - - - - - B3919 - MRHPLVMGNWKLNGSRHMVHELVSNLRKELAGVAGCAVAIAPPEMYIDMAKREAEGSHIMLGAQNVDLNLSGAFTGETSAAMLKDIGAQYIIIGHSERRTYHKESDELIAKKFAVLKEQGLTPVLCIGETEAENEAGKTEEVCARQIDAVLKTQGAAAFEGAVIAYEPVWAIGTGKSATPAQAQAVHKFIRDHIAKVDANIAEQVIIQYGGSVNASNAAELFAQPDIDGALVGGASLKADAFAVIVKAAEAAKQA - Tpi - TpiA - triose phosphate isomerase monomer - - - - - - - - - - - - - - - - - Ald - B2925 - Fba - FbaA - Fda - MSKIFDFVKPGVITGDDVQKVFQVAKENNFALPAVNCVGTDSINAVLETAAKVKAPVIVQFSNGGASFIAGKGVKSDVPQGAAILGAISGAHHVHQMAEHYGVPVILHTDHCAKKLLPWIDGLLDAGEKHFAATGKPLFSSHMIDLSEESLQENIEICSKYLERMSKIGMTLEIELGCTGGEEDGVDNSHMDASALYTQPEDVDYAYTELSKISPRFTIAASFGNVHGVYKPGNVVLTPTILRDSQEYVSKKHNLPHNSLNFVFHGGSGSTAQEIKDSVSYGVVKMNIDTDTQWATWEGVLNYYKANEAYLQGQLGNPKGEDQPNKKYYDPRVWLRAGQTSMIARLEKAFQELNAIDVL - The amino acid sequence of the E.coli Class II -fructose-1,6-bisphosphate aldolase inferred from the DNA sequence of -the fda gene is the first primary structure of a Class II aldolase to be -established. There is no immediately apparent sequence homology with -any of the Class I fructose-1,6-bisphosphate aldolases which have been -widely studied. |CITS:[89193446]| - -An fda mutant exhibits a heat-sensitive defect in rRNA transcription that is elicited via altered abundance of ppGpp and of initiating NTPs |CITS: [14526031]|. - -Fda has similarity to an <i>Edwardsiella ictaluri</i> protein that provokes an immune response in catfish |CITS: [12542086]|. - - fructose bisphosphate aldolase monomer - - - - - - - - - - - - - - - - B2097 - DhnA - FbaB - MIARKRRARTIHSRYPIGIYGSIVMTDIAQLLGKDADNLLQHRCMTIPSDQLYLPGHDYVDRVMIDNNRPPAVLRNMQTLYNTGRLAGTGYLSILPVDQGVEHSAGASFAANPLYFDPKNIVELAIEAGCNCVASTYGVLASVSRRYAHRIPFLVKLNHNETLSYPNTYDQTLYASVEQAFNMGAVAVGATIYFGSEESRRQIEEISAAFERAHELGMVTVLWAYLRNSAFKKDGVDYHVSADLTGQANHLAATIGADIVKQKMAENNGGYKAINYGYTDDRVYSKLTSENPIDLVRYQLANCYMGRAGLINSGGAAGGETDLSDAVRTAVINKRAGGMGLILGRKAFKKSMADGVKLINAVQDVYLDSKITIA - fructose bisphosphate aldolase monomer - - - - - - - - - - - - - - B4025 - MKNINPTQTAAWQALQKHFDEMKDVTIADLFAKDGDRFSKFSATFDDQMLVDYSKNRITEETLAKLQDLAKECDLAGAIKSMFSGEKINRTENRAVLHVALRNRSNTPILVDGKDVMPEVNAVLEKMKTFSEAIISGEWKGYTGKAITDVVNIGIGGSDLGPYMVTEALRPYKNHLNMHFVSNVDGTHIAEVLKKVNPETTLFLVASKTFTTQETMTNAHSARDWFLKAAGDEKHVAKHFAALSTNAKAVGEFGIDTANMFEFWDWVGGRYSLWSAIGLSIVLSIGFDNFVELLSGAHAMDKHFSTTPAEKNLPVLLALIGIWYNNFFGAETEAILPYDQYMHRFAAYFQQGNMESNGKYVDRNGNVVDYQTGPIIWGEPGTNGQHAFYQLIHQGTKMVPCDFIAPAITHNPLSDHHQKLLSNFFAQTEALAFGKSREVVEQEYRDQGKDPATLDYVVPFKVFEGNRPTNSILLREITPFSLGALIALYEHKIFTQGVILNIFTFDQWGVELGKQLANRILPELKDDKEISSHDSSTNGLINRYKAWRG - PGLUCISOM - Pgi - phosphoglucose isomerase is found primarily in the cytoplasm - - - - - - - - - - - - - - - 6-phosphofructokinase-1 monomer - B3916 - MIKKIGVLTSGGDAPGMNAAIRGVVRSALTEGLEVMGIYDGYLGLYEDRMVQLDRYSVSDMINRGGTFLGSARFPEFRDENIRAVAIENLKKRGIDALVVIGGDGSYMGAMRLTEMGFPCIGLPGTIDNDIKGTDYTIGFFTALSTVVEAIDRLRDTSSSHQRISVVEVMGRYCGDLTLAAAIAGGCEFVVVPEVEFSREDLVNEIKAGIAKGKKHAIVAITEHMCDVDELAHFIEKETGRETRATVLGHIQRGGSPVPYDRILASRMGAYAIDLLLAGYGGRCVGIQNEQLVHHDIIDAIENMKRPFKGDWLDCAKKLY - PfkA - - - - - - - - - - - - - - - - B3612 - GpmC - GpmI - GpmM - MLVSKKPMVLVILDGYGYREEQQDNAIFSAKTPVMDALWANRPHTLIDASGLEVGLPDRQMGNSEVGHVNLGAGRIVYQDLTRLDVEIKDRAFFANPVLTGAVDKAKNAGKAVHIMGLLSAGGVHSHEDHIMAMVELAAERGAEKIYLHAFLDGRDTPPRSAESSLKKFEEKFAALGKGRVASIIGRYYAMDRDNRWDRVEKAYDLLTLAQGEFQADTAVAGLQAAYARDENDEFVKATVIRAEGQPDAAMEDGDALIFMNFRADRAREITRAFVNADFDGFARKKVVNVDFVMLTEYAADIKTAVAYPPASLVNTFGEWMAKNDKTQLRISETEKYAHVTFFFNGGVEESFKGEDRILINSPKVATYDLQPEMSSAELTEKLVAAIKSGKYDTIICNYPNGDMVGHTGVMEAAVKAVEALDHCVEEVAKAVESVGGQLLITADHGNAEQMRDPATGQAHTAHTNLPVPLIYVGDKNVKAVEGGKLSDIAPTMLSLMGMEIPQEMTGKPLFIVE - PGMI-MONOMER - PgmI - YibO - - - - - - - - - - - - - - B0755 - Gpm - GpmA - GpmA - MAVTKLVLVRHGESQWNKENRFTGWYDVDLSEKGVSEAKAAGKLLKEEGYSFDFAYTSVLKRAIHTLWNVLDELDQAWLPVEKSWKLNERHYGALQGLNKAETAEKYGDEQVKQWRRGFAVTPPELTKDDERYPGHDPRYAKLSEKELPLTESLALTIDRVIPYWNETILPRMKSGERVIIAAHGNSLRALVKYLDNMSEEEILELNIPTGVPLVYEFDENFKPLKRYYLGNADEIAAKAAAVANQGKAK - Pgm - PgmA - Regulation has been described |CITS: [11101675]|. Transcription is regulated by Fur |CITS: [11101675]|. - - - - - - - - - - - - - - B2779 - Eno - Eno - MSKIVKIIGREIIDSRGNPTVEAEVHLEGGFVGMAAAPSGASTGSREALELRDGDKSRFLGKGVTKAVAAVNGPIAQALIGKDAKDQAGIDKIMIDLDGTENKSKFGANAILAVSLANAKAAAAAKGMPLYEHIAELNGTPGKYSMPVPMMNIINGGEHADNNVDIQEFMIQPVGAKTVKEAIRMGSEVFHHLAKVLKAKGMNTAVGDEGGYAPNLGSNAEALAVIAEAVKAAGYELGKDITLAMDCAASEFYKDGKYVLAGEGNKAFTSEEFTHFLEELTKQYPIVSIEDGLDESDWDGFAYQTKVLGDKIQLVGDDLFVTNTKILKEGIEKGIANSILIKFNQIGSLTETLAAIKMAKDAGYTAVISHRSGETEDATIADLAVGTAAGQIKTGSMSRSDRVAKYNQLIRIEEALGEKAPYNGRKEIKGQA - - - - - - - - - - - - - - - 1988 - 2975709 - Crystal structure of the complex of phosphofructokinase from Escherichia coli with its reaction products. - Evans PR - J Mol Biol 1988;204(4);973-94 - PubMed - Shirakihara Y - - - - - - - - - 1990 - 2140983 - Eur J Biochem 1990;189(3);487-92 - Garel JR - PubMed - Role of the C-terminal region in the allosteric properties of Escherichia coli phosphofructokinase-1. - Serre MC - - - - - - - - - 1832014 - 1991 - Berger SA - Biochemistry 1991;30(34);8477-80 - Evans PR - PubMed - Steady-state fluorescence of Escherichia coli phosphofructokinase reveals a regulatory role for ATP. - - - - - - - - - Biochemistry - Stryer L - WH Freeman and Co., 3rd edition, New York, 1988 - - - - - - - - - 153704 - 1979 - Adv Enzymol Relat Areas Mol Biol 1979;48;193-244 - Phosphofructokinase. - PubMed - Uyeda K - - - - - - - - - 1997 - 9260967 - Boschi-Muller S - Branlant G - Characterization of Escherichia coli strains with gapA and gapB genes deleted. - J Bacteriol 1997;179(16);5218-21 - PubMed - Seta FD - Vignais ML - - - - - - - - - 1985 - 2990926 - Branlant C - Branlant G - Eur J Biochem 1985;150(1);61-6 - Nucleotide sequence of the Escherichia coli gap gene. Different evolutionary behavior of the NAD+-binding domain and of the catalytic domain of D-glyceraldehyde-3-phosphate dehydrogenase. - PubMed - - - - - - - - - 1998 - 9696782 - Involvement of the gapA- and epd (gapB)-encoded dehydrogenases in pyridoxal 5'-phosphate coenzyme biosynthesis in Escherichia coli K-12. - J Bacteriol 1998;180(16);4294-9 - Man TK - PubMed - Winkler ME - Yang Y - Zhao G - - - - - - - - - 1990 - 2124629 - A naturally occurring horizontal gene transfer from a eukaryote to a prokaryote. - Alberro MR - Anderson KL - Doolittle RF - Feng DF - J Mol Evol 1990;31(5);383-8 - PubMed - - - - - - - - - Oxidation-Reduction, Part C - The Enzymes, Vol.XIII Academic Press, New York 1976;3rd Edition - - - - - - - - - 1995 - 7751290 - Bharani N - Biochemical characterization of gapB-encoded erythrose 4-phosphate dehydrogenase of Escherichia coli K-12 and its possible role in pyridoxal 5'-phosphate biosynthesis. - J Bacteriol 1995;177(10);2804-12 - Pease AJ - PubMed - Winkler ME - Zhao G - - - - - - - - - 1984 - 6235149 - Daldal F - Gene 1984;28(3);337-42 - Nucleotide sequence of gene pfkB encoding the minor phosphofructokinase of Escherichia coli K-12. - PubMed - - - - - - - - - 1981 - 6456900 - Buc H - Eur J Biochem 1981;117(3);569-74 - Kotlarz D - PubMed - Regulatory properties of phosphofructokinase 2 from Escherichia coli. - - - - - - - - - 1985 - 3158524 - Eur J Biochem 1985;149(2);363-73 - Evans PR - Hellinga HW - Nucleotide sequence and high-level expression of the major Escherichia coli phosphofructokinase. - PubMed - - - - - - - - - 149128 - 1978 - Babul J - J Biol Chem 1978;253(12);4350-5 - Phosphofructokinases from Escherichia coli. Purification and characterization of the nonallosteric isozyme. - PubMed - - - - - - - - - 1973 - 4198624 - Biochem J 1973;131(4);833-41 - Perham RN - PubMed - Purification and characterization of two fructose diphosphate aldolases from Escherichia coli (Crookes' strain). - Stribling D - - - - - - - - - 1989 - 2649077 - Alefounder PR - Baldwin SA - Biochem J 1989;257(2);529-34 - Cloning, sequence analysis and over-expression of the gene for the class II fructose 1,6-bisphosphate aldolase of Escherichia coli. - Perham RN - PubMed - Short NJ - - - - - - - - - 1978 - 417719 - Baldwin SA - Biochem J 1978;169(3);633-41 - Perham RN - PubMed - Purification and characterization of the class-II D-fructose 1,6-bisphosphate aldolase from Escherichia coli (Crookes' strain). - Stribling D - - - - - - - - - 1989 - 2549364 - Froman BE - Gottlieb LD - Isolation and characterization of the phosphoglucose isomerase gene from Escherichia coli. - Mol Gen Genet 1989;217(1);126-31 - PubMed - Tait RC - - - - - - - - - 1998 - 9531482 - Ashcroft AE - Berry A - Biochem J 1998;331 ( Pt 2);437-45 - Howlett GJ - PubMed - The dhnA gene of Escherichia coli encodes a class I fructose bisphosphate aldolase. - Thomson GJ - - - - - - - - - 1989 - 2531001 - Biochemistry 1989;28(17);6836-41 - Bras GL - Deville-Bonne D - Garel JR - PubMed - Teschner W - Urea-induced inactivation, dissociation, and unfolding of the allosteric phosphofructokinase from Escherichia coli. - - - - - - - - - BBA 1964;92:378-387 - Endresen A - Intracellular pH effect upon phosphoglucose isomerase in Escherichia coli - Klungsoyr L - - - - - - - - - 1828369 - 1991 - Biochemistry 1991;30(23);5750-4 - Bourgain F - Deville-Bonne D - Garel JR - PubMed - pH dependence of the kinetic properties of allosteric phosphofructokinase from Escherichia coli. - - - - - - - - - 1989 - 2527305 - Crystal structure of unliganded phosphofructokinase from Escherichia coli. - Evans PR - J Mol Biol 1989;207(4);805-21 - PubMed - Rypniewski WR - - - - - - - - - 1531298 - 1992 - A conformational transition involved in antagonistic substrate binding to the allosteric phosphofructokinase from Escherichia coli. - Biochemistry 1992;31(6);1695-700 - Deville-Bonne D - Garel JR - PubMed - - - - - - - - - 1971 - 4942326 - J Biol Chem 1971;246(22);6797-802 - PubMed - Spring TG - The purification and characterization of Escherichia coli enolase. - Wold F - - - - - - - - - ENO-MONOMER - EcoO157Cyc - Ortholog - - - - - - - - - EcoO157Cyc - Ortholog - PYKF-MONOMER - - - - - - - - - EcoO157Cyc - Ortholog - PYKA-MONOMER - - - - - - - - - EcoO157Cyc - GPMB-MONOMER - Ortholog - - - - - - - - - EcoO157Cyc - GAPA-MONOMER - Ortholog - - - - - - - - - EcoO157Cyc - G7E-3-MONOMER - Ortholog - - - - - - - - - EcoO157Cyc - Ortholog - PFKB-MONOMER - - - - - - - - - EcoO157Cyc - Ortholog - TPIA-MONOMER - - - - - - - - - EcoO157Cyc - FBA-MONOMER - Ortholog - - - - - - - - - EcoO157Cyc - Ortholog - Z3260-MONOMER - - - - - - - - - EcoO157Cyc - Ortholog - PGI-MONOMER - - - - - - - - - EcoO157Cyc - Ortholog - PFKA-MONOMER - - - - - - - - - EcoO157Cyc - Ortholog - YIBO-MONOMER - - - - - - - - - F - F- - fluoride - fluoride ion - - - - - - - - - 39.098 - K+ - potassium ion - - - - - - - - - - 2-oxo-propionic acid - 2-oxopropanoate - 2-oxopropanoic acid - 88.063 - BTS - acetylformic acid - alpha-ketopropionic acid - pyroracemic acid - pyruvate - pyruvic acid - - - - - - - - - - - - - 40.08 - Ca2+ - Ca<SUP>++</SUP> - Ca<SUP>+2</SUP> - calcium ion - - - - - - - - - - 867.608 - suc-co-A - suc-coa - succ-CoA - succ-S-CoA - succ-S-coenzyme-A - succ-coenzyme-A - succinyl-CoA - succinyl-S-CoA - succinyl-S-coenzyme-A - succinylcoenzyme-A - - - - - - - - - - - 347.224 - A - AMP - adenosine-5'-phosphate - adenosine-monophosphate - adenosine-phosphate - adenylate - adenylic acid - - - - - - - - - - - vanadate - - - - - - - - - 94.971 - HPO<SUB>4</SUB><SUP>2-</SUP> - PO<SUB>4</SUB><SUP>3-</SUP> - Pi - inorganic phosphate - orthophosphate - phosphate - phosphate-inorganic - - - - - - - - - - - 665.446 - DPNH - NAD-reduced - NADH - NADH+H+ - NADH2 - NADH<sub>2</sub> - dihydrodiphosphopyridine nucleotide - dihydronicotinamide adenine dinucleotide - diphosphopyridine nucleotide reduced - nicotinamide adenine dinucleotide reduced - - - - - - - - - - 170.058 - 3-phosphoglyceraldehyde - D-glyceraldehyde-3-P - D-glyceraldehyde-3-phosphate - gap - glyceraldehyde-3-P - glyceraldehyde-3-phosphate - glyceraldehyde-P - glyceraldehyde-phosphate - - - - - - - - - - - 663.43 - DPN - DPN+ - DPN-ox - NAD - NAD+ - NAD-ox - NAD-oxidized - coenzyme I - diphosphopyridine nucleotide - diphosphopyridine nucleotide oxidized - nicotinamide adenine dinucleotide - nicotinamide adenine dinucleotide oxidized - - - - - - - - - - - 427.203 - ADP - adenosine 5'-pyrophosphate - adenosine pyrophosphate - adenosine-5'-diphosphate - adenosine-5-diphosphate - adenosine-diphosphate - - - - - - - - - - - 138.919 - AsO<SUB>4</SUB><SUP>3-</SUP> - arsenate - inorganic arsenate - orthoarsenate - - - - - - - - - - 170.058 - DHAP - di-OH-acetone-P - dihydroxy-acetone-phosphate - dihydroxyacetone 3-phosphate - dihydroxyacetone-P - dihydroxyacetone-phosphate - glycerone-phosphate - - - - - - - - - - - 260.137 - A-D-fructose-6-P - D-fructose-6-P - D-fructose-6-phosphate - fru-6-P - fruc6p - fructose-6-P - fructose-6-phosphate - fructose-6P - - - - - - - - - - - 443.203 - GDP - guanosine-5'-diphosphate - guanosine-diphosphate - ppG - - - - - - - - - - - 192.125 - 2-hydroxy-1,2,3-propanetricarboxylic acid - cit - citr - citrate - citric acid - - - - - - - - - - - &alpha;-D-glucose-6-P - &alpha;-D-glucose-6-phosphate - 260.137 - D-glucose-6-P - D-glucose-6-phosphate - glucose-6-P - glucose-6-phosphate - - - - - - - - - - - &alpha;-glycerophosphate - 172.074 - D-glycerol-3-phosphate - glycerol-3-P - glycerol-3-phosphate - sn-glycerol-3-phosphate - - - - - - - - - - - 1.008 - H - H+ - hydrogen ion - proton - - - - - - - - - - &alpha;-D-fructose-1,6-diphosphate - 340.117 - D-fructose-1,6-bisphosphate - D-fructose-1,6-diphosphate - fructose-1,6-bisphosphate - fructose-1,6-diphosphate - - - - - - - - - - - EDTA - - - - - - - - - BOROHYDRIDE - - - - - - - - - 507.183 - ATP - adenosine-5'-triphosphate - adenosine-triphosphate - adenylpyrophosphate - - - - - - - - - - - 1,3-biphosphoglycerate - 1,3-bis-phosphoglycerate - 1,3-diphosphateglycerate - 1,3-diphosphoglycerate - 13-dpg - 266.038 - 3-P-glyceroyl-P - 3-phospho-D-glyceroyl-phosphate - 3-phosphoglyceroyl-P - 3-phosphoglyceroyl-phosphate - P-glyceroyl-P - dpg - glycerate 1,3-biphosphate - glycerate 1,3-diphosphate - phosphoglyceroyl-P - - - - - - - - - - - 186.058 - 3-P-D-glycerate - 3-P-glycerate - 3-pg - 3-phospho-(R)-glycerate - 3-phospho-D-glycerate - 3-phospho-glyceric acid - 3-phosphoglycerate - D-Glycerate 3-phosphate - g3p - glycerate 3-phosphate - glycerate-3-P - - - - - - - - - - - 24.305 - Mg2+ - Mg<SUP>++</SUP> - Mg<SUP>+2</SUP> - magnesium ion - - - - - - - - - - 186.058 - 2-P-D-glycerate - 2-P-glycerate - 2-pg - 2-phospho-D-glycerate - 2-phosphoglycerate - 2-phosphoglyceric acid - D-Glycerate 2-phosphate - glycerate 2-phosphate - - - - - - - - - - - Mn2+ - Mn<SUP>++</SUP> - Mn<SUP>+2</SUP> - manganese ion - - - - - - - - - 168.043 - P-enol-pyr - P-enol-pyruvate - PEP - phosphoenolpyruvate - - - - - - - - - - - - 18.015 - H20 - H2O - hydrogen oxide - water - - - - - - - - - - - P08324 - SWISS-MODEL - - - - - - - - - PIR - b2779 - - - - - - - - - NP_417259 - RefSeq - - - - - - - - - UMBBD - c0159 - - - - - - - - - 127-17-3 - CAS - - - - - - - - - LIGAND - c00022 - - - - - - - - - PIR - b1676 - - - - - - - - - P14178 - SWISS-PROT - - - - - - - - - 1E0T - PDB - - - - - - - - - NP_416191 - RefSeq - - - - - - - - - P14178 - SWISS-MODEL - - - - - - - - - 1E0U - PDB - - - - - - - - - 1PKY - PDB - - - - - - - - - NP_416368 - RefSeq - - - - - - - - - P21599 - SWISS-PROT - - - - - - - - - PIR - b1854 - - - - - - - - - P21599 - SWISS-MODEL - - - - - - - - - 604-98-8 - CAS - - - - - - - - - 61-19-8 - CAS - - - - - - - - - PIR - b4395 - - - - - - - - - P36942 - SWISS-PROT - - - - - - - - - NP_418812 - RefSeq - - - - - - - - - P36942 - SWISS-MODEL - - - - - - - - - 14265-44-2 - CAS - - - - - - - - - GO - GO:0005737 - - - - - - - - - 142-10-9 - CAS - - - - - - - - - 53-84-9 - CAS - - - - - - - - - NP_416293 - RefSeq - - - - - - - - - P06977 - SWISS-MODEL - - - - - - - - - 1GAD - PDB - - - - - - - - - PIR - b1779 - - - - - - - - - 1GAE - PDB - - - - - - - - - P06977 - SWISS-PROT - - - - - - - - - 58-64-0 - CAS - - - - - - - - - P11665 - SWISS-PROT - - - - - - - - - PIR - b2926 - - - - - - - - - NP_417401 - RefSeq - - - - - - - - - P11665 - SWISS-MODEL - - - - - - - - - NP_416237 - RefSeq - - - - - - - - - P06999 - SWISS-PROT - - - - - - - - - PIR - b1723 - - - - - - - - - 56-73-5 - CAS - - - - - - - - - 57-04-5 - CAS - - - - - - - - - 146-91-8 - CAS - - - - - - - - - NP_417400 - RefSeq - - - - - - - - - 1DOS - PDB - - - - - - - - - 77-92-9 - CAS - - - - - - - - - 643-13-0 - CAS - - - - - - - - - 1TMH - PDB - - - - - - - - - PIR - b3919 - - - - - - - - - 1TRE - PDB - - - - - - - - - P04790 - SWISS-PROT - - - - - - - - - NP_418354 - RefSeq - - - - - - - - - P04790 - SWISS-MODEL - - - - - - - - - 1ZEN - PDB - - - - - - - - - 57-03-4 - CAS - - - - - - - - - P11537 - SWISS-PROT - - - - - - - - - PIR - b4025 - - - - - - - - - P11604 - SWISS-PROT - - - - - - - - - PIR - b2925 - - - - - - - - - NP_416600 - RefSeq - - - - - - - - - P71295 - SWISS-PROT - - - - - - - - - PIR - b2097 - - - - - - - - - NP_418449 - RefSeq - - - - - - - - - 488-69-7 - CAS - - - - - - - - - 56-65-5 - CAS - - - - - - - - - GO - GO:0008372 - - - - - - - - - 83333 - Escherichia coli K-12 - taxon - - - - - - - - - P06998 - SWISS-PROT - - - - - - - - - 2PFK - PDB - - - - - - - - - NP_418351 - RefSeq - - - - - - - - - PIR - b3916 - - - - - - - - - P06998 - SWISS-MODEL - - - - - - - - - 1981-49-3 - CAS - - - - - - - - - 820-11-1 - CAS - - - - - - - - - 2553-59-5 - CAS - - - - - - - - - P37689 - SWISS-PROT - - - - - - - - - PIR - b3612 - - - - - - - - - NP_418069 - RefSeq - - - - - - - - - P31217 - SWISS-PROT - - - - - - - - - P31217 - SWISS-MODEL - - - - - - - - - PIR - b0755 - - - - - - - - - NP_415276 - RefSeq - - - - - - - - - LIGAND - c00074 - - - - - - - - - 73-89-2 - CAS - - - - - - - - - 7732-18-5 - CAS - - - - - - - - - P08324 - SWISS-PROT - - - - - - - diff --git a/KGs/Carcinogenesis/carcinogenesis.owl.link b/KGs/Carcinogenesis/carcinogenesis.owl.link deleted file mode 100644 index 458f49b7..00000000 --- a/KGs/Carcinogenesis/carcinogenesis.owl.link +++ /dev/null @@ -1,5 +0,0 @@ -#% GitExt 0.1 -path:KGs/Carcinogenesis/carcinogenesis.owl -oid:4afe107f274f0c8054ac22dd5b9a40abfe655a39 -sha256sum:f8a59974ce36c60c69a615a1c6f950648bb1ba2f945cf67099a8de83847b3128 -size:10049853 diff --git a/KGs/Family/family-benchmark_rich_background.owl b/KGs/Family/family-benchmark_rich_background.owl deleted file mode 100644 index 8fc9035f..00000000 --- a/KGs/Family/family-benchmark_rich_background.owl +++ /dev/null @@ -1,3419 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/KGs/Lymphography/lymphography.owl b/KGs/Lymphography/lymphography.owl deleted file mode 100644 index 25e97e39..00000000 --- a/KGs/Lymphography/lymphography.owl +++ /dev/null @@ -1,3363 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/KGs/Mutagenesis/mutagenesis.owl.link b/KGs/Mutagenesis/mutagenesis.owl.link deleted file mode 100644 index 5102547c..00000000 --- a/KGs/Mutagenesis/mutagenesis.owl.link +++ /dev/null @@ -1,5 +0,0 @@ -#% GitExt 0.1 -path:KGs/Mutagenesis/mutagenesis.owl -oid:ad6ae560bee250bd9ce535695d7ee1a130ee97d8 -sha256sum:3bfdd5c35e89c8cb337f9ee8aed2e4cee40644586b287aa0d785261b716ab916 -size:6180787 diff --git a/KGs/Nctrer/nctrer.owl.link b/KGs/Nctrer/nctrer.owl.link deleted file mode 100644 index fd99197b..00000000 --- a/KGs/Nctrer/nctrer.owl.link +++ /dev/null @@ -1,5 +0,0 @@ -#% GitExt 0.1 -path:KGs/Nctrer/nctrer.owl -oid:fe6a53a2838078c424cdb7ffdf85bd7adcd12fcb -sha256sum:7c7dd42062510035f09be1892be4f5923426aba17f7129f755287d962ea346ad -size:25184914 diff --git a/KGs/Suramin/dataset.ttl b/KGs/Suramin/dataset.ttl deleted file mode 100644 index 2afff92d..00000000 --- a/KGs/Suramin/dataset.ttl +++ /dev/null @@ -1,32 +0,0 @@ -@prefix : . -@prefix void: . -@prefix owl: . -@prefix xsd: . -@prefix dcterms: . -@prefix dcat: . -@prefix mexc: . -@prefix sbo: . - -:suramin_owl - a - void:Dataset , - mexc:Dataset , - [ - a owl:Restriction ; - owl:onProperty sbo:expressedInKRLanguage ; - owl:someValuesFrom sbo:OWL - ] ; - dcterms:title "Suramin" ; - dcterms:description "Dataset for finding a predictive description of suramin analogues for cancer treatment" ; - dcterms:source ; - dcterms:issued "2016-04-30"^^xsd:date ; - dcterms:subject ; - dcterms:subject ; - dcterms:subject ; - dcterms:subject ; - dcterms:subject ; - dcterms:subject ; - dcterms:subject ; - dcat:byteSize "1273169"^^xsd:decimal ; - owl:versionInfo "0.1"^^xsd:string . - diff --git a/KGs/dbpedia_2016-10.owl.link b/KGs/dbpedia_2016-10.owl.link deleted file mode 100644 index 9bec97eb..00000000 --- a/KGs/dbpedia_2016-10.owl.link +++ /dev/null @@ -1,5 +0,0 @@ -#% GitExt 0.1 -path:KGs/dbpedia_2016-10.owl -oid:d1e677b3dfc4900ec28f83294217abf71ff89ccd -sha256sum:a0ca30c8f25cf2d2957639dcad4fd1115f37a856d6d542fd50bba3bf9fa6bf9f -size:2451743 diff --git a/KGs/father.owl b/KGs/father.owl deleted file mode 100644 index cfc902f4..00000000 --- a/KGs/father.owl +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/KGs/test_ontology.owl b/KGs/test_ontology.owl deleted file mode 100644 index 8ba8dfc2..00000000 --- a/KGs/test_ontology.owl +++ /dev/null @@ -1,396 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/README.md b/README.md index bbda21a0..914b74ed 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # Ontolearn *Ontolearn* is an open-source software library for explainable structured machine learning in Python. -It contains the following (ready-to-apply) algorithms that learn OWL class expressions from positive and negative examples: +It contains the following (ready-to-apply) algorithms that learn OWL class expressions from positive and negative examples +(aka a learning problem): - **NCES2** → (soon) [Neural Class Expression Synthesis in ALCHIQ(D)](https://papers.dice-research.org/2023/ECML_NCES2/NCES2_public.pdf) - **Drill** → [Deep Reinforcement Learning for Refinement Operators in ALC](https://arxiv.org/pdf/2106.15373.pdf) - **NCES** → [Neural Class Expression Synthesis](https://link.springer.com/chapter/10.1007/978-3-031-33455-9_13) @@ -15,8 +16,10 @@ You can find more details about *Ontolearn* and these algorithms and their varia Quick navigation: - [Installation](#installation) +- [Quick try-out](#quick-try-out) - [Usage](#usage) - [Relevant Papers](#relevant-papers) + ## Installation For detailed instructions please refer to the [installation guide](https://ontolearn-docs-dice-group.netlify.app/usage/installation.html) in the documentation. @@ -27,8 +30,8 @@ before continuing with the installation. To successfully pass all the tests you need to download some external resources in advance -(see [_Download external files_](#download-external-files-link-files)). We recommend to -download them all. Also, install _java_ and _curl_ if you don't have them in your system: +(see [_Download external files_](#download-external-files)). You will need +at least to download the datasets. Also, install _java_ and _curl_ if you don't have them in your system already: ```commandline sudo apt install openjdk-11-jdk @@ -51,12 +54,45 @@ tox # full test with tox ```shell pip install ontolearn # more on https://pypi.org/project/ontolearn/ ``` + +## Quick try-out + +You can execute the script `deploy_cl.py` to deploy the concept learners in a local web server and try +the algorithms using an interactive interface made possible by [Gradio](https://www.gradio.app/). Currently, +you can only deploy the following concept learners: **NCES**, **EvoLearner**, **CELOE** and **OCEL**. + +> **NOTE: In case you don't have a dataset, don't worry, you can use +> the datasets we store in our data server. See _[Download external files](#download-external-files)_.** + +For example the command below will launch an interface using **EvoLearner** as the model on +the **Family** dataset which is a simple dataset with 202 individuals: + +```shell +python deploy_cl.py --model evolearner --path_knowledge_base KGs/Family/family-benchmark_rich_background.owl +``` + +Once you run this command, a local URL where our model is deployed will be provided to you. + + +In the interface you need to enter the positive and the negative examples. For a quick run you can +click on the **Random Examples** checkbox, but you may as well enter some real examples for +the learning problem of **Aunt**, **Brother**, **Cousin**, etc. which +you can find in the folder `examples/synthetic_problems.json`. Just copy and paste the IRIs of +positive and negative examples for a certain learning problem directly +in their respective fields. + +Run the help command to see the description on this script usage: + +```shell +python deploy_cl.py --help +``` + ## Usage In the [examples](https://github.com/dice-group/Ontolearn/tree/develop/examples) folder, you can find examples on how to use the learning algorithms. Also in the [tests](https://github.com/dice-group/Ontolearn/tree/develop/tests) folder we have added some test cases. -For more detailed instructions we suggest to follow the [guides](https://ontolearn-docs-dice-group.netlify.app/usage/03_algorithm.html) in the documentation. +For more detailed instructions we suggest to follow the [guides](https://ontolearn-docs-dice-group.netlify.app/usage/06_concept_learners) in the documentation. Below we give a simple example on using CELOE to learn class expressions for a small dataset. @@ -66,10 +102,11 @@ from ontolearn.model_adapter import ModelAdapter from ontolearn.owlapy.model import OWLNamedIndividual, IRI from ontolearn.owlapy.namespaces import Namespaces from ontolearn.owlapy.render import DLSyntaxObjectRenderer -from examples.experiments_standard import ClosedWorld_ReasonerFactory +from ontolearn.owlapy.owlready2.complex_ce_instances import OWLReasoner_Owlready2_ComplexCEInstances NS = Namespaces('ex', 'http://example.com/father#') +# Defining the learning problem positive_examples = {OWLNamedIndividual(IRI.create(NS, 'stefan')), OWLNamedIndividual(IRI.create(NS, 'markus')), OWLNamedIndividual(IRI.create(NS, 'martin'))} @@ -79,16 +116,16 @@ negative_examples = {OWLNamedIndividual(IRI.create(NS, 'heinz')), # Only the class of the learning algorithm is specified model = ModelAdapter(learner_type=CELOE, - reasoner_factory=ClosedWorld_ReasonerFactory, + reasoner_type=OWLReasoner_Owlready2_ComplexCEInstances, path="KGs/father.owl") model.fit(pos=positive_examples, neg=negative_examples) -dlsr = DLSyntaxObjectRenderer() +renderer = DLSyntaxObjectRenderer() for desc in model.best_hypotheses(1): - print('The result:', dlsr.render(desc.concept), 'has quality', desc.quality) + print('The result:', renderer.render(desc.concept), 'has quality', desc.quality) ``` The goal in this example is to learn a class expression for the concept "father". The output is as follows: @@ -100,32 +137,52 @@ For a quick start on how to use NCES, please refer to the notebook [simple usage ---------------------------------------------------------------------------- -#### Download external files (.link files) +#### Download external files + +Some resources like pre-calculated embeddings or `pre_trained_agents` and datasets (ontologies) +are not included in the repository directly. Use the command line command `wget` + to download them from our data server. -Some resources like pre-calculated embeddings or `pre_trained_agents` -are not included in the Git repository directly. Use the following -command to download them from our data server. +> **NOTE: Before you run this commands in your terminal, make sure you are +in the root directory of the project!** + +To download the datasets: -For Drill: ```shell -./big_gitext/download_big.sh examples/pre_trained_agents.zip.link -./big_gitext/download_big.sh -A # to download them all into examples folder +wget https://files.dice-research.org/projects/Ontolearn/KGs.zip -O ./KGs.zip ``` -For NCES: +Then depending on your operating system, use the appropriate command to unzip the files: + ```shell -./big_gitext/download_nces_data +# Windows +tar -xf KGs.zip + +# or + +# macOS and Linux +unzip KGs.zip ``` -To update or upload resource files, follow the instructions -[here](https://github.com/dice-group/Ontolearn-internal/wiki/Upload-big-data-to-hobbitdata) -and use the following command (only for Drill): +Finally, remove the _.zip_ file: ```shell -./big_gitext/upload_big.sh pre_trained_agents.zip +rm KGs.zip ``` + +And for NCES data: + +```shell +wget https://files.dice-research.org/projects/NCES/NCES_Ontolearn_Data/NCESData.zip -O ./NCESData.zip +unzip NCESData.zip +rm NCESData.zip +``` + + ---------------------------------------------------------------------------- + #### Building (sdist and bdist_wheel) + You can use tox to build sdist and bdist_wheel packages for Ontolearn. - "sdist" is short for "source distribution" and is useful for distribution of packages that will be installed from source. - "bdist_wheel" is short for "built distribution wheel" and is useful for distributing packages that include large amounts of compiled code, as well as for distributing packages that have complex dependencies. @@ -146,15 +203,16 @@ tox -e docs Using the following command will run the linting tool [flake8](https://flake8.pycqa.org/) on the source code. ```shell -tox -e lint -- +flake8 ``` + ---------------------------------------------------------------------------- #### Contribution Feel free to create a pull request! -## Relevant papers +## Relevant Papers - [NCES2](https://papers.dice-research.org/2023/ECML_NCES2/NCES2_public.pdf): Neural Class Expression Synthesis in ALCHIQ(D) - [NCES](https://link.springer.com/chapter/10.1007/978-3-031-33455-9_13): Neural Class Expression Synthesis @@ -207,4 +265,4 @@ address="Cham" } ``` -For any further questions, please contact: ```onto-learn@lists.uni-paderborn.de``` +In case you have any question, please contact: ```onto-learn@lists.uni-paderborn.de``` diff --git a/big_gitext/check_big.sh b/big_gitext/check_big.sh deleted file mode 100755 index e917d2ba..00000000 --- a/big_gitext/check_big.sh +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/bin/env bash - -# This script is used to check resources that should be stored outside -# of Git on an external server - -set -eu - -abs2rel() { perl -l -MFile::Spec -e'print File::Spec->abs2rel(@ARGV)' "$@"; } - -git_dir="$(git rev-parse --git-dir)" -repo_root="$(git rev-parse --show-toplevel)" -repo_root="$(abs2rel "$repo_root")" -if [[ -z "$git_dir" ]] || [[ -z "$repo_root" ]]; then - exit 2 -fi - -if ! command -v sha256sum >/dev/null; then - sha256sum() { - sha256="$(openssl sha256 "$1")" - echo "$(echo "$sha256"|awk -v FS='= ' '{print $NF}')"" ""$1" - } -fi - - -check_file() { - : - if [[ "$1" == *.link ]]; then - f="$1" - else - f="$1".link - fi - o="${f%.link}" - - declare -A link_info - declare -A local_info - - noid= - if [[ -f "$o" ]]; then - noid="$(git hash-object "$o")" - if [[ -z "$noid" ]]; then - echo "Error: git hash-object failed" - exit 2 - fi - local_info["oid"]="$noid" - - sha256="$(sha256sum "$o" | awk '{print $1}')" - if [[ -z "$sha256" ]]; then - echo "Error: sha256sum failed" - exit 2 - fi - local_info["sha256sum"]="$sha256" - - size="$( ( stat --printf="%s" "$o" 2>/dev/null || stat -f%z "$o" 2>/dev/null ) | awk '{print $1}')" - if [[ -z "$size" ]]; then - echo "Error: stat failed" - exit 2 - fi - local_info["size"]="$size" - - nbfpath="$git_dir/big_files/$(echo "$noid"|cut -b1-2)/$(echo "$noid"|cut -b3-4)/" - nlocalf="$nbfpath$noid" - if [[ -f "$nlocalf" ]]; then - local_info["cached"]=1 - else - local_info["cached"]=0 - fi - fi - - if [[ "${local_info["cached"]-0}" -eq 1 ]]; then - _c=C - _m="$_c" - _ct=", but is cached locally" - _mt=", and has a local copy" - else - _c=" " - _m=M - _ct="" - _mt=", and is not checked in" - fi - - if [[ -f "$f" ]]; then - while IFS=: read -r k v; do - if [[ -n "$k" ]]; then - link_info["$k"]="$v" - fi - done <"$f" - else - if [[ -f "$o" ]]; then - if [[ "$short_mode" -eq 1 ]]; then - echo "?$_c ${o#./}" - else - echo " missing .link: \`${o#./}'$_ct" - fi - else - if [[ "$short_mode" -eq 1 ]]; then - echo "!! ${o#./}" - else - echo "Error: \`${o#./}' does not exist" - fi - fi - return - fi - - - hdr="#% GitExt 0.1" - if [[ "${link_info["$hdr"]-x}" != "" ]]; then - if [[ "$short_mode" -eq 1 ]]; then - echo "!$_c ${o#./}" - else - echo "Error: \`${o#./}' has no valid .link file$_ct" - fi - return - fi - - oid="${link_info["oid"]}" - if [[ -z "$oid" ]]; then - if [[ "$short_mode" -eq 1 ]]; then - echo "!$_c ${o#./}" - else - echo "Error: \`${f#./}': oid missing$_ct" - fi - return - fi - - - bfpath="$git_dir/big_files/$(echo "$oid"|cut -b1-2)/$(echo "$oid"|cut -b3-4)/" - localf="$bfpath$oid" - if [[ -f "$localf" ]]; then - link_info["cached"]=1 - _d=U - __dt=" is cached locally" - _dt=", but$__dt" - _dta=", and$__dt" - else - link_info["cached"]=0 - _d=D - _dt="" - _dta="" - fi - - if [[ -f "$o" ]]; then - if [[ "$sha256" == "${link_info["sha256sum"]}" ]]; then - if [[ "$auto_mode" -eq 1 ]]; then - : - else - if [[ "$short_mode" -eq 1 ]]; then - echo ".$_c ${o#./}" - else - echo " unchanged from .link: \`${o#./}'$_dta" - fi - fi - else - # files differ - : - if [[ "$short_mode" -eq 1 ]]; then - echo "M$_m ${o#./}" - else - echo " file differs: \`${o#./}'$_mt" - fi - fi - else - if [[ "$short_mode" -eq 1 ]]; then - echo "$_d ${o#./}" - else - echo " not downloaded: \`${o#./}'$_dt" - fi - fi -} - -short_mode=0 -if [[ "$#" -ge 1 ]]; then - if [[ "$1" == "-s" ]] || [[ "$1" == "--short" ]]; then - short_mode=1 - shift - fi -fi - -auto_mode=0 -if [[ "$#" -eq 0 ]]; then - set -- -A - auto_mode=1 -fi - -if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then - cat < - -Description: - Check files that should not be stored in Git directly. Uses .link - files that contain metadata about the external file to check if - they are changed. - -Options: - -s Show short summary. - -Arguments: - -A Check all files for which a .link file exists - filename(s) Check the specified files only - -Short summary legend: - D not downloaded - U not checked out - . unchanged from .link file - C local copy exists - M differs from .link file - -Example: - ./big_gitext/check_big.sh -s - ./big_gitext/check_big.sh model.pt - -EOT - exit -fi - -if [[ "$1" == "-A" ]] || [[ "$1" == "--all" ]]; then - shopt -s globstar nullglob dotglob - files=("$repo_root/"**/*.link) -else - files=("$@") -fi - -for file in "${files[@]}"; do - check_file "$file" -done - -if [[ "$short_mode" -eq 0 ]]; then - echo "Done." -fi diff --git a/big_gitext/download_big.sh b/big_gitext/download_big.sh deleted file mode 100755 index fdf801ab..00000000 --- a/big_gitext/download_big.sh +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env bash - -# This script is used to download resources from an external server -# Requires curl - -set -eu - -HTTP=https://files.dice-research.org/archive/GitExt/OntoPy/ - -abs2rel() { perl -l -MFile::Spec -e'print File::Spec->abs2rel(@ARGV)' "$@"; } - -git_dir="$(git rev-parse --git-dir 2>/dev/null || :)" -repo_root="$(git rev-parse --show-toplevel 2>/dev/null || :)" -repo_root="$(abs2rel "$repo_root")" -if [[ -z "$git_dir" ]] || [[ -z "$repo_root" ]]; then - echo "No git detected" - repo_root=. -fi - -if ! command -v sha256sum >/dev/null; then - sha256sum() { - sha256="$(openssl sha256 "$1")" - echo "$(echo "$sha256"|awk -v FS='= ' '{print $NF}')"" ""$1" - } -fi - - -download_file() { - : - if [[ "$1" == *.link ]]; then - f="$1" - else - f="$1".link - fi - o="${f%.link}" - - if [[ -f "$f" ]]; then - : - else - echo "Error: \`$f' is not a regular file" - exit 1 - fi - - declare -A link_info - while IFS=: read -r k v; do - if [[ -n "$k" ]]; then - link_info["$k"]="$v" - fi - done <"$f" - - hdr="#% GitExt 0.1" - if [[ "${link_info["$hdr"]-x}" != "" ]]; then - echo "Error: no valid .link file" - exit 2 - fi - - oid="${link_info["oid"]}" - if [[ -z "$oid" ]]; then - echo "Error: oid missing" - exit 2 - fi - - - if [[ -n "$git_dir" ]]; then - bfpath="$git_dir/big_files/$(echo "$oid"|cut -b1-2)/$(echo "$oid"|cut -b3-4)/" - localf="$bfpath$oid" - else - localf= - fi - - filepath="${link_info["path"]}" - - skip=0 - if [[ -f "$o" ]]; then - sha256="$(sha256sum "$o" | awk '{print $1}')" - if [[ "$sha256" == "${link_info["sha256sum"]}" ]]; then - echo "Already exists: $filepath..." - skip=1 - else - mv "$o" "$o"~~ - fi - fi - - backup=0 - if [[ -f "$o"~~ ]]; then - backup=1 - fi - - basename="${filepath##*/}" - dirname="${filepath%"$basename"}" - root="${basename%.*}" - if [[ -z "$root" ]]; then - root="$basename" - ext="" - else - ext="${basename#"$root"}" - fi - - if [[ "$skip" -eq 0 ]]; then - echo "Downloading $filepath..." - if [[ -n "$localf" ]] && [[ -f "$localf" ]]; then - cp "$localf" "$o" - echo '(cached)' - else - curl -f -o "$o".part -C- "$HTTP/$dirname$root/$oid$ext" - mv "$o".part "$o" - fi - - sha256="$(sha256sum "$o" | awk '{print $1}')" - if [[ "$sha256" != "${link_info["sha256sum"]}" ]]; then - echo "Error: sha256sum failed" - exit 2 - fi - fi - - size="$( ( stat --printf="%s" "$o" 2>/dev/null || stat -f%z "$o" 2>/dev/null ) | awk '{print $1}')" - if [[ "$size" -ne "${link_info["size"]}" ]]; then - echo "Error: size mismatch" - exit 2 - fi - - if [[ -n "$localf" ]] && [[ ! -f "$localf" ]]; then - mkdir -p "$bfpath" - cp "$o" "$localf" - fi - - if [[ "$backup" -eq 1 ]]; then - if cmp -s "o" "$o"~~; then - rm "$o"~~ - else - mv "$o"~~ "$o"~ - fi - fi -} - -if [[ "$#" -eq 0 ]]; then - echo "syntax: ./big_gitext/download_big.sh -A|" - exit 1 -fi - -if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then - cat < - -Description: - Download files from an external server that were not stored in Git - directly. Uses .link files that contain metadata about the external - file to find the download information. - - Requires curl. - -Arguments: - -A Download all files for which a .link file exists - filename(s) Download the specified files only - -Example: - ./big_gitext/download_big.sh model.pt - -EOT - exit -fi - -if [[ "$1" == "-A" ]] || [[ "$1" == "--all" ]]; then - shopt -s globstar nullglob dotglob - files=("$repo_root/"**/*.link) -else - files=("$@") -fi - -for file in "${files[@]}"; do - download_file "$file" -done -echo "Done." diff --git a/big_gitext/download_nces_data b/big_gitext/download_nces_data deleted file mode 100755 index 4264c554..00000000 --- a/big_gitext/download_nces_data +++ /dev/null @@ -1,3 +0,0 @@ -! wget https://files.dice-research.org/projects/NCES/NCES_Ontolearn_Data/NCESData.zip -O ./NCESData.zip -! unzip -o ./NCESData.zip -! rm -f ./NCESData.zip diff --git a/big_gitext/upload_big.sh b/big_gitext/upload_big.sh deleted file mode 100755 index b6490298..00000000 --- a/big_gitext/upload_big.sh +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env bash - -# This script is used to upload resources to an external server -# Requires curl - -set -eu - -FTP=ftp://files.dice-research.org/archive/GitExt/OntoPy/ -HTTP=https://files.dice-research.org/archive/GitExt/OntoPy/ - -abs2rel() { perl -l -MFile::Spec -e'print File::Spec->abs2rel(@ARGV)' "$@"; } - -git_dir="$(git rev-parse --git-dir)" -repo_root="$(git rev-parse --show-toplevel)" -repo_root="$(abs2rel "$repo_root")" -if [[ -z "$git_dir" ]] || [[ -z "$repo_root" ]]; then - exit 2 -fi - -find_content_length() { - echo "$1"|awk -v IGNORECASE=1 '{ sub("\r$", "") } $1 == "Content-Length:" { print $2; exit }' -} - -if ! command -v sha256sum >/dev/null; then - sha256sum() { - sha256="$(openssl sha256 "$1")" - echo "$(echo "$sha256"|awk -v FS='= ' '{print $NF}')"" ""$1" - } -fi - - -upload_file() { - if [[ -f "$1" ]]; then - : - else - echo "Error: \`$1' is not a regular file" - exit 1 - fi - - if [[ "$1" == *.link ]]; then - echo "Error: \`$1' is a .link file" - exit 1 - fi - - oid="$(git hash-object "$1")" - if [[ -z "$oid" ]]; then - echo "Error: git hash-object failed" - exit 2 - fi - - sha256="$(sha256sum "$1" | awk '{print $1}')" - if [[ -z "$sha256" ]]; then - echo "Error: sha256sum failed" - exit 2 - fi - - size="$( ( stat --printf="%s" "$1" 2>/dev/null || stat -f%z "$1" 2>/dev/null ) | awk '{print $1}')" - if [[ -z "$size" ]]; then - echo "Error: stat failed" - exit 2 - fi - - - linkfile="$1.link" - : >"$linkfile" - git add -N "$linkfile" - filepath="$(git ls-files --full-name "$linkfile")" - if [[ -z "$filepath" ]]; then - exit 2 - fi - - filepath="${filepath%.link}" - basename="${filepath##*/}" - dirname="${filepath%"$basename"}" - root="${basename%.*}" - if [[ -z "$root" ]]; then - root="$basename" - ext="" - else - ext="${basename#"$root"}" - fi - - - exec 6>&1 >"$linkfile" - - echo "#% GitExt 0.1" - echo "path:$filepath" - echo "oid:$oid" - echo "sha256sum:$sha256" - echo "size:$size" - - exec 1>&6 6>&- - - bfpath="$git_dir/big_files/$(echo "$oid"|cut -b1-2)/$(echo "$oid"|cut -b3-4)/" - mkdir -p "$bfpath" - newf="$bfpath$oid" - echo "Uploading $filepath..." - cp "$1" "$newf" - ret=0 - check_size=-1 - upload_test="$(curl -f -s -I "$HTTP/$dirname$root/$oid$ext")" || ret=$? - if [[ "$ret" -eq 0 ]]; then - check_size="$(find_content_length "$upload_test")" - fi - if [[ "$check_size" -ne "$size" ]]; then - curl -f -n -T "$1" -C- --ssl --ftp-create-dirs "$FTP/$dirname$root/$oid$ext" - else - echo '(cached)' - fi - upload_test="$(curl -f -s -I "$HTTP/$dirname$root/$oid$ext")" || ret=$? - if [[ "$ret" -eq 0 ]]; then - check_size="$(find_content_length "$upload_test")" - fi - if [[ -z "$check_size" ]] || [[ "$check_size" -ne "$size" ]]; then - echo "Upload failed, size mismatch" - exit 2 - fi - - git add "$linkfile" - if ! grep -qFx "$filepath" "$repo_root/.gitignore"; then - echo "$filepath" >>"$repo_root/.gitignore" - git add "$repo_root/.gitignore" - fi -} - -if [[ "$#" -eq 0 ]]; then - echo "syntax: ./big_gitext/upload_big.sh -A|" - exit 1 -fi - -if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then - cat < - -Description: - Upload files to an external server that should not be stored in Git - directly. Creates .link files that contain metadata about the external - file. - - Requires curl. - -Arguments: - -A Upload all files for which a .link file already exists - filename(s) Upload these files and create .link files - -Example: - ./big_gitext/upload_big.sh model.pt - -EOT - exit -fi - -if [[ "$1" == "-A" ]] || [[ "$1" == "--all" ]]; then - shopt -s globstar nullglob dotglob - files=() - for lf in "$repo_root/"**/*.link; do - file="${lf%.link}" - if [[ -e "$file" ]]; then - files+=("$file") - else - echo "Link without file: ${lf#./}" - fi - done -else - files=("$@") -fi - -for file in "${files[@]}"; do - upload_file "$file" -done -echo "Done." diff --git a/big_gitext/verify_big.sh b/big_gitext/verify_big.sh deleted file mode 100755 index 26e3a62a..00000000 --- a/big_gitext/verify_big.sh +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env bash - -# This script is used to quickly verify resources on an external server -# Requires curl - -set -eu - -HTTP=https://files.dice-research.org/archive/GitExt/OntoPy/ - -abs2rel() { perl -l -MFile::Spec -e'print File::Spec->abs2rel(@ARGV)' "$@"; } - -git_dir="$(git rev-parse --git-dir 2>/dev/null || :)" -repo_root="$(git rev-parse --show-toplevel 2>/dev/null || :)" -repo_root="$(abs2rel "$repo_root")" -if [[ -z "$git_dir" ]] || [[ -z "$repo_root" ]]; then - echo "No git detected" - repo_root=. -fi - -find_content_length() { - echo "$1"|awk -v IGNORECASE=1 '{ sub("\r$", "") } $1 == "Content-Length:" { print $2; exit }' -} - - -verify_file() { - if [[ "$1" == *.link ]]; then - f="$1" - else - f="$1".link - fi - - if [[ -f "$f" ]]; then - : - else - echo "Error: \`$f' is not a regular file" - return 1 - fi - - declare -A link_info - while IFS=: read -r k v; do - if [[ -n "$k" ]]; then - link_info["$k"]="$v" - fi - done <"$f" - - hdr="#% GitExt 0.1" - if [[ "${link_info["$hdr"]-x}" != "" ]]; then - echo "Error: no valid .link file" - return 2 - fi - - oid="${link_info["oid"]}" - if [[ -z "$oid" ]]; then - echo "Error: oid missing" - return 2 - fi - - filepath="${link_info["path"]}" - basename="${filepath##*/}" - dirname="${filepath%"$basename"}" - root="${basename%.*}" - if [[ -z "$root" ]]; then - root="$basename" - ext="" - else - ext="${basename#"$root"}" - fi - - size="${link_info["size"]}" - - echo "Verifying $filepath..." - upload_test="$(curl -f -s -I "$HTTP/$dirname$root/$oid$ext")" || ret=$? - if [[ "$ret" -ne 0 ]]; then - echo "Verify failed, file not found" - return 2 - else - check_size="$(find_content_length "$upload_test")" - if [[ -z "$check_size" ]] || [[ "$check_size" -ne "$size" ]]; then - echo "Verify failed, size mismatch" - return 2 - fi - fi - -} - -if [[ "$#" -eq 0 ]]; then - echo "syntax: ./big_gitext/verify_big.sh -A|" - exit 1 -fi - -if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then - cat < - -Description: - Quickly verify if the given files are stored on an external server - by checking if the oid file given in the .link file has the expected - size. Attention: Does not verify the checksum. - - Requires curl. - -Arguments: - -A Verify all .link files - filename(s) Verify the specified .link files only - - -Example: - ./big_gitext/verify_big.sh model.pt - -EOT - exit -fi - -if [[ "$1" == "-A" ]] || [[ "$1" == "--all" ]]; then - shopt -s globstar nullglob dotglob - files=("$repo_root/"**/*.link) -else - files=("$@") -fi - -# check if the server is reachable -echo -n "Testing connection to $HTTP ..." -curl -f -s -S -I -o /dev/null "$HTTP" && echo "ok" || exit $? - -ret=0 -for file in "${files[@]}"; do - verify_file "$file" || ret=$(( ret + $? )) -done -if [[ "$ret" -gt 0 ]]; then - echo "Errors." - exit "$ret" -fi - -echo "Done." diff --git a/deploy_cl.py b/deploy_cl.py index 8c83fa27..85e4ccc1 100644 --- a/deploy_cl.py +++ b/deploy_cl.py @@ -26,17 +26,19 @@ } renderer = DLSyntaxObjectRenderer() + def compute_quality(KB, solution, pos, neg, qulaity_func="F1"): func = metrics[qulaity_func]().score2 instances = set(KB.individuals(solution)) if isinstance(list(pos)[0], str): instances = {ind.get_iri().as_str().split("/")[-1] for ind in instances} - tp=len(pos.intersection(instances)) - fn=len(pos.difference(instances)) - fp=len(neg.intersection(instances)) - tn=len(neg.difference(instances)) + tp = len(pos.intersection(instances)) + fn = len(pos.difference(instances)) + fp = len(neg.intersection(instances)) + tn = len(neg.difference(instances)) return func(tp=tp, fn=fn, fp=fp, tn=tn)[-1] + def setup_prerequisites(individuals, pos_ex, neg_ex, random_ex: bool, size_of_ex): # start_time = time.time() @@ -46,7 +48,7 @@ def setup_prerequisites(individuals, pos_ex, neg_ex, random_ex: bool, size_of_ex if random_ex: typed_pos = set(random.sample(individuals, int(size_of_ex))) remaining = list(set(individuals)-typed_pos) - typed_neg = set(random.sample(remaining, min(len(remaining), int(size_of_ex))))#set(random.sample(individuals, int(size_of_ex))) + typed_neg = set(random.sample(remaining, min(len(remaining), int(size_of_ex)))) pos_str = [pos_ind.get_iri().as_str() for pos_ind in typed_pos] neg_str = [neg_ind.get_iri().as_str() for neg_ind in typed_neg] else: @@ -432,10 +434,10 @@ def launch_nces(args): individuals = list(kb.individuals()) # kb_display_value = args.path_knowledge_base.split("/")[-1] - def predict(positive_examples, negative_examples, random_examples: bool, size_of_examples, quality_func, learner_name, - proj_dim, rnn_n_layers, drop_prob, num_heads, num_seeds, num_inds, ln, learning_rate, decay_rate, - clip_value, batch_size, num_workers, max_length, load_pretrained, sorted_examples, pretrained_model_name - ): + def predict(positive_examples, negative_examples, random_examples: bool, size_of_examples, quality_func, + learner_name, proj_dim, rnn_n_layers, drop_prob, num_heads, num_seeds, num_inds, ln, learning_rate, + decay_rate, clip_value, batch_size, num_workers, max_length, load_pretrained, sorted_examples, + pretrained_model_name): lp, s = setup_prerequisites(individuals, positive_examples, negative_examples, random_examples, size_of_examples) @@ -452,8 +454,9 @@ def predict(positive_examples, negative_examples, random_examples: bool, size_of with torch.no_grad(): hypotheses = model.fit(lp.pos, lp.neg) - report = {'Prediction': renderer.render(hypotheses), f'Quality({quality_func})': compute_quality(kb, hypotheses, lp.pos,\ - lp.neg, quality_func), 'Individuals': kb.individuals_count(hypotheses)} + report = {'Prediction': renderer.render(hypotheses), + f'Quality({quality_func})': compute_quality(kb, hypotheses, lp.pos, lp.neg, quality_func), + 'Individuals': kb.individuals_count(hypotheses)} return s, pd.DataFrame([report]) @@ -648,10 +651,14 @@ def run(args): # type=str, # default='pre_trained_agents/DrillHeuristic_averaging/DrillHeuristic_averaging.pth', # help='*Only for DRILL* Provide a path of .pth file') - - if not os.path.exists("NCESData/"): - print("\nDownloading data") - import subprocess - subprocess.run("./big_gitext/download_nces_data", shell=True) - print("Done!") - run(parser.parse_args()) + + args = parser.parse_args() + + if not os.path.exists("NCESData/") and args.model == "nces": + print("\nWarning! You are trying to deploy NCES without the NCES data!") + print(f"Please download the necessary files first: see ./download_external_resources.sh\n") + elif not os.path.exists("KGs") and "KGs/" in args.path_knowledge_base: + print("\nWarning! There is no 'KGs' folder!") + print(f"Please download the datasets first: see ./download_external_resources.sh\n") + else: + run(args) diff --git a/docs/index.rst b/docs/index.rst index 979c2dbd..6d43e799 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,16 +7,15 @@ Ontolearn is an open-source software library for explainable structured machine :maxdepth: 2 :caption: Contents: - usage/installation - usage/01_knowledge_base - usage/02_learning_problem + usage/01_introduction + usage/02_installation usage/03_ontologies - usage/04_reasoner - usage/05_concept_learners - usage/06_reasoning_details - usage/08_architecture - usage/09_model_adapter - usage/see_examples + usage/04_knowledge_base + usage/05_reasoner + usage/06_concept_learners + usage/07_reasoning_details + usage/08_model_adapter + usage/09_further_resources api diff --git a/docs/usage/01_introduction.md b/docs/usage/01_introduction.md new file mode 100644 index 00000000..5d690aaf --- /dev/null +++ b/docs/usage/01_introduction.md @@ -0,0 +1,45 @@ +# Ontolearn + +**Version:** ontolearn 0.5.4 + +**GitHub repository:** https://github.com/dice-group/Ontolearn + +**Publisher and maintainer:** [DICE](https://dice-research.org/) - data science research group of [Paderborn University](https://www.uni-paderborn.de/en/university). + +**Contact**: [onto-learn@lists.uni-paderborn.de](mailto:onto-learn@lists.uni-paderborn.de) + +-------------------------------------------------------------------------------------------- + +Ontolearn is an open-source software library for explainable structured machine learning in Python. + +For the core module [owlapy](ontolearn.owlapy) Ontolearn is based on [Owlready2](https://owlready2.readthedocs.io/en/latest/index.html), +a package for manipulating OWL 2.0 ontologies in Python. In addition, we have implemented +a higher degree of code for manipulation OWL 2.0 ontologies, in pursuit of making it +easier, more flexible and of course, having this all in Python. This adaptation of +Owlready2 library made it possible to build more complex algorithms. + +Ontolearn started with the goal of using _Explainable Structured Machine Learning_ +in OWL 2.0 ontologies and this +exactly what our library offers. The main contribution are the exclusive concept learning +algorithms that are part of this library. Currently, we have 4 fully functioning algorithms that +learn concept in description logics. Papers can be found [here](09_further_resources.md). + +Ontolearn can do the following: + +- Load/save ontologies in RDF/XML, OWL/XML +- Modify ontologies by adding/removing axioms +- Access individuals/classes/properties of an ontology (and a lot more) +- Define learning problems +- Construct class expressions +- Use concept learning algorithms to classify positive examples in a learning problem +- Reason over an ontology. +- Other convenient functionalities like converting OWL class expressions to SPARQL or DL syntax + +The rest of the content is build as a top-to-bottom guide, but nevertheless self-containing, where +you can learn more in depth about the capabilities of Ontolearn. + +If you want to quickly view the concept learning algorithms in action check +[_Quick try-out_](06_concept_learners.md#quick-try-out). + + + diff --git a/docs/usage/01_knowledge_base.md b/docs/usage/01_knowledge_base.md deleted file mode 100644 index c6125856..00000000 --- a/docs/usage/01_knowledge_base.md +++ /dev/null @@ -1,204 +0,0 @@ -# Knowledge Bases - -To get started with Structured Machine Learning, the first thing -required is an [Ontology](https://www.w3.org/TR/owl2-overview/) with -[Named Individuals](https://www.w3.org/TR/owl-syntax/#Named_Individuals). -In the literature, an Ontology is part of a -Knowledge Base. In Ontolearn we represent a knowledge base -by the class [KnowledgeBase](ontolearn.knowledge_base.KnowledgeBase) which contains two main class attributes, -an ontology represented by the class [OWLOntology](owlapy.model.OWLOntology) and a reasoner represented by the class [OWLReasoner](owlapy.model.OWLReasoner). -It also contains a Hierarchy generator as well as other Ontology-related attributes required for the Structured Machine Learning library. - -An instance of `KnowledgeBase` is required to run a learning -algorithm. - -We will frequently **use a sample ontology** to give examples. You can find in -the `KGs/father.owl` file. Here is a hierarchical diagram that shows the classes and their -relationships: - - Thing - | - Person - / | - Male Female - -It contains only one object property which is _'hasChild'_ and in total there -are six persons (individuals), of which four are male and two are female. - - - ----------------------------------------------------------------------------- - -## Create an instance -There are different ways to initialize an object of type `KnowledgeBase` -because of the optional arguments. Let us show the most basic ones. - -We consider that you have already an OWL ontology (containing *.owl* extension). - -The simplest way is to use the path of your _.owl_ file to initialize it as follows: - -```python -from ontolearn.knowledge_base import KnowledgeBase - -kb = KnowledgeBase(path="file://KGs/father.owl") -``` - -Another way would be to use an instance of `OWLOntology` -and an instance of `OWLReasoner`: - -```python - -# onto: OWLOntology -# reas: OWLReasoner - -kb = KnowledgeBase(ontology= onto, reasoner=reas) -``` -You can read more about `OWLOntology` and `OWLReasoner` [here](03_ontologies.md). - - ----------------------------------------------------------------------------- - -## Ignore concepts -To avoid trivial solutions sometimes you need to ignore specific concepts. - -Suppose that we have the class "Father" for the individuals in -our example ontology `KGs/father.owl`. If we are trying to learn -the concept of a 'Father' then we need to ignore this concept -before fitting a model. -It can be done as follows: - - - -```python -from ontolearn.owlapy.model import OWLClass -from ontolearn.owlapy.model import IRI - -iri = IRI('http://example.com/father#', 'Father') -father_concept = OWLClass(iri) -concepts_to_ignore = {father_concept} # you can add more than 1 - -new_kb = kb.ignore_and_copy(ignored_classes=concepts_to_ignore) -``` -In this example, we have created an instance of [OWLClass](owlapy.model.OWLClass) by using an [IRI](owlapy.model.IRI). -On the other side, an instance of `IRI` is created by passing two parameters which are -the namespace of the ontology and the remainder 'Father'. - ----------------------------------------------------------------------------- - -## Accessing individuals -You may need to work with individuals of a knowledge base. -We cover different ways of accessing them. - -Let us give a simple example of how to get the individuals that -are classified by an [OWLClassExpression](owlapy.model.OWLClassExpression). As a class expression, we will simply use the -concept 'male'. - - -```python -NS = 'http://example.com/father#' -male_concept = OWLClass(IRI(NS,'male')) - -male_individuals = kb.individuals(male_concept) -``` -`male_individuals` will contain all the individuals that are classified as -'male'. -Keep in mind that `OWLClass` inherit from `OWLClassExpression`. - - -If you don't specify a class expression than this method returns all the individuals: - -```python -all_individuals = kb.individuals() -``` - -You can as well get all the individuals using: - -```python -all_individuals_set = kb.all_individuals_set() -``` -The difference is that `individuals()` return type is `Iterable[OWLNamedIndividual]` -and `all_individuals_set()` return type is `frozenset(OWLNamedIndividual)`. - -In case you need your result as frozenset, `individual_set` method is a better option -then the `individuals` method: - -```python -male_individuals_set = kb.individuals_set(male_concept) -``` - -Or you can even combine both methods: - -```python -male_individuals_set = kb.individuals_set(male_individuals) -``` - ----------------------------------------------------------------------------- - -## Evaluate a concept - -`KnowledgeBase` class offers methods to evaluate a concept, but to do that -you will need a **learning problem** for the concept you want to evaluate. -You may need to check the guidelines for [defining the learning problem](02_learning_problem.md) -before continuing. - -We will consider that you already have constructed an -instance of [PosNegLPStandard](ontolearn.learning_problem.PosNegLPStandard) class. To evaluate a concept you will -first need the encoded learning problem. - -```python -# lp: PosNegLPStandard -encoded_lp = kb.encode_learning_problem(lp) -``` -For more details about this method please refer to the API. - -To evaluate a concept you can use the method `evaluate_concept`. To do that -you will need 3 properties: - -1. a concept to evaluate: [OWLClassExpression](owlapy.model.OWLClassExpression) -2. a quality metric: [AbstractScorer](ontolearn.abstracts.AbstractScorer) -3. the encoded learning problem: [EncodedLearningProblem](ontolearn.learning_problem.EncodedPosNegLPStandard) - -Let's suppose that the class expression `(¬female) ⊓ (∃ hasChild.⊤)` -was generated by [CELOE](https://ontolearn-docs-dice-group.netlify.app/usage/03_algorithm.html#) -for the concept of 'Father' and is stored in the variable `hypothesis` (check [_Using Concept Learners_](05_concept_learners.md) and/or [CELOE notebook](celoe_notebook.ipynb) -to learn more about CELOE). -You can evaluate this class expression as follows: - -```python -from ontolearn.metrics import F1 - -evaluated_concept = kb.evaluate_concept(hypothesis, F1(), encoded_lp) -``` -In this example we used F1-score to evaluate the hypothesis, but you can also -use Accuracy by importing it first and then replacing `F1()` with `Accuracy()`. - -You can now: - -- Print the quality: - - ```python - print(evaluated_concept.q) # 1.0 - ``` - -- Print the set of individuals covered by the hypothesis: - - ```python - for ind in evaluated_concept.inds: - print(ind) - - # OWLNamedIndividual(http://example.com/father#markus) - # OWLNamedIndividual(http://example.com/father#martin) - # OWLNamedIndividual(http://example.com/father#stefan) - ``` -- Print the amount of them: - - ```python - print(evaluated_concept.ic) # 3 - ``` - -You can always check all the methods of the [KnowledgeBase](ontolearn.knowledge_base.KnowledgeBase) -class in its class documentation. -Since `KnowlegeBase` inherit from [ConceptGenerator](ontolearn.concept_generator.ConceptGenerator) -you can also make use of some convenient methods that are available there. - -In the next guide we describe how to define a learning problem in Ontolearn. diff --git a/docs/usage/installation.md b/docs/usage/02_installation.md similarity index 70% rename from docs/usage/installation.md rename to docs/usage/02_installation.md index 3735bd6c..afa5ca2e 100644 --- a/docs/usage/installation.md +++ b/docs/usage/02_installation.md @@ -12,7 +12,7 @@ One such system for virtual python environments is We have good experience with it and make use of conda in the [Installation from source](#installation-from-source) step. -## Installation from source +## Installation From Source To download the Ontolearn source code, you will also need to have a copy of the [Git](https://git-scm.com/) version control system. @@ -62,13 +62,7 @@ python -c "import ontolearn" ### Tests -In order to run our test suite, type: - -```shell -tox -``` - -You can also run the tests directly as follows but make sure you have installed +You can run the tests as follows but make sure you have installed the external files using the commands described [here](#download-external-files-link-files) to successfully pass all the tests: ```shell @@ -76,7 +70,7 @@ pytest ``` -## Installation via pip +## Installation via _pip_ Released versions of Ontolearn can also be installed using `pip`, the Package Installer for Python. It comes as part of Python. Please @@ -90,23 +84,52 @@ pip install ontolearn This will download and install the latest release version of Ontolearn and all its dependencies from . -## Download external files (.link files) +## Download External Files + +Some resources like pre-calculated embeddings or `pre_trained_agents` and datasets (ontologies) +are not included in the repository directly. Use the command line command `wget` + to download them from our data server. + +> **NOTE: Before you run this commands in your terminal, make sure you are +in the root directory of the project!** + +To download the datasets: + +```shell +wget https://files.dice-research.org/projects/Ontolearn/KGs.zip -O ./KGs.zip +``` + +Then depending on your operating system, use the appropriate command to unzip the files: + +```shell +# Windows +tar -xf KGs.zip + +# or + +# macOS and Linux +unzip KGs.zip +``` + +Finally, remove the _.zip_ file: + +```shell +rm KGs.zip +``` -Some resources like pre-calculated embeddings or `pre_trained_agents` -are not included in the Git repository directly. Use the following -command to download them from our data server. +And for NCES data: ```shell -./big_gitext/download_big.sh pre_trained_agents.zip.link -./big_gitext/download_big.sh -A # to download them all +wget https://files.dice-research.org/projects/NCES/NCES_Ontolearn_Data/NCESData.zip -O ./NCESData.zip +unzip NCESData.zip +rm NCESData.zip ``` -To update or upload resource files, follow the instructions -[here](https://github.com/dice-group/Ontolearn-internal/wiki/Upload-big-data-to-hobbitdata) -and use the following command. +If you are getting any error check if the following flags can help: ```shell -./big_gitext/upload_big.sh pre_trained_agents.zip +unzip -o NCESData.zip +rm -f NCESData.zip ``` ## Building (sdist and bdist_wheel) @@ -137,12 +160,17 @@ be installed: tox -e docs latexpdf ``` -## Contribution +## Simple Linting + +Using the following command will run the linting tool [flake8](https://flake8.pycqa.org/) on the source code. +```shell +flake8 +``` + +Additionally, you can specify the path where you want to flake8 to run. -Feel free to create a pull request. -## Questions +---------------------------------------------------------------------- -For any further questions, please contact: ```onto-learn@lists.uni-paderborn.de``` -or open an issue on our [GitHub issues -page](https://github.com/dice-group/Ontolearn/issues). +In the next guide, we explore about ontologies in Ontolearn and how you can modify them +using axioms. diff --git a/docs/usage/02_learning_problem.md b/docs/usage/02_learning_problem.md deleted file mode 100644 index 80a834e2..00000000 --- a/docs/usage/02_learning_problem.md +++ /dev/null @@ -1,69 +0,0 @@ - - -# Learning Problem - -The Structured Machine Learning implemented in our Ontolearn library -is working with a type of [supervised -learning](https://en.wikipedia.org/wiki/Supervised_learning). One of -the first things to do after loading the Ontology is thus to define -the positive and negative examples whose description the learning -algorithm should attempt to find. - -### Referencing Named Individuals - -Let's assume we are working with the Ontology `father.owl` that was -loaded in the previous chapter. Our positive examples (individuals to -describe) are stefan, markus, and martin. And our negative examples -(individuals to not describe) are heinz, anna, and michelle. Then we -could write the following Python code: - - - -```python -from ontolearn.owlapy.namespaces import Namespaces -from ontolearn.owlapy.model import OWLNamedIndividual, IRI - -NS = Namespaces('ex', 'http://example.com/father#') - -positive_examples = {OWLNamedIndividual(IRI.create(NS, 'stefan')), - OWLNamedIndividual(IRI.create(NS, 'markus')), - OWLNamedIndividual(IRI.create(NS, 'martin'))} -negative_examples = {OWLNamedIndividual(IRI.create(NS, 'heinz')), - OWLNamedIndividual(IRI.create(NS, 'anna')), - OWLNamedIndividual(IRI.create(NS, 'michelle'))} -``` - -Note that the namespace has to match the Namespace/IRI that is defined -in the Ontology document. - - -### Creating the Learning Problem - -Now the learning problem can be captured in its respective object, the -[positive-negative standard learning -problem](ontolearn.learning_problem.PosNegLPStandard): - - -```python -from ontolearn.learning_problem import PosNegLPStandard - -lp = PosNegLPStandard(pos=positive_examples, neg=negative_examples) -``` - -In the next guide, you can learn more about ontologies in Ontolearn and how you can modify them -using axioms. \ No newline at end of file diff --git a/docs/usage/03_ontologies.md b/docs/usage/03_ontologies.md index 016eb481..91980469 100644 --- a/docs/usage/03_ontologies.md +++ b/docs/usage/03_ontologies.md @@ -1,15 +1,26 @@ # Ontologies +To get started with Structured Machine Learning, the first thing +required is an [Ontology](https://www.w3.org/TR/owl2-overview/) with +[Named Individuals](https://www.w3.org/TR/owl-syntax/#Named_Individuals). +In this guide we show the basics of working with ontologies in Ontolearn. -In this guide, we will explain how to modify or get specific data from an Ontology. There -are some similar functionalities as the `KnowledgeBase` class which we describe here: -[Working with Knowledge Bases](01_knowledge_base.md). +We will frequently **use a sample ontology** to give examples. You can find it in +`KGs/father.owl`. Here is a hierarchical diagram that shows the classes and their +relationships: -## Loading an Ontology -> **Note:** Although you can load an ontology directly, you will still need a `KnowledgeBase` object to run -concept learning algorithms. + Thing + | + Person + / | + Male Female + +It contains only one object property which is _'hasChild'_ and in total there +are six persons (individuals), of which four are male and two are female. -To load an ontology as well as to manage it, you will need an [OWLOntologyManager](owlapy.owlready2.OWLOntologyManager). +## Loading an Ontology + +To load an ontology as well as to manage it, you will need an [OWLOntologyManager](ontolearn.owlapy.owlready2.OWLOntologyManager). To load an ontology, use the following Python code: ```python @@ -24,7 +35,7 @@ First, we import the `IRI` class and a suitable OWLOntologyManager. To load a file from our computer, we have to reference it with an [IRI](https://tools.ietf.org/html/rfc3987). Secondly, we need the Ontology Manager. Currently, Ontolearn contains one such manager: The -[OWLOntologyManager_Owlready2](owlapy.owlready2.OWLOntologyManager_Owlready2). +[OWLOntologyManager_Owlready2](ontolearn.owlapy.owlready2.OWLOntologyManager_Owlready2). Now, we can already inspect the contents of the ontology. For example, to list all individuals: @@ -42,32 +53,31 @@ You can get the object properties in the signature: onto.object_properties_in_signature() ``` -For more methods, refer to the [OWLOntology](owlapy.model.OWLOntology) class documentation. - ----------------------------------------------------------------------------- +For more methods, refer to the [OWLOntology](ontolearn.owlapy.model.OWLOntology) class documentation. ## Modifying an Ontology Axioms in ontology serve as the basis for defining the vocabulary of a domain and for -making statements about the relationships between entities and concepts in that domain. +making statements about the relationships between individuals and concepts in that domain. They provide a formal and precise way to represent knowledge and allow for automated reasoning and inference. Axioms can be **added**, **modified**, or **removed** from an ontology, allowing the ontology to evolve and adapt as new knowledge is gained. In Ontolearn we also have different axioms represented by different classes. You can check all -the axioms classes [here](owlapy.model). The main axioms you may use more frequently are: +the axioms classes [here](ontolearn.owlapy.model). A few important axioms are: -- [OWLDeclarationAxiom](owlapy.model.OWLDeclarationAxiom) -- [OWLObjectPropertyAssertionAxiom](owlapy.model.OWLObjectPropertyAssertionAxiom) -- [OWLDataPropertyAssertionAxiom](owlapy.model.OWLObjectPropertyAssertionAxiom) -- [OWLClassAssertionAxiom](owlapy.model.OWLObjectPropertyAssertionAxiom) +- [OWLDeclarationAxiom](ontolearn.owlapy.model.OWLDeclarationAxiom) +- [OWLObjectPropertyAssertionAxiom](ontolearn.owlapy.model.OWLObjectPropertyAssertionAxiom) +- [OWLDataPropertyAssertionAxiom](ontolearn.owlapy.model.OWLObjectPropertyAssertionAxiom) +- [OWLClassAssertionAxiom](ontolearn.owlapy.model.OWLObjectPropertyAssertionAxiom) +- [OWLSubClassOfAxiom](ontolearn.owlapy.model.OWLSubClassOfAxiom) +- [OWLEquivalentClassesAxiom](ontolearn.owlapy.model.OWLEquivalentClassesAxiom) #### Add a new Class Let's suppose you want to add a new class in our example ontology `KGs/father.owl` -(You can find this ontology inside the project or click [here](01_knowledge_base.md) -to see a description of it). It can be done as follows: +It can be done as follows: @@ -82,21 +92,21 @@ child_class_declaration_axiom = OWLDeclarationAxiom(child_class) manager.add_axiom(onto, child_class_declaration_axiom) ``` In this example, we added the class 'child' to the father.owl ontology. -Firstly we create an instance of [OWLClass](owlapy.model.OWLClass) to represent the concept -of 'child' by using an [IRI](owlapy.model.IRI). +Firstly we create an instance of [OWLClass](ontolearn.owlapy.model.OWLClass) to represent the concept +of 'child' by using an [IRI](ontolearn.owlapy.model.IRI). On the other side, an instance of `IRI` is created by passing two arguments which are the namespace of the ontology and the remainder 'child'. To declare this new class we need an axiom of type `OWLDeclarationAxiom`. We simply pass the `child_class` to create an instance of this axiom. The final step is to add this axiom to the ontology using the -[OWLOntologyManager](owlapy.owlready2.OWLOntologyManager). We use the `add_axiom` method +[OWLOntologyManager](ontolearn.owlapy.owlready2.OWLOntologyManager). We use the `add_axiom` method of the `manager` to add into the ontology `onto` the axiom `child_class_declaration_axiom`. #### Add a new Object Property / Data Property The idea is the same as adding a new class. Instead of `OWLClass`, for object properties, -you can use the class [OWLObjectProperty](owlapy.model.OWLObjectProperty) and for data -properties you can use the class [OWLDataProperty](owlapy.model.OWLDataProperty). +you can use the class [OWLObjectProperty](ontolearn.owlapy.model.OWLObjectProperty) and for data +properties you can use the class [OWLDataProperty](ontolearn.owlapy.model.OWLDataProperty). @@ -115,7 +125,7 @@ hasAge_dp_declaration_axiom = OWLDeclarationAxiom(hasAge_dp) manager.add_axiom(onto, hasAge_dp_declaration_axiom) ``` -See the [API documentation](owlapy.model) for more OWL entities that you can add as a declaration axiom. +See the [API documentation](ontolearn.owlapy.model) for more OWL entities that you can add as a declaration axiom. #### Add an Assertion Axiom @@ -139,7 +149,7 @@ want to assert a class axiom for the individual `heinz`. We have used the class `OWLClassAssertionAxiom` where the first argument is the 'individual' `heinz` and the second argument is the 'class_expression'. As the class expression, we used the previously defined class -`child_Class`. Finally, add the axiom by using `add_axiom` method of the [OWLOntologyManager](owlapy.owlready2.OWLOntologyManager). +`child_Class`. Finally, add the axiom by using `add_axiom` method of the [OWLOntologyManager](ontolearn.owlapy.owlready2.OWLOntologyManager). Let's show one more example using a `OWLDataPropertyAssertionAxiom` to assign the age of 17 to heinz. @@ -156,14 +166,14 @@ dp_assertion_axiom = OWLDataPropertyAssertionAxiom(heinz, hasAge_dp, literal_17) manager.add_axiom(onto, dp_assertion_axiom) ``` -[OWLLiteral](owlapy.model.OWLLiteral) is a class that represents the literal values in +[OWLLiteral](ontolearn.owlapy.model.OWLLiteral) is a class that represents the literal values in Ontolearn. We have stored the integer literal value of '18' in the variable `literal_17`. Then we construct the `OWLDataPropertyAssertionAxiom` by passing as the first argument, the individual `heinz`, as the second argument the data property `hasAge_dp`, and the third argument the literal value `literal_17`. Finally, add it to the ontology by using `add_axiom` method. -Check the [API documentation](owlapy.model) to see all the OWL +Check the [API documentation](ontolearn.owlapy.model) to see all the OWL assertion axioms that you can use. @@ -178,12 +188,11 @@ manager.remove_axiom(onto,dp_assertion_axiom) The first argument is the ontology you want to remove the axiom from and the second argument is the axiom you want to remove. ----------------------------------------------------------------------------- ## Save an Ontology If you modified an ontology, you may want to save it as a new file. To do this -you can use the `save_ontology` method of the [OWLOntologyManager](owlapy.owlready2.OWLOntologyManager). +you can use the `save_ontology` method of the [OWLOntologyManager](ontolearn.owlapy.owlready2.OWLOntologyManager). It requires two arguments, the first is the ontology you want to save and The second is the IRI of the new ontology. @@ -194,11 +203,10 @@ manager.save_ontology(onto, IRI.create('file:/' + 'test' + '.owl')) The above line of code will save the ontology `onto` in the file *test.owl* which will be created in the same directory as the file you are running this code. ----------------------------------------------------------------------------- ## Worlds -Owlready2 stores every triples in a ‘World’ object, and it can handle several Worlds in parallel. +Owlready2 stores every triple in a ‘World’ object, and it can handle several Worlds in parallel. Owlready2 uses an optimized quadstore to store the world. Each world object is stored in a separate quadstore and by default the quadstore is stored in memory, but it can also be stored in an SQLite3 file. The method `save_world()` of the ontology manager does the latter. @@ -208,16 +216,15 @@ By calling the method `load_ontology(iri)` the ontology is loaded to this world. It possible to create several isolated “worlds”, sometimes called “universe of speech”. This makes it possible in particular to load the same ontology several times, independently, that is to say, without -the modifications made on one copy affecting the other copy. In [Detailed reasoner docs](06_reasoning_details.md) -we explain how you can isolate the worlds(together with the ontology) that a reasoner is using. +the modifications made on one copy affecting the other copy. Sometimes the need to [isolate an ontology](07_reasoning_details.md#isolated-world) +arise. What that means is that you can have multiple reference of the same ontology in different +worlds. +------------------------------------------------------------------------------------- -## Attaching a Reasoner +In the next guide we will explore the [KnowledgeBase](ontolearn.knowledge_base.KnowledgeBase) class that is needed to +run a concept learner. -It is important that an ontology also contains a reasoner that is used to inferring knowledge -from the knowledge base, i.e. to perform ontology reasoning. -In the next guide we show how to attach a reason in Ontolearn and describe some -convenient methods that they offer. diff --git a/docs/usage/04_knowledge_base.md b/docs/usage/04_knowledge_base.md new file mode 100644 index 00000000..62d3627f --- /dev/null +++ b/docs/usage/04_knowledge_base.md @@ -0,0 +1,261 @@ +# Knowledge Bases + +In Ontolearn we represent a knowledge base +by the class [KnowledgeBase](ontolearn.knowledge_base.KnowledgeBase) which contains two main class attributes, +an ontology [OWLOntology](ontolearn.owlapy.model.OWLOntology) and a reasoner [OWLReasoner](ontolearn.owlapy.model.OWLReasoner). +It also contains the class and properties hierarchy as well as other +Ontology-related attributes required for the Structured Machine Learning library. + + +## Knowledge Base vs Ontology + +These terms may be used interchangeably sometimes but in Ontolearn they are not the same thing, +although they share a lot of similarities. An ontology in Ontolearn, as we explained in the +[previous guide](03_ontologies.md) is the object where we load the OWL 2.0 ontologies from +a _.owl_ file containing the ontology in an RDF/XML or OWL/XML format. On the other side +a KnowledgeBase is a class which combines an ontology and a reasoner together. Therefore, +differently from the ontology you can use methods that require reasoning. You can check +the methods for each in the links below: + +- [KnowledgeBase](ontolearn.knowledge_base.KnowledgeBase) +- [OWLOntology](ontolearn.owlapy.model.OWLOntology) + +In summary: + +- An instance of `KnowledgeBase` contains an ontology and a reasoner and +is required to run a learning algorithm. + +- The ontology object can load an OWL 2.0 ontology, +be modified using the ontology manager and saved. + +- Although they have some similar functionalities, there are a lot of other distinct +functionalities that each of them has. + + +## Create an Object of KnowledgeBase + +Let us show how you can initialize an object of `KnowledgeBase`. +We consider that you have already an OWL 2.0 ontology (containing *.owl* extension). + +The simplest way is to use the path of your _.owl_ file as follows: + +```python +from ontolearn.knowledge_base import KnowledgeBase + +kb = KnowledgeBase(path="file://KGs/father.owl") +``` + +What happens in the background is that the ontology located in this path will be loaded +in the `OWLOntology` object of `kb` as done [here](03_ontologies.md#loading-an-ontology). + + +## Ignore Concepts + +During concept learning which we describe later, you may need to +avoid trivial solutions from being learned. So in Ontolearn you +have the opportunity to ignore specific concepts. Since we pass a `KnowledgeBase` +object to the concept learner, we set this ignored concept using the method +`ignore_and_copy` of the `KnowledgeBase` class. + +We don't have such concept in our example ontology `KGs/father.owl` but suppose that +there is a class(concept) "Father" that we want to ignore, because we are trying +to learn this a meaningful class expression for 'Father' using other classes(e.g. male, female, ∃ hasChild.⊤... ). +So we need to ignore this concept before fitting a model (model fitting is covered in [concept learning](06_concept_learners.md)). +It can be done as follows: + + + +```python +from ontolearn.owlapy.model import OWLClass +from ontolearn.owlapy.model import IRI + +iri = IRI('http://example.com/father#', 'Father') +father_concept = OWLClass(iri) +concepts_to_ignore = {father_concept} # you can add more than 1 + +new_kb = kb.ignore_and_copy(ignored_classes=concepts_to_ignore) +``` +In this example, we have created an instance of [OWLClass](ontolearn.owlapy.model.OWLClass) by using an [IRI](ontolearn.owlapy.model.IRI). +On the other side, an instance of `IRI` is created by passing two parameters which are +the namespace of the ontology and the remainder 'Father'. + +## Accessing Individuals + +You may need to work with individuals of a knowledge base. +We cover different ways of accessing them. + +Let us give a simple example of how to get the individuals that +are classified by an [OWLClassExpression](ontolearn.owlapy.model.OWLClassExpression). As a class expression, we will simply use the +concept 'male'. + + +```python +NS = 'http://example.com/father#' +male_concept = OWLClass(IRI(NS,'male')) + +male_individuals = kb.individuals(male_concept) +``` +Note that the namespace has to match the Namespace/IRI that is defined +in the Ontology document. + +`male_individuals` will contain all the individuals of type 'male'. +Keep in mind that `OWLClass` inherit from `OWLClassExpression`. Depending on +the reasoner that the `kb` object is using the results may differ slightly but in +case of a small dataset like the one we are using for this example, the results do not change. + + +If you don't give any argument than this method returns all the individuals in the ontology: + +```python +all_individuals = kb.individuals() +``` + +You can as well get all the individuals using: + +```python +all_individuals_set = kb.all_individuals_set() +``` +The difference is that `individuals()` return type is `Iterable[OWLNamedIndividual]` +and `all_individuals_set()` return type is `frozenset(OWLNamedIndividual)`. + +In case you need your result as frozenset, `individual_set` method is a better option +then the `individuals` method: + +```python +male_individuals_set = kb.individuals_set(male_concept) +``` + +Or you can even combine both methods: + +```python +male_individuals_set = kb.individuals_set(male_individuals) +``` + + +## Evaluate a Concept + +When using a concept learner, the generated concepts (class expressions) for a certain learning problem +need to be evaluated to see the performance. +To do that you can use the method `evaluate_concept` of `KnowledgeBase`. It requires the following arguments: + +1. a concept to evaluate: [OWLClassExpression](ontolearn.owlapy.model.OWLClassExpression) +2. a quality metric: [AbstractScorer](ontolearn.abstracts.AbstractScorer) +3. the encoded learning problem: [EncodedLearningProblem](ontolearn.learning_problem.EncodedPosNegLPStandard) + +The evaluation should be done for the learning problem that you used to generate the +concept. The main result of the evaluation is the quality score describing how well the generated +concept is doing on the job of classifying the positive individuals. The concept learners do this +process automatically. + +### Construct a learning problem + +To evaluate a concept you need a learning problem. Firstly, we create two simple sets containing +the positive and negative examples for the concept of 'Father'. Our positive examples +(individuals to describe) are stefan, markus, and martin. And our negative examples +(individuals to not describe) are heinz, anna, and michelle. + + +```python +from ontolearn.owlapy.model import OWLNamedIndividual + +positive_examples = {OWLNamedIndividual(IRI.create(NS, 'stefan')), + OWLNamedIndividual(IRI.create(NS, 'markus')), + OWLNamedIndividual(IRI.create(NS, 'martin'))} + +negative_examples = {OWLNamedIndividual(IRI.create(NS, 'heinz')), + OWLNamedIndividual(IRI.create(NS, 'anna')), + OWLNamedIndividual(IRI.create(NS, 'michelle'))} +``` + +Now the learning problem can be captured in its respective object, the +[positive-negative standard learning problem](ontolearn.learning_problem.PosNegLPStandard) and +encode it using the method `encode_learning_problem` of `KnowledgeBase`: + + +```python +from ontolearn.learning_problem import PosNegLPStandard + +lp = PosNegLPStandard(pos=positive_examples, neg=negative_examples) + +encoded_lp = kb.encode_learning_problem(lp) +``` + +Now that we have an encoded learning problem, we need a concept to evaluate. + +### Construct a concept + +Suppose that the class expression `(¬female) ⊓ (∃ hasChild.⊤)` +was generated by [CELOE](ontolearn.concept_learner.CELOE) +for the concept of 'Father'. We will see how that can happen later +but for now we let's construct this class expression manually: + + +```python +from ontolearn.owlapy.model import OWLObjectProperty, OWLObjectSomeValuesFrom , OWLObjectIntersectionOf + +female = OWLClass(IRI(NS,'female')) +not_female = kb.generator.negation(female) +has_child_property = OWLObjectProperty(IRI(NS, "hasChild")) +thing = OWLClass(IRI('http://www.w3.org/2002/07/owl#', 'Thing')) +exist_has_child_T = OWLObjectSomeValuesFrom(property=has_child_property, filler=thing) + +concept_to_test = OWLObjectIntersectionOf([not_female, exist_has_child_T]) +``` + +`kb` has an instance of [ConceptGenerator](ontolearn.concept_generator.ConceptGenerator) +which we use in this case to create the negated concept `¬female`. The other classes +[OWLObjectProperty](ontolearn.owlapy.model.OWLObjectProperty), +[OWLObjectSomeValuesFrom](ontolearn.owlapy.model.OWLObjectSomeValuesFrom) +and [OWLObjectIntersectionOf](ontolearn.owlapy.model.OWLObjectIntersectionOf) are classes +that represent different kind of axioms in ontolearn and can be found in +[owlapy model](ontolearn.owlapy.model). There are more kind of axioms there which you +can use to construct class expressions like we did in the example above. + +### Evaluation and results + +You can now evaluate the concept you just constructed as follows: + + +```python +from ontolearn.metrics import F1 + +evaluated_concept = kb.evaluate_concept(concept_to_test, F1(), encoded_lp) +``` +In this example we use F1-score to evaluate the concept, but there are more [metrics](ontolearn.metrics) +which you can use including Accuracy, Precision and Recall. + +You can now: + +- Print the quality: + + ```python + print(evaluated_concept.q) # 1.0 + ``` + +- Print the set of individuals covered by the hypothesis: + + ```python + for ind in evaluated_concept.inds: + print(ind) + + # OWLNamedIndividual(http://example.com/father#markus) + # OWLNamedIndividual(http://example.com/father#martin) + # OWLNamedIndividual(http://example.com/father#stefan) + ``` +- Print the amount of them: + + ```python + print(evaluated_concept.ic) # 3 + ``` + +----------------------------------------------------------------------------------------------------- + +See [KnowledgeBase API documentation](ontolearn.knowledge_base.KnowledgeBase) +to check all the methods that this class has to offer. You will find methods to +access the class/property hierarchy, convenient methods that use the reasoner indirectly and +a lot more. + +Speaking of the reasoner, it is important that an ontology +is associated with a reasoner which is used to inferring knowledge +from the ontology, i.e. to perform ontology reasoning. +In the next guide we will see how to use a reasoner in Ontolearn. \ No newline at end of file diff --git a/docs/usage/04_reasoner.md b/docs/usage/04_reasoner.md deleted file mode 100644 index d231784b..00000000 --- a/docs/usage/04_reasoner.md +++ /dev/null @@ -1,209 +0,0 @@ -# Reasoners - -To validate facts about statements in the ontology (and thus -also for the Structured Machine Learning task), the help of a reasoner -component is required. - -In our Ontolearn library, we provide several **reasoners** to choose -from. Currently, there are the following reasoners available for you to choose from: - -- Owlready2 reasoner with support for complex class expression instances: [OWLReasoner_Owlready2_ComplexCEInstances](owlapy.owlready2.complex_ce_instances.OWLReasoner_Owlready2_ComplexCEInstances) -- Fast instance checker: [OWLReasoner_FastInstanceChecker](owlapy.fast_instance_checker.OWLReasoner_FastInstanceChecker) -- Structural Owlready2 reasoner (base reasoner): [OWLReasoner_Owlready2](owlapy.owlready2.OWLReasoner_Owlready2) - ->Both reasoners `OWLReasoner_Owlready2_ComplexCEInstances` and `OWLReasoner_FastInstanceChecker` -> only overrides the functionality of finding instances for complex class expression. -> All other functionalities are redirected to the base class `OWLReasoner_Owlready2`. -> -> There are further differences between the first 2 reasoners mentioned where the most -> significant is that `OWLReasoner_Owlready2_ComplexCEInstances` uses sync_reasoner. You -> can read more about sync reasoner in the [end of the page](#sync-reasoner). - -To load any reasoner, use the following code: - - - -```python -from ontolearn.owlapy.owlready2 import OWLReasoner_Owlready2 -from ontolearn.owlapy.owlready2.complex_ce_instances import OWLReasoner_Owlready2_ComplexCEInstances -from ontolearn.owlapy.fast_instance_checker import OWLReasoner_FastInstanceChecker - -structural_reasoner = OWLReasoner_Owlready2(onto) -complex_reasoner = OWLReasoner_Owlready2_ComplexCEInstances(onto) -fast_instance_checker = OWLReasoner_FastInstanceChecker(onto, structural_reasoner) -``` - -The reasoner takes as its first argument the ontology to load. The -fast instance checker requires a base reasoner to which any reasoning -tasks not covered by the fast instance checking code are deferred to. - ----------------------------------------------------------------------------- - -## Usage of the Reasoner -All the reasoners available in the Ontolearn library inherit from the -class: [OWLReasonerEx](owlapy.ext.OWLReasonerEx). This class provides some -extra convenient methods compared to its base class [OWLReasoner](owlapy.model.OWLReasoner), which is an -abstract class. -Further in this guide, we use -[OWLReasoner_FastInstanceChecker](owlapy.fast_instance_checker.OWLReasoner_FastInstanceChecker) (FIC). -to show the capabilities of a reasoner implemented in Ontolearn. - -To give examples we consider the _father_ dataset. -If you are not already familiar with this small dataset, -you can find an overview of it [here](01_knowledge_base.md). - - -## Class Reasoning - -Using an [OWLOntology](owlapy.model.OWLOntology) you can list all the classes in the signature, -but a reasoner can give you more than that. You can get the subclasses, superclasses or the -equivalent classes of a class in the ontology: - - - -```python -from ontolearn.owlapy.model import OWLClass -from ontolearn.owlapy.model import IRI - -namespace = "http://example.com/father#" -male = OWLClass(IRI(namespace, "male")) - -male_super_classes = fast_instance_checker.super_classes(male) -male_sub_classes = fast_instance_checker.sub_classes(male) -male_equivalent_classes = fast_instance_checker.equivalent_classes(male) -``` - -We define the _male_ class by creating an [OWLClass](owlapy.model.OWLClass) object. The -methods `super_classes` and `sub_classes` have 2 more boolean arguments: `direct` and `only_named`. -If `direct=True` then only the direct classes in the -hierarchy will be returned, else it will return every class in the hierarchy depending -on the method(sub_classes or super_classes). -By default, its value is _False_. -The next argument `only_named` specifies whether you want -to show only named classes or complex classes as well. By default, its value is _True_ which -means that it will return only the named classes. - ->**NOTE**: The extra arguments `direct` and `only_named` are also used in other methods that reason -upon the class, object property, or data property hierarchy. - -You can get all the types of a certain individual using `types` method: - - - -```python -from ontolearn.owlapy.owlready2 import OWLOntologyManager_Owlready2 - -manager = OWLOntologyManager_Owlready2() -onto = manager.load_ontology(IRI.create("KGs/father.owl")) -anna = list( - onto.individuals_in_signature()).pop() # getting the 1st individual in the list of individuals which is 'anna' - -anna_types = fast_instance_checker.types(anna) -``` - -We first create a manager and use that to open the _father_ ontology. -We retrieve _anna_ as the first individual on the list of individuals -of this ontology. You can see more details on ontologies in the [Working with Ontologies](03_ontologies.md) -guide. The `type` method only returns named classes. - - -## Object Properties and Data Properties Reasoning -Ontolearn resoners offers some convenient methods for working with object properties and -data properties. Below we show some of them, but you can always check all the methods in the -[OWLReasoner_FastInstanceChecker](owlapy.fast_instance_checker.OWLReasoner_FastInstanceChecker) -class documentation. - -You can get all the object properties that an individual has by using the -following method: - - -```python -anna = individuals[0] -object_properties = fast_instance_checker.ind_object_properties(anna) -``` -In this example, `object_properties` contains all the object properties -that _anna_ has, which in our case would only be _hasChild_. -Now we can get the individuals of this object property for _anna_. - - -```python -for op in object_properties: - object_properties_values = fast_instance_checker.object_property_values(anna, op) - for individual in object_properties_values: - print(individual) -``` - -In this example we iterated over the `object_properties`, assuming that there -are more than 1, and we use the reasoner -to get the values for each object property `op` of the individual `anna`. The values -are individuals which we store in the variable `object_properties_values` and are -printed in the end. The method `object_property_values` requires as the -first argument, an [OWLNamedIndividual](owlapy.model.OWLNamedIndividual) that is the subject of the object property values and -the second argument an [OWLObjectProperty](owlapy.model.OWLObjectProperty) whose values are to be retrieved for the -specified individual. - -> **NOTE:** You can as well get all the data properties of an individual in the same way by using -`ind_data_properties` instead of `ind_object_properties` and `data_property_values` instead of -`object_property_values`. Keep in mind that `data_property_values` returns literal values -(type of [OWLLiteral](owlapy.model.OWLLiteral)). - -In the same way as with classes, you can also get the sub object properties or equivalent object properties. - - - -```python -from ontolearn.owlapy.model import OWLObjectProperty - -hasChild = OWLObjectProperty(IRI(namespace, "hasChild")) - -equivalent_to_hasChild = fast_instance_checker.equivalent_object_properties(hasChild) -hasChild_sub_properties = fast_instance_checker.sub_object_properties(hasChild) -``` - -In case you want to get the domains and ranges of an object property use the following: - - -```python -hasChild_domains = fast_instance_checker.object_property_domains(hasChild) -hasChild_ranges = fast_instance_checker.object_property_ranges(hasChild) -``` - -> **NOTE:** Again, you can do the same for data properties but instead of the word 'object' in the -> method name you should use 'data'. - - -## Find Instances - -The method `instances` of fast instance checker is a very convenient method. It takes only 1 argument that is basically -a class expression and returns all the individuals belonging to that class expression. In Ontolearn -we have implemented a Python class for each type of class expression. Therefore `instances` -has multiple implementations depending on which type of argument is passed, but that is something for the developers. Below you will find a list of all the supported class expressions for this -method: - -- [OWLClass](owlapy.model.OWLClass) -- [OWLObjectUnionOf](owlapy.model.OWLObjectUnionOf) -- [OWLObjectIntersectionOf](owlapy.model.OWLObjectIntersectionOf) -- [OWLObjectSomeValuesFrom](owlapy.model.OWLObjectSomeValuesFrom) -- [OWLObjectComplementOf](owlapy.model.OWLObjectComplementOf) -- [OWLObjectAllValuesFrom](owlapy.model.OWLObjectAllValuesFrom) -- [OWLObjectOneOf](owlapy.model.OWLObjectOneOf) -- [OWLObjectHasValue](owlapy.model.OWLObjectHasValue) -- [OWLObjectMinCardinality](owlapy.model.OWLObjectMinCardinality) -- [OWLObjectMaxCardinality](owlapy.model.OWLObjectMaxCardinality) -- [OWLObjectExactCardinality](owlapy.model.OWLObjectExactCardinality) -- [OWLDataSomeValuesFrom](owlapy.model.OWLDataSomeValuesFrom) -- [OWLDataAllValuesFrom](owlapy.model.OWLDataAllValuesFrom) -- [OWLDataHasValue](owlapy.model.OWLDataHasValue) - -Let us now show a simple example by finding the instances of the class _male_ and printing them: - - -```python -male_individuals = fast_instance_checker.instances(male) -for ind in male_individuals: - print(ind) -``` - -In the next guide, we show how to use concept learners to learn class expressions in a -knowledge base for a certain learning problem. - diff --git a/docs/usage/05_reasoner.md b/docs/usage/05_reasoner.md new file mode 100644 index 00000000..eeaeef94 --- /dev/null +++ b/docs/usage/05_reasoner.md @@ -0,0 +1,235 @@ +# Reasoners + +To validate facts about statements in the ontology (and thus +also for the Structured Machine Learning task), the help of a reasoner +component is required. + +For this guide we will also consider the 'Father' ontology: + +```python +from ontolearn.owlapy.owlready2 import OWLOntologyManager_Owlready2 + +manager = OWLOntologyManager_Owlready2() +onto = manager.load_ontology(IRI.create("KGs/father.owl")) +``` + +In our Ontolearn library, we provide several **reasoners** to choose +from. Currently, there are the following reasoners available: + +- [**OWLReasoner_Owlready2**](ontolearn.owlapy.owlready2.OWLReasoner_Owlready2) + + Or differently Structural Owlready2 Reasoner, is the base reasoner in Ontolearn. The functionalities + of this reasoner are limited. It does not provide full reasoning in _ALCH_. Furthermore, + it has no support for instances of complex class expressions, which is covered by the + other reasoners (CCEI and FIC). We recommend to use the other reasoners for any reasoning tasks. + + **Initialization:** + + ```python + from ontolearn.owlapy.owlready2 import OWLReasoner_Owlready2 + + structural_reasoner = OWLReasoner_Owlready2(onto) + ``` + + The structural reasoner requires an ontology ([OWLOntology](ontolearn.owlapy.model.OWLOntology)). + There is also the `isolate` argument which isolates the world the reasoner is performing the + reasoning. More on that on _[Reasoning Details](07_reasoning_details.md#isolated-world)_. + + +- [**OWLReasoner_Owlready2_ComplexCEInstances**](ontolearn.owlapy.owlready2.complex_ce_instances.OWLReasoner_Owlready2_ComplexCEInstances) **(CCEI)** + + Can perform full reasoning in _ALCH_ due to the use of HermiT/Pellet and provides support for + complex class expression instances (when using the method `instances`). CCEI is more useful when + your main goal is reasoning over the ontology. + + **Initialization:** + + ```python + from ontolearn.owlapy.owlready2.complex_ce_instances import OWLReasoner_Owlready2_ComplexCEInstances + from ontolearn.owlapy.owlready2 import BaseReasoner_Owlready2 + + ccei_reasoner = OWLReasoner_Owlready2_ComplexCEInstances(onto, BaseReasoner_Owlready2.HERMIT, + infer_property_values = True) + ``` + + CCEI requires an ontology and a base reasoner of type [BaseReasoner_Owlready2](ontolearn.owlapy.owlready2.BaseReasoner_Owlready2) + which is just an enumeration with two possible values: `BaseReasoner_Owlready2.HERMIT` and `BaseReasoner_Owlready2.PELLET`. + You can set the `infer_property_values` argument to `True` if you want the reasoner to infer + property values. `infer_data_property_values` is an additional argument when the base reasoner is set to + `BaseReasoner_Owlready2.PELLET`. + + +- [**OWLReasoner_FastInstanceChecker**](ontolearn.owlapy.fast_instance_checker.OWLReasoner_FastInstanceChecker) **(FIC)** + + FIC also provides support for complex class expression but the rest of the methods are the same as in + the base reasoner. + It has a cache storing system that allows for faster execution of some reasoning functionalities. Due to this + feature, FIC is more appropriate to be used in concept learning. + + **Initialization:** + + ```python + from ontolearn.owlapy.fast_instance_checker import OWLReasoner_FastInstanceChecker + + fic_reasoner = OWLReasoner_FastInstanceChecker(onto, structural_reasoner, property_cache = True, + negation_default = True, sub_properties = False) + ``` + Besides the ontology, FIC requires a base reasoner to delegate any reasoning tasks not covered by it. + This base reasoner + can be any other reasoner in Ontolearn. `property_cache` specifies whether to cache property values. This + requires more memory, but it speeds up the reasoning processes. If `negation_default` argument is set + to `True` the missing facts in the ontology means false. The argument + `sub_properties` is another boolean argument to specify whether you want to take sub properties in consideration + for `instances()` method. + +## Usage of the Reasoner +All the reasoners available in the Ontolearn library inherit from the +class: [OWLReasonerEx](ontolearn.owlapy.ext.OWLReasonerEx). This class provides some +extra convenient methods compared to its base class [OWLReasoner](ontolearn.owlapy.model.OWLReasoner), which is an +abstract class. +Further in this guide, we use +[OWLReasoner_Owlready2_ComplexCEInstances](ontolearn.owlapy.owlready2.complex_ce_instances). +to show the capabilities of a reasoner implemented in Ontolearn. + +To give examples we consider the _father_ dataset. +If you are not already familiar with this small dataset, +you can find an overview of it [here](03_ontologies.md). + + +## Class Reasoning + +Using an [OWLOntology](ontolearn.owlapy.model.OWLOntology) you can list all the classes in the signature, +but a reasoner can give you more than that. You can get the subclasses, superclasses or the +equivalent classes of a class in the ontology: + + + +```python +from ontolearn.owlapy.model import OWLClass +from ontolearn.owlapy.model import IRI + +namespace = "http://example.com/father#" +male = OWLClass(IRI(namespace, "male")) + +male_super_classes = ccei_reasoner.super_classes(male) +male_sub_classes = ccei_reasoner.sub_classes(male) +male_equivalent_classes = ccei_reasoner.equivalent_classes(male) +``` + +We define the _male_ class by creating an [OWLClass](ontolearn.owlapy.model.OWLClass) object. The +methods `super_classes` and `sub_classes` have 2 more boolean arguments: `direct` and `only_named`. +If `direct=True` then only the direct classes in the +hierarchy will be returned, else it will return every class in the hierarchy depending +on the method(sub_classes or super_classes). +By default, its value is _False_. +The next argument `only_named` specifies whether you want +to show only named classes or complex classes as well. By default, its value is _True_ which +means that it will return only the named classes. + +>**NOTE**: The extra arguments `direct` and `only_named` are also used in other methods that reason +upon the class, object property, or data property hierarchy. + +You can get all the types of a certain individual using `types` method: + + + +```python +anna = list( onto.individuals_in_signature()).pop() + +anna_types = ccei_reasoner.types(anna) +``` + +We retrieve _anna_ as the first individual on the list of individuals +of the 'Father' ontology. The `type` method only returns named classes. + + +## Object Properties and Data Properties Reasoning +Ontolearn reasoners offers some convenient methods for working with object properties and +data properties. Below we show some of them, but you can always check all the methods in the +[OWLReasoner_Owlready2_ComplexCEInstances](ontolearn.owlapy.owlready2.complex_ce_instances) +class documentation. + +You can get all the object properties that an individual has by using the +following method: + + +```python +anna = individuals[0] +object_properties = ccei_reasoner.ind_object_properties(anna) +``` +In this example, `object_properties` contains all the object properties +that _anna_ has, which in our case would only be _hasChild_. +Now we can get the individuals of this object property for _anna_. + + +```python +for op in object_properties: + object_properties_values = ccei_reasoner.object_property_values(anna, op) + for individual in object_properties_values: + print(individual) +``` + +In this example we iterated over the `object_properties`, assuming that there +are more than 1, and we use the reasoner +to get the values for each object property `op` of the individual `anna`. The values +are individuals which we store in the variable `object_properties_values` and are +printed in the end. The method `object_property_values` requires as the +first argument, an [OWLNamedIndividual](ontolearn.owlapy.model.OWLNamedIndividual) that is the subject of the object property values and +the second argument an [OWLObjectProperty](ontolearn.owlapy.model.OWLObjectProperty) whose values are to be retrieved for the +specified individual. + +> **NOTE:** You can as well get all the data properties of an individual in the same way by using +`ind_data_properties` instead of `ind_object_properties` and `data_property_values` instead of +`object_property_values`. Keep in mind that `data_property_values` returns literal values +(type of [OWLLiteral](ontolearn.owlapy.model.OWLLiteral)). + +In the same way as with classes, you can also get the sub object properties or equivalent object properties. + + + +```python +from ontolearn.owlapy.model import OWLObjectProperty + +hasChild = OWLObjectProperty(IRI(namespace, "hasChild")) + +equivalent_to_hasChild = ccei_reasoner.equivalent_object_properties(hasChild) +hasChild_sub_properties = ccei_reasoner.sub_object_properties(hasChild) +``` + +In case you want to get the domains and ranges of an object property use the following: + + +```python +hasChild_domains = ccei_reasoner.object_property_domains(hasChild) +hasChild_ranges = ccei_reasoner.object_property_ranges(hasChild) +``` + +> **NOTE:** Again, you can do the same for data properties but instead of the word 'object' in the +> method name you should use 'data'. + + +## Find Instances + +The method `instances` is a very convenient method. It takes only 1 argument that is basically +a class expression and returns all the individuals belonging to that class expression. In Ontolearn +we have implemented a Python class for each type of class expression. +The argument is of type [OWLClassExpression](ontolearn.owlapy.model.OWLClassExpression). + +Let us now show a simple example by finding the instances of the class _male_ and printing them: + + +```python +male_individuals = ccei_reasoner.instances(male) +for ind in male_individuals: + print(ind) +``` + +----------------------------------------------------------------------- + +In this guide we covered the main functionalities of the reasoners in Ontolearn. More +details are provided in _[Reasoning Details](07_reasoning_details.md)_. + +Since we have now covered all the basics, on the next guide +you will see how to use concept learners to learn class expressions in a +knowledge base for a certain learning problem. + diff --git a/docs/usage/05_concept_learners.md b/docs/usage/06_concept_learners.md similarity index 64% rename from docs/usage/05_concept_learners.md rename to docs/usage/06_concept_learners.md index 53e8e74b..001aae20 100644 --- a/docs/usage/05_concept_learners.md +++ b/docs/usage/06_concept_learners.md @@ -1,4 +1,4 @@ -# Concept Learners +# Concept Learning This is a guide to show how to use a concept learner to generate hypotheses for a target concept in an ontology. @@ -8,17 +8,20 @@ of Ontolearn library: - [CELOE](ontolearn.concept_learner.CELOE) - [OCEL](ontolearn.concept_learner.OCEL) +> **IMPORTANT**! +> - _DRILL_ is not fully implemented in Ontolear. In the meantime you can refer to +> [_DRILL's_ GitHub repo](https://github.com/dice-group/drill). +> - Documentation for _NCES_ coming soon. In the meantime visit _NCES_ jupyter notebooks +> inside [examples folder](https://github.com/dice-group/Ontolearn/tree/develop/examples). + These algorithms are similar in execution, for that reason, we are -describing them in a general manner. To test them separately we have provided -a jupyter notebook file for each of them (find them [here](#end-notes)). +describing them in a general manner. To test them separately see [_Quick try-out_](#quick-try-out). Each algorithm may have different available configuration. However, at -minimum, they require a [knowledge base](01_knowledge_base.md) and a -[learning problem](02_learning_problem.md). +minimum, they require a [knowledge base](04_knowledge_base.md) and a +[learning problem](04_knowledge_base.md#construct-a-learning-problem). Let's see the prerequisites needed to run the concept learners: ----------------------------------------------------------------------------- - ## Prerequisites Before configuring and running an algorithm, we recommend you store the dataset path @@ -60,9 +63,7 @@ an example file `synthetic_problems.json` showing how should it look: We have stored the ontology path under the property `data_path` and the **learning problems** under the property `problems`. ----------------------------------------------------------------------------- - -## Configuring input parameters +## Configuring Input Parameters Before starting with the configuration you can enable logging to see the logs which give insights about the main processes of the algorithm: @@ -84,15 +85,16 @@ with open('synthetic_problems.json') as json_file: settings = json.load(json_file) ``` +### Load the ontology - -#### Load the knowledge base - -Load the knowledge base by simply creating an instance of the class +Load the ontology by simply creating an instance of the class [KnowledgeBase](ontolearn.knowledge_base.KnowledgeBase) -and passing the knowledge base path stored +and passing the ontology path stored under `data_path` property of `settings`: +> The concept learning algorithm requires an object of type `KnowledgeBase`, that +> is why we are loading the ontology like this. + ```python from ontolearn.knowledge_base import KnowledgeBase @@ -111,8 +113,14 @@ for str_target_concept, examples in settings['problems'].items(): > **Note**: all the **code blocks** shown **below** this notice are inside the "`for`" loop. +## Configure the Learning Problem -#### Configure the learning problem +The Structured Machine Learning implemented in our Ontolearn library +is working with a type of [supervised +learning](https://en.wikipedia.org/wiki/Supervised_learning). One of +the first things to do after loading the Ontology is thus to define +the positive and negative examples whose description the learning +algorithm should attempt to find. Store the positive and negative examples into sets and *(optional)* print `str_target_concept` to keep track of @@ -125,10 +133,6 @@ which target concept is currently being learned: print('Target concept: ', str_target_concept) ``` -*(Optional)* If you have target concepts that you want to ignore check -[how to ignore concepts](01_knowledge_base.md#ignore-concepts) - - In Ontolearn you represent the learning problem as an object of the class `PosNegLPStandard` which has two parameters `pos` and `neg` respectively for the positive and negative examples. These parameters are of @@ -140,27 +144,26 @@ and `negative_examples` to `OWLNamedIndividual`: ```python from ontolearn.learning_problem import PosNegLPStandard -from ontolearn.owlapy.model import IRI, OWLNamedIndividual - -typed_pos = set(map(OWLNamedIndividual, map(IRI.create, p))) -typed_neg = set(map(OWLNamedIndividual, map(IRI.create, n))) -lp = PosNegLPStandard(pos=typed_pos, neg=typed_neg) + from ontolearn.owlapy.model import IRI, OWLNamedIndividual + + typed_pos = set(map(OWLNamedIndividual, map(IRI.create, p))) + typed_neg = set(map(OWLNamedIndividual, map(IRI.create, n))) + lp = PosNegLPStandard(pos=typed_pos, neg=typed_neg) ``` -To construct an [OWLNamedIndividual](owlapy.model.OWLNamedIndividual) object an [IRI](owlapy.model.IRI) is required as an input. -You can simply create an `IRI` object by calling the inbuilt method `create` +To construct an [OWLNamedIndividual](ontolearn.owlapy.model.OWLNamedIndividual) object an [IRI](ontolearn.owlapy.model.IRI) is required as an input. +You can simply create an `IRI` object by calling the static method `create` and passing the IRI as a `string`. ----------------------------------------------------------------------------- -## Configuring and Executing a Concept Learner +## Configuring & Executing a Concept Learner To learn class expressions we need to build a model of the concept learner that we want to use. It can be either EvoLearner, CELOE or OCEL. Depending on the algorithm you chose there are different initialization parameters which you can check [here](ontolearn.concept_learner). Let's start by setting a quality function. -#### Quality metrics +### Quality metrics The default quality function to evaluate the quality of the found expressions is [F1 Score](ontolearn.metrics.F1). @@ -176,9 +179,12 @@ There are as well [Predictive Accuracy](ontolearn.metrics.Accuracy), ``` In the following example we have build a model of [OCEL](ontolearn.concept_learner.OCEL) and -we have specified some of the parameters which OCEL offers: +we have specified some of the parameters which OCEL offers. -#### Create a model +*(Optional)* If you have target concepts that you want to ignore check +[_how to ignore concepts_](04_knowledge_base.md#ignore-concepts). + +### Create a model ```python @@ -200,7 +206,7 @@ The following parameters are optional. - `iter_bound` - limit to stop the algorithm after _n_ refinement steps are done. (Default value = 10_000) -#### Execute and fetch the results +### Execute and fetch the results Now, after creating the model you can **fit** the learning problem into this model, and it will find @@ -235,17 +241,46 @@ the method `best_hypotheses` where `n` is the number of hypotheses you want to r [print(hypothesis) for hypothesis in hypotheses] ``` ----------------------------------------------------------------------------- +## Quick try-out + +You can execute the script `deploy_cl.py` to deploy the concept learners in a local web server and try +the algorithms using an interactive interface made possible by [gradio](https://www.gradio.app/). Currently, +you can only deploy the following concept learners: **NCES**, **EvoLearner**, **CELOE** and **OCEL**. + +> **NOTE: In case you don't have you own dataset, don't worry, you can use +> the datasets we store in our data server. See _[Download external files](02_installation.md#download-external-files)_.** + +For example the command below will launch an interface using **EvoLearner** as the model on +the **Family** dataset which is a simple dataset with 202 individuals: + +```shell +python deploy_cl.py --model evolearner --path_knowledge_base KGs/Family/family-benchmark_rich_background.owl +``` + +Once you run this command, a local URL where our model is deployed will be provided to you. + +In the interface you need to enter the positive and the negative examples. For a quick run you can +click on the **Random Examples** checkbox, but you may as well enter some real examples for +the learning problem of **Aunt**, **Brother**, **Cousin**, etc. which +you can find in the folder `examples/synthetic_problems.json`. Just copy and paste the IRIs of +positive and negative examples for a certain learning problem directly +in their respective fields. + +Run the help command to see the description on this script usage: + +```shell +python deploy_cl.py --help +``` -### End Notes +--------------------------------------------------------------------------------------- In this guide, we have shown the prerequisites of running a concept learner, -how to configure its input properties and how to run it to successfully -learn class expressions for learning problems in an ontology. You can try the concept -learners that we mentioned in this guide by executing the following jupyter notebook -files: - -- [EvoLearner notebook](evolearner_notebook.ipynb) -- [CELOE notebook](celoe_notebook.ipynb) -- [OCEL notebook](ocel_notebook.ipynb) +how to configure it's input properties and how to run it to successfully +learn class expressions for learning problems in an ontology. There is also a jupyter +notebook for each of these concept learners: + +- [NCES notebook](../../examples/simple-usage-NCES.ipynb) +- [EvoLearner notebook](../../examples/evolearner_notebook.ipynb) +- [CELOE notebook](../../examples/celoe_notebook.ipynb) +- [OCEL notebook](../../examples/ocel_notebook.ipynb) diff --git a/docs/usage/06_reasoning_details.md b/docs/usage/06_reasoning_details.md deleted file mode 100644 index d86c0f39..00000000 --- a/docs/usage/06_reasoning_details.md +++ /dev/null @@ -1,242 +0,0 @@ -# Reasoning details - -In an earlier guide we explained how to [work with reasoners](04_reasoner.md). Here we cover a detailed explanation of -the Ontolearn reasoners, particularly -[OWLReasoner_Owlready2_ComplexCEInstances](owlapy.owlready2.complex_ce_instances.OWLReasoner_Owlready2_ComplexCEInstances). -Before we continue to talk about its [capabilities](#capabilities) we have to explain briefly -the term _sync_reasoner_. - -## Sync Reasoner - -_sync_reasoner_ is a definition used in owlready2 to run [HermiT](http://www.hermit-reasoner.com/) -or [Pellet](https://github.com/stardog-union/pellet) and -automatically apply the facts deduced to the quadstore. In simple terms, by running HermiT or Pellet, -one can infer more knowledge from the ontology (the specification are not mentioned here). -We make use of this functionality in Ontolearn, and it is used by the reasoner -[OWLReasoner_Owlready2_ComplexCEInstances](owlapy.owlready2.complex_ce_instances.OWLReasoner_Owlready2_ComplexCEInstances) -behind the stage. We explained the concept of "Worlds" in [Working with Ontologies](03_ontologies.md#worlds). Having -that in mind you need to know that sync_reasoner is applied to the World object. -After this particular reasoner is instantiated, because the facts are applied to the quadstore, changes made -in the ontology by using the ontology manager will not be reflected to the ontology. The reasoner will use the state of -the ontology at the moment it is instantiated. - -There are 2 boolean parameters for sync_reasoner that you can specify when creating an instance of -[OWLReasoner_Owlready2_ComplexCEInstances](owlapy.owlready2.complex_ce_instances.OWLReasoner_Owlready2_ComplexCEInstances). -The first one `infer_property_values` tells HermiT or Pellet whether to infer (or not) property values. The same idea but -for data properties is specified by the parameter `infer_data_property_values` which is only relevant to Pellet. - -> Note: HermiT and Pellet are Java programs, so you will need to install -a Java virtual machine to use them. If you don’t have Java, you may install -it from www.java.com (for Windows and macOS) or from the packages -of your Linux distribution (the packages are often named “jre” or “jdk” for -Java Runtime Environment and Java Development Kit). - -## Isolated World - -In [_Working with Ontologies_](03_ontologies.md#worlds) we mentioned that several isolated “worlds” -can be created. This comes in handy when we use multiple reasoners in the same script. If we create -an instance of _OWLReasoner_Owlready2_ComplexCEInstances_ it will apply sync_reasoner in the world object -of the ontology and this will affect also the other reasoner/s which is/are using the same world. To overcome this issue you can set the argument `isolate=True` when -initializing a reasoner. -[OWLReasoner_FastInstanceChecker](owlapy.fast_instance_checker.OWLReasoner_FastInstanceChecker) (FIC) -does not have this argument because it uses a base reasoner to delegate most of its methods. Therefore, -if the base reasoner has `isolate=True` then FIC will also operate in the isolated world of it's base reasoner. - -### Modifying an isolated ontology - -When a reasoner is operating in an isolated ontology, every axiom added to the original ontology before or after -the initialization, will not be reflected to the isolated ontology. To update the isolated ontology and add -or remove any axiom, you can use `update_isolated_ontology(axioms_to_add, axioms_to_remove)`. This method accepts -a list of axioms for every argument (i.e. the axioms that you want to add and the axioms that you want to remove). - -## Capabilities - -In _OWLReasoner_Owlready2_ComplexCEInstances_ we consider a close-world assumption (CWA) -according to the literature. We have adapted and build upon -[owlready2](https://owlready2.readthedocs.io/en/latest/) reasoner to provide -our own implementation in python. Below we give more details about each -functionality of our reasoner: - - -- #### Sub and Super Classes - - You can retrieve sub (super) classes of a given class expression. Depending on - your preferences you can retrieve the whole chain of sub (super) classes or only the - direct sub (super) classes (`direct` argument). It is also possible to get anonymous classes in addition - to named classes (`only_named` argument). Class equivalence entails subsumption of classes to each other. - -- #### Equivalent Classes - - You are able to get the equivalent classes of a given class expression. It can be - decided whether only named classes should be returned - or anonymous classes as well. If two classes are subclasses of each other they - are considered equivalent. - -- #### Disjoint Classes - - Every class that is explicitly defined as disjoint with another class will be returned. - In addition, every subclass and equivalent class of the disjoint classes will be - returned. If a target class does not have explicitly-defined disjoint classes the search - is transferred to the superclasses of that target class. - -- #### Equivalent Properties - - You are able to get equivalent properties of a given object or data property. - If two properties are sub-properties of each other, they are considered equivalent. - -- #### Sub and Super Properties - - Our reasoner has support also for sub and super properties of a - given property. You can set the `direct` argument like in sub (super) classes. - Properties equivalence entails subsumption of properties to each other. - -- #### Disjoint Properties - - Similarly to disjoint classes, you can get the disjoint properties of a property. - Same rules apply. - -- #### Property values - - Given an individual(instance) and an object property you can get all the object values. - Similarly, given an individual and a data property you can get all the literal values. - You can set whether you want only the direct values or all of them. - -- #### Property domain and range - - Easily retrieval available for domain and range for object properties and domain for data properties. - -- #### Instances - - This functionality enables you to get instances for a given named(atomic) class or complex class expression. - For the moment direct instances of complex class expressions is not possible. - -- #### Types - - This functionality enables you to get the types of a given instance. It returns only - named(atomic) classes. You can set the `direct` attribute. - -- #### Same and Different Individuals - - Given an individual you can get the individuals that are explicitly defined as same or different to that individual. - - - -## Concrete example - -You can find the associated [code](https://github.com/dice-group/Ontolearn/blob/develop/examples/example_reasoner.py) -for the following examples inside `examples/example_reasoner.py` -(note that the naming of the classes/relations/individuals may change from the table below). -We constructed an ontology for testing purposes. On the table we show for -each **method** of the reasoner _OWLReasoner_Owlready2_ComplexCEInstances_ the results -depending on a given **TBox** and **Abox**. The level of complexity of the TBox-es is low compared -to real world scenarios, but it's just to show the capabilities of the reasoner. - -> **Note:** not every method of the reasoner is used. You can check all the methods at the [API documentation](owlapy). - - -| Method | TBox | ABox | Returns
(T = Thing) | -|---------------------------------------------|---------------------------| --------------------- |------------------------| -| Equivalent_classes(A) | A ≡ B | \- | [B] | -| Equivalent_classes(B) | A ≡ B | \- | [A] | -| Instances(A) | A ≡ B | A(a),B(b) | [a,b] | -| Instances(B) | A ≡ B | A(a),B(b) | [a,b] | -| Types(a) | A ≡ B | A(a),B(b) | [T, A,B] | -| Types(b) | A ≡ B | A(a),B(b) | [T, A,B] | -| Sub_classes(A) | A ≡ B | \- | [B] | -| Sub_classes(B) | A ≡ B | \- | [A] | -| Super_classes(A) | A ≡ B | \- | [B,T] | -| Super_classes(B) | A ≡ B | \- | [A,T] | -| Equivalent_object_properties(r1) | r1 ≡ r2 | \- | [r2] | -| Equivalent_object_properties(r2) | r1 ≡ r2 | \- | [r1] | -| sub_object_properties(r1) | r1 ≡ r2 | \- | [r2] | -| sub_object_properties(r2) | r1 ≡ r2 | \- | [r1] | -| object_property_values(a, r1, direct=False) | r1 ≡ r2 | r1(a,b) r2(a,c) | [c] | -| object_property_values(a, r2, direct=False) | r1 ≡ r2 | r1(a,b) r2(a,c) | [c] | -| Sub_classes(B) | A ⊑ B | \- | [A] | -| Super_classes(A) | A ⊑ B | \- | [T, B] | -| Types(a) | A ⊑ B | A(a),B(b) | [A,B,T] | -| Types(b) | A ⊑ B | A(a),B(b) | [B,T] | -| Instances(A) | A ⊑ B | A(a),B(b) | [a] | -| Instances(B) | A ⊑ B | A(a),B(b) | [a,b] | -| sub_object_properties(r1) | r2⊑ r1 | \- | [r2] | -| object_property_values(a, r2) | r2⊑ r1 | r2(a,b) | [b] | -| object_property_values(a, r1, direct=False) | r2⊑ r1 | r2(a,b) | [b] | -| Sub_classes(r1.T) | r2⊑ r1 | \- | [r2.T] | -| Super_classes(D, only_named=False) | D ⊑ r.E | \- | [T, r.E] | -| Sub_classes(r.E) | D ⊑ r.E | \- | [D] | -| Instances(D) | D ⊑ r.E | D(d) r(i,e) E(e) | [d] | -| Instances(r.E) | D ⊑ r.E | D(d) r(i,e) E(e) | [i, d] | -| types(d) | D ⊑ r.E | D(d) r(i,e) E(e) | [D,T] | -| types(i) | D ⊑ r.E | D(d) r(i,e) E(e) | [T] | -| object_property_values(i, r) | D ⊑ r.E | r(i,e) E(e) | [e] | -| Sub_classes(D, only_named=False) | r.E ⊑ D | \- | [ r.E] | -| Super_classes( r.E) | r.E ⊑ D | \- | [D, T] | -| Instances(D) | r.E ⊑ D | D(d) r(i,e) E(e) | [i, d] | -| Instances(r.E) | r.E ⊑ D | D(d) r(i,e) E(e) | [i] | -| types(d) | r.E ⊑ D | D(d) r(i,e) E(e) | [D, T] | -| types(i) | r.E ⊑ D | D(d) r(i,e) E(e) | [D, T] | -| object_property_values(i, r) | r.E ⊑ D | r(i,e) E(e) | [e] | -| Sub_classes(A) | A ⊑ B, B ⊑ A | \- | [A,B] | -| Sub_classes(B) | A ⊑ B, B ⊑ A | \- | [A,B] | -| Super_classes(A) | A ⊑ B, B ⊑ A | \- | [T, B] | -| Super_classes(B) | A ⊑ B, B ⊑ A | \- | [T, A] | -| Types(a) | A ⊑ B, B ⊑ A | A(a),B(b) | [A,B,T] | -| Types(b) | A ⊑ B, B ⊑ A | A(a),B(b) | [A,B,T] | -| Instances(A) | A ⊑ B, B ⊑ A | A(a),B(b) | [a,b] | -| Instances(B) | A ⊑ B, B ⊑ A | A(a),B(b) | [a,b] | -| Equivalent_classes(A,only_named=False) | A ⊑ B, B ⊑ A | \- | [B] | -| Equivalent_classes(B,only_named=False) | A ⊑ B, B ⊑ A | \- | [A] | -| sub_object_properties(r1) | r2⊑ r1, r1⊑ r2 | \- | [r2,r1] | -| sub_object_properties(r2) | r2⊑ r1, r1⊑ r2 | \- | [r1,r2] | -| Equivalent_object_properties(r1) | r2⊑ r1, r1⊑ r2 | \- | [r2] | -| Equivalent_object_properties(r2) | r2⊑ r1, r1⊑ r2 | \- | [r1] | -| object_property_values(a, r1, direct=False) | r2⊑ r1, r1⊑ r2 | r1(a,b) r2(a,c) | [b,c] | -| object_property_values(a, r2, direct=False) | r2⊑ r1, r1⊑ r2 | r1(a,b) r2(a,c) | [b,c] | -| Sub_classes(J ⊓ K) | I ⊑ J ⊓ K | \- | [I] | -| Super_classes(I, only_named=False) | I ⊑ J ⊓ K | \- | [J ⊓ K, J, K, T] | -| Instances(J ⊓ K) | I ⊑ J ⊓ K | I(c) | [c] | -| types(c) | I ⊑ J ⊓ K | I(c) | [J, K, I, T] | -| Super_classes(J ⊓ K) | J ⊓ K ⊑ I | \- | [I, T] | -| Sub_classes(I, only_named=False) | J ⊓ K ⊑ I | \- | [J ⊓ K] | -| Instances(I) | J ⊓ K ⊑ I | J(s),K(s) | [s] | -| Instances(J ⊓ K) | J ⊓ K ⊑ I | J(s),K(s) | [s] | -| types(s) | J ⊓ K ⊑ I | J(s),K(s) | [J, K, I, T] | -| Sub_classes( r.E ⊓ B ) | D ⊑ r.E ⊓ B | \- | [D] | -| Super_classes(D, only_named=False) | D ⊑ r.E ⊓ B | \- | [T, r.E ⊓ B, B] | -| Instances(r.E ⊓ B) | D ⊑ r.E ⊓ B | D(d) r(b,f) E(f) B(b) | [d,b] | -| Sub_classes(H, only_named= False) | F ≡ r.G, F ⊑ H | \- | [F, r.G] | -| Super_classes(F) | F ≡ r.G, F ⊑ H | \- | [H,r.G,T] | -| Super_classes(r.G) | F ≡ r.G, F ⊑ H | \- | [F,H,T] | -| Equivalent_classes(F, only_named=False) | F ≡ r.G, F ⊑ H | \- | [r.G] | -| Equivalent_classes(r.G) | F ≡ r.G, F ⊑ H | \- | [F] | -| Instances(r.G) | F ≡ r.G, F ⊑ H | r(i,g) G(g) | [i] | -| Instances(F) | F ≡ r.G, F ⊑ H | r(i,g) G(g) | [i] | -| Instances(H) | F ≡ r.G, F ⊑ H | r(i,g) G(g) | [i] | -| types(i) | F ≡ r.G, F ⊑ H | r(i,g) G(g) | [H,F,T] | -| Sub_classes(C, only_named=False) | A ⊓ B ≡ R, R ⊑ C | \- | [R, A ⊓ B] | -| Super_classes(A ⊓ B) | A ⊓ B ≡ R, R ⊑ C | \- | [R, C,A,B,T] | -| Equivalent_classes(R,
only_named=False) | A ⊓ B ≡ R, R ⊑ C | \- | [A ⊓ B] | -| Equivalent_classes(A ⊓ B) | A ⊓ B ≡ R, R ⊑ C | \- | [R] | -| Instances(A ⊓ B) | A ⊓ B ≡ R, R ⊑ C | R(e) A(a) B(a) | [e,a] | -| Instances(R) | A ⊓ B ≡ R, R ⊑ C | R(e) A(a) B(a) | [a, e] | -| Instances(C) | A ⊓ B ≡ R, R ⊑ C | R(e) A(a) B(a) | [a, e] | -| Types(a) | A ⊓ B ≡ R, R ⊑ C | R(e) A(a) B(a) | [A,B,R,C,T] | -| Types(e) | A ⊓ B ≡ R, R ⊑ C | R(e) A(a) B(a) | [A,B,R,C,T] | -| Sub_classes(D, only_named=False) | r.P ⊓ C ≡ E, E ⊑ D | \- | [E, r.P ⊓ C] | -| Super_classes(r.P ⊓ C) | r.P ⊓ C ≡ E, E ⊑ D | \- | [E, D, T] | -| Equivalent_classes(r.P ⊓ C) | r.P ⊓ C ≡ E, E ⊑ D | \- | [E] | -| Equivalent_classes(E,
only_named=False) | r.P ⊓ C ≡ E, E ⊑ D | \- | [r.P ⊓ C] | -| Instances(r.P ⊓ C) | r.P ⊓ C ≡ E, E ⊑ D | r(x,y) C(x) P(y) | [x] | -| Instances(E) | r.P ⊓ C ≡ E, E ⊑ D | r(x,y) C(x) P(y) | [x] | -| Instances(D) | r.P ⊓ C ≡ E, E ⊑ D | r(x,y) C(x) P(y) | [x] | -| Types(x) | r.P ⊓ C ≡ E, E ⊑ D | r(x,y) C(x) P(y) | [C] | -| disjoint_classes(A) | A ⊔ B | \- | [B] | -| disjoint_classes(B) | A ⊔ B | \- | [A] | -| disjoint_classes(A) | A ⊔ B, B ≡ C | \- | [B, C] | -| disjoint_classes(B) | A ⊔ B, B ≡ C | \- | [A] | -| disjoint_classes(C) | A ⊔ B, B ≡ C | \- | [A] | -| object_property_domains(r) | Domain(r) = A | \- | [A,T] | -| object_property_domains(r) | Domain(r) = A
A ≡ B | \- | [A,T] | -| object_property_domains(r2) | Domain(r1) = A
r2 ⊑ r1 | \- | [A,T] | - - diff --git a/docs/usage/07_reasoning_details.md b/docs/usage/07_reasoning_details.md new file mode 100644 index 00000000..e8e69344 --- /dev/null +++ b/docs/usage/07_reasoning_details.md @@ -0,0 +1,243 @@ +# Reasoning Details + +In an earlier guide we explained how to [use reasoners](05_reasoner.md) in Ontolearn. Here we cover a detailed explanation of +the Ontolearn reasoners, particularly +[OWLReasoner_Owlready2_ComplexCEInstances](ontolearn.owlapy.owlready2.complex_ce_instances.OWLReasoner_Owlready2_ComplexCEInstances) (CCEI). +Before we continue to talk about its [capabilities](#capabilities) we have to explain briefly +the term _sync_reasoner_. + +## Sync Reasoner + +_sync_reasoner_ is a definition used in owlready2 to run [HermiT](http://www.hermit-reasoner.com/) +or [Pellet](https://github.com/stardog-union/pellet) and +automatically apply the facts deduced to the quadstore. In simple terms, by running HermiT or Pellet, +one can infer more knowledge from the ontology (the specification are not mentioned here). +We make use of this functionality in Ontolearn, and it is used by CCEI +behind the stage. We explained the concept of "Worlds" in [Working with Ontologies](03_ontologies.md#worlds). Having +that in mind you need to know that sync_reasoner is applied to the World object. +After this particular reasoner is instantiated, because the facts are applied to the quadstore, changes made +in the ontology by using the ontology manager will not be reflected to the ontology. The reasoner will use the state of +the ontology at the moment it is instantiated. + +There are 2 boolean parameters for sync_reasoner that you can specify when creating an instance of +[OWLReasoner_Owlready2_ComplexCEInstances](ontolearn.owlapy.owlready2.complex_ce_instances.OWLReasoner_Owlready2_ComplexCEInstances). +The first one `infer_property_values` tells HermiT or Pellet whether to infer (or not) property values. The same idea but +for data properties is specified by the parameter `infer_data_property_values` which is only relevant to Pellet. + +> Note: HermiT and Pellet are Java programs, so you will need to install +a Java virtual machine to use them. If you don’t have Java, you may install +it from www.java.com (for Windows and macOS) or from the packages +of your Linux distribution (the packages are often named “jre” or “jdk” for +Java Runtime Environment and Java Development Kit). + +## Isolated World + +In [_Working with Ontologies_](03_ontologies.md#worlds) we mentioned that we can have multiple reference of in different +worlds, which we can use to isolate an ontology to a specific World. For simplicity the terms "isolated world" and +"isolated ontology" can be used interchangeably in this guide. +The isolation comes in handy when we use multiple reasoners in the same script. If we create +an instance of _OWLReasoner_Owlready2_ComplexCEInstances_ it will apply sync_reasoner in the world object +of the ontology and this will affect also the other reasoner/s which is/are using the same world. +To overcome this issue you can set the argument `isolate=True` when +initializing a reasoner. +[OWLReasoner_FastInstanceChecker](ontolearn.owlapy.fast_instance_checker.OWLReasoner_FastInstanceChecker) (FIC) +does not have this argument because it uses a base reasoner to delegate most of its methods. Therefore, +if the base reasoner has `isolate=True` then FIC will also operate in the isolated world of it's base reasoner. + +### Modifying an isolated ontology + +When a reasoner is operating in an isolated ontology, every axiom added to the original ontology before or after +the initialization, will not be reflected to the isolated ontology. To update the isolated ontology and add +or remove any axiom, you can use `update_isolated_ontology(axioms_to_add, axioms_to_remove)`. This method accepts +a list of axioms for every argument (i.e. the axioms that you want to add and the axioms that you want to remove). + +## Capabilities + +_OWLReasoner_Owlready2_ComplexCEInstances_ provides full reasoning in +_ALCH_. We have adapted and build upon +[owlready2](https://owlready2.readthedocs.io/en/latest/) reasoner to provide +our own implementation in python. Below we give more details about each +functionality of our reasoner: + + +- #### Sub and Super Classes + + You can retrieve sub (super) classes of a given class expression. Depending on + your preferences you can retrieve the whole chain of sub (super) classes or only the + direct sub (super) classes (`direct` argument). It is also possible to get anonymous classes in addition + to named classes (`only_named` argument). Class equivalence entails subsumption of classes to each other. + +- #### Equivalent Classes + + You are able to get the equivalent classes of a given class expression. It can be + decided whether only named classes should be returned + or anonymous classes as well. If two classes are subclasses of each other they + are considered equivalent. + +- #### Disjoint Classes + + Every class that is explicitly defined as disjoint with another class will be returned. + In addition, every subclass and equivalent class of the disjoint classes will be + returned. If a target class does not have explicitly-defined disjoint classes the search + is transferred to the superclasses of that target class. + +- #### Equivalent Properties + + You are able to get equivalent properties of a given object or data property. + If two properties are sub-properties of each other, they are considered equivalent. + +- #### Sub and Super Properties + + Our reasoner has support also for sub and super properties of a + given property. You can set the `direct` argument like in sub (super) classes. + Properties equivalence entails subsumption of properties to each other. + +- #### Disjoint Properties + + Similarly to disjoint classes, you can get the disjoint properties of a property. + Same rules apply. + +- #### Property values + + Given an individual(instance) and an object property you can get all the object values. + Similarly, given an individual and a data property you can get all the literal values. + You can set whether you want only the direct values or all of them. + +- #### Property domain and range + + Easily retrieval available for domain and range for object properties and domain for data properties. + +- #### Instances + + This functionality enables you to get instances for a given named(atomic) class or complex class expression. + For the moment direct instances of complex class expressions is not possible. + +- #### Types + + This functionality enables you to get the types of a given instance. It returns only + named(atomic) classes. You can set the `direct` attribute. + +- #### Same and Different Individuals + + Given an individual you can get the individuals that are explicitly defined as same or different to that individual. + + +## Concrete Example + +You can find the associated [code](https://github.com/dice-group/Ontolearn/blob/develop/examples/example_reasone∃r.Py) +for the following examples inside `examples/example_reasone∃r.Py` +(note that the naming of the classes/relations/individuals may change from the table below). +We constructed an ontology for testing purposes. On the table we show for +each **method** of the reasoner _OWLReasoner_Owlready2_ComplexCEInstances_ the results +depending on a given **TBox** and **Abox**. The level of complexity of the TBox-es is low compared +to real world scenarios, but it's just to show the capabilities of the reasoner. + +> **Note:** not every method of the reasoner is used in this example. You can check all the methods at the [API documentation](owlapy). + + +| Method | TBox | ABox | Returns
(T = Thing) | +|-------------------------------------------|---------------------------| --------------------- |------------------------| +| Equivalent_classes(A) | A ≡ B | \- | [B] | +| Equivalent_classes(B) | A ≡ B | \- | [A] | +| Instances(A) | A ≡ B | A(a),B(b) | [a,b] | +| Instances(B) | A ≡ B | A(a),B(b) | [a,b] | +| Types(a) | A ≡ B | A(a),B(b) | [T, A,B] | +| Types(b) | A ≡ B | A(a),B(b) | [T, A,B] | +| Sub_classes(A) | A ≡ B | \- | [B] | +| Sub_classes(B) | A ≡ B | \- | [A] | +| Super_classes(A) | A ≡ B | \- | [B,T] | +| Super_classes(B) | A ≡ B | \- | [A,T] | +| Equivalent_object_properties(r1) | r1 ≡ r2 | \- | [r2] | +| Equivalent_object_properties(r2) | r1 ≡ r2 | \- | [r1] | +| sub_object_properties(r1) | r1 ≡ r2 | \- | [r2] | +| sub_object_properties(r2) | r1 ≡ r2 | \- | [r1] | +| object_property_values(a, r1, direct=False) | r1 ≡ r2 | r1(a,b) r2(a,c) | [c] | +| object_property_values(a, r2, direct=False) | r1 ≡ r2 | r1(a,b) r2(a,c) | [c] | +| Sub_classes(B) | A ⊑ B | \- | [A] | +| Super_classes(A) | A ⊑ B | \- | [T, B] | +| Types(a) | A ⊑ B | A(a),B(b) | [A,B,T] | +| Types(b) | A ⊑ B | A(a),B(b) | [B,T] | +| Instances(A) | A ⊑ B | A(a),B(b) | [a] | +| Instances(B) | A ⊑ B | A(a),B(b) | [a,b] | +| sub_object_properties(r1) | r2 ⊑ r1 | \- | [r2] | +| object_property_values(a, r2) | r2 ⊑ r1 | r2(a,b) | [b] | +| object_property_values(a, r1, direct=False) | r2 ⊑ r1 | r2(a,b) | [b] | +| Sub_classes(r1.T) | r2 ⊑ r1 | \- | [r2.T] | +| Super_classes(D, only_named=False) | D ⊑ ∃r.E | \- | [T, ∃r.E] | +| Sub_classes(∃r.E) | D ⊑ ∃r.E | \- | [D] | +| Instances(D) | D ⊑ ∃r.E | D(d) r(i,e) E(e) | [d] | +| Instances(∃r.E) | D ⊑ ∃r.E | D(d) r(i,e) E(e) | [i, d] | +| types(d) | D ⊑ ∃r.E | D(d) r(i,e) E(e) | [D,T] | +| types(i) | D ⊑ ∃r.E | D(d) r(i,e) E(e) | [T] | +| object_property_values(i, r) | D ⊑ ∃r.E | r(i,e) E(e) | [e] | +| Sub_classes(D, only_named=False) | ∃r.E ⊑ D | \- | [ ∃r.E] | +| Super_classes( ∃r.E) | ∃r.E ⊑ D | \- | [D, T] | +| Instances(D) | ∃r.E ⊑ D | D(d) r(i,e) E(e) | [i, d] | +| Instances(∃r.E) | ∃r.E ⊑ D | D(d) r(i,e) E(e) | [i] | +| types(d) | ∃r.E ⊑ D | D(d) r(i,e) E(e) | [D, T] | +| types(i) | ∃r.E ⊑ D | D(d) r(i,e) E(e) | [D, T] | +| object_property_values(i, r) | ∃r.E ⊑ D | r(i,e) E(e) | [e] | +| Sub_classes(A) | A ⊑ B, B ⊑ A | \- | [A,B] | +| Sub_classes(B) | A ⊑ B, B ⊑ A | \- | [A,B] | +| Super_classes(A) | A ⊑ B, B ⊑ A | \- | [T, B] | +| Super_classes(B) | A ⊑ B, B ⊑ A | \- | [T, A] | +| Types(a) | A ⊑ B, B ⊑ A | A(a),B(b) | [A,B,T] | +| Types(b) | A ⊑ B, B ⊑ A | A(a),B(b) | [A,B,T] | +| Instances(A) | A ⊑ B, B ⊑ A | A(a),B(b) | [a,b] | +| Instances(B) | A ⊑ B, B ⊑ A | A(a),B(b) | [a,b] | +| Equivalent_classes(A,only_named=False) | A ⊑ B, B ⊑ A | \- | [B] | +| Equivalent_classes(B,only_named=False) | A ⊑ B, B ⊑ A | \- | [A] | +| sub_object_properties(r1) | r2⊑ r1, r1⊑ r2 | \- | [r2,r1] | +| sub_object_properties(r2) | r2⊑ r1, r1⊑ r2 | \- | [r1,r2] | +| Equivalent_object_properties(r1) | r2⊑ r1, r1⊑ r2 | \- | [r2] | +| Equivalent_object_properties(r2) | r2⊑ r1, r1⊑ r2 | \- | [r1] | +| object_property_values(a, r1, direct=False) | r2 ⊑ r1, r1 ⊑ r2 | r1(a,b) r2(a,c) | [b,c] | +| object_property_values(a, r2, direct=False) | r2 ⊑ r1, r1 ⊑ r2 | r1(a,b) r2(a,c) | [b,c] | +| Sub_classes(J ⊓ K) | I ⊑ J ⊓ K | \- | [I] | +| Super_classes(I, only_named=False) | I ⊑ J ⊓ K | \- | [J ⊓ K, J, K, T] | +| Instances(J ⊓ K) | I ⊑ J ⊓ K | I(c) | [c] | +| types(c) | I ⊑ J ⊓ K | I(c) | [J, K, I, T] | +| Super_classes(J ⊓ K) | J ⊓ K ⊑ I | \- | [I, T] | +| Sub_classes(I, only_named=False) | J ⊓ K ⊑ I | \- | [J ⊓ K] | +| Instances(I) | J ⊓ K ⊑ I | J(s),K(s) | [s] | +| Instances(J ⊓ K) | J ⊓ K ⊑ I | J(s),K(s) | [s] | +| types(s) | J ⊓ K ⊑ I | J(s),K(s) | [J, K, I, T] | +| Sub_classes( ∃r.E ⊓ B ) | D ⊑ ∃r.E ⊓ B | \- | [D] | +| Super_classes(D, only_named=False) | D ⊑ ∃r.E ⊓ B | \- | [T, ∃r.E ⊓ B, B] | +| Instances(∃r.E ⊓ B) | D ⊑ ∃r.E ⊓ B | D(d) r(b,f) E(f) B(b) | [d,b] | +| Sub_classes(H, only_named= False) | F ≡ ∃r.G, F ⊑ H | \- | [F, ∃r.G] | +| Super_classes(F) | F ≡ ∃r.G, F ⊑ H | \- | [H,∃r.G,T] | +| Super_classes(∃r.G) | F ≡ ∃r.G, F ⊑ H | \- | [F,H,T] | +| Equivalent_classes(F, only_named=False) | F ≡ ∃r.G, F ⊑ H | \- | [∃r.G] | +| Equivalent_classes(∃r.G) | F ≡ ∃r.G, F ⊑ H | \- | [F] | +| Instances(∃r.G) | F ≡ ∃r.G, F ⊑ H | r(i,g) G(g) | [i] | +| Instances(F) | F ≡ ∃r.G, F ⊑ H | r(i,g) G(g) | [i] | +| Instances(H) | F ≡ ∃r.G, F ⊑ H | r(i,g) G(g) | [i] | +| types(i) | F ≡ ∃r.G, F ⊑ H | r(i,g) G(g) | [H,F,T] | +| Sub_classes(C, only_named=False) | A ⊓ B ≡ R, R ⊑ C | \- | [R, A ⊓ B] | +| Super_classes(A ⊓ B) | A ⊓ B ≡ R, R ⊑ C | \- | [R, C,A,B,T] | +| Equivalent_classes(R,
only_named=False) | A ⊓ B ≡ R, R ⊑ C | \- | [A ⊓ B] | +| Equivalent_classes(A ⊓ B) | A ⊓ B ≡ R, R ⊑ C | \- | [R] | +| Instances(A ⊓ B) | A ⊓ B ≡ R, R ⊑ C | R(e) A(a) B(a) | [e,a] | +| Instances(R) | A ⊓ B ≡ R, R ⊑ C | R(e) A(a) B(a) | [a, e] | +| Instances(C) | A ⊓ B ≡ R, R ⊑ C | R(e) A(a) B(a) | [a, e] | +| Types(a) | A ⊓ B ≡ R, R ⊑ C | R(e) A(a) B(a) | [A,B,R,C,T] | +| Types(e) | A ⊓ B ≡ R, R ⊑ C | R(e) A(a) B(a) | [A,B,R,C,T] | +| Sub_classes(D, only_named=False) | ∃r.P ⊓ C ≡ E, E ⊑ D | \- | [E, ∃r.P ⊓ C] | +| Super_classes(∃r.P ⊓ C) | ∃r.P ⊓ C ≡ E, E ⊑ D | \- | [E, D, T] | +| Equivalent_classes(∃r.P ⊓ C) | ∃r.P ⊓ C ≡ E, E ⊑ D | \- | [E] | +| Equivalent_classes(E,
only_named=False) | ∃r.P ⊓ C ≡ E, E ⊑ D | \- | [∃r.P ⊓ C] | +| Instances(∃r.P ⊓ C) | ∃r.P ⊓ C ≡ E, E ⊑ D | r(x,y) C(x) P(y) | [x] | +| Instances(E) | ∃r.P ⊓ C ≡ E, E ⊑ D | r(x,y) C(x) P(y) | [x] | +| Instances(D) | ∃r.P ⊓ C ≡ E, E ⊑ D | r(x,y) C(x) P(y) | [x] | +| Types(x) | ∃r.P ⊓ C ≡ E, E ⊑ D | r(x,y) C(x) P(y) | [C] | +| disjoint_classes(A) | A ⊔ B | \- | [B] | +| disjoint_classes(B) | A ⊔ B | \- | [A] | +| disjoint_classes(A) | A ⊔ B, B ≡ C | \- | [B, C] | +| disjoint_classes(B) | A ⊔ B, B ≡ C | \- | [A] | +| disjoint_classes(C) | A ⊔ B, B ≡ C | \- | [A] | +| object_property_domains(r) | Domain(r) = A | \- | [A,T] | +| object_property_domains(r) | Domain(r) = A
A ≡ B | \- | [A,T] | +| object_property_domains(r2) | Domain(r1) = A
r2 ⊑ r1 | \- | [A,T] | + + diff --git a/docs/usage/09_model_adapter.md b/docs/usage/08_model_adapter.md similarity index 97% rename from docs/usage/09_model_adapter.md rename to docs/usage/08_model_adapter.md index 8f33112b..0a372f6f 100644 --- a/docs/usage/09_model_adapter.md +++ b/docs/usage/08_model_adapter.md @@ -1,7 +1,7 @@ # Model Adaptor To simplify the connection between all the -[Components](08_architecture.md#component-architecture), there is a +components, there is a model adaptor available that automatically constructs and connects them. Here is how to implement the previous example using the Model Adaptor: diff --git a/docs/usage/09_further_resources.md b/docs/usage/09_further_resources.md new file mode 100644 index 00000000..1e3ac37f --- /dev/null +++ b/docs/usage/09_further_resources.md @@ -0,0 +1,74 @@ +# Further Resources + +You can find more details in the related papers for each algorithm: + +- **NCES2** → (soon) [Neural Class Expression Synthesis in ALCHIQ(D)](https://papers.dice-research.org/2023/ECML_NCES2/NCES2_public.pdf) +- **Drill** → [Deep Reinforcement Learning for Refinement Operators in ALC](https://arxiv.org/pdf/2106.15373.pdf) +- **NCES** → [Neural Class Expression Synthesis](https://link.springer.com/chapter/10.1007/978-3-031-33455-9_13) +- **NERO** → (soon) [Learning Permutation-Invariant Embeddings for Description Logic Concepts](https://github.com/dice-group/Nero) +- **EvoLearner** → [An evolutionary approach to learn concepts in ALCQ(D)](https://dl.acm.org/doi/abs/10.1145/3485447.3511925) +- **CLIP** → (soon) [Learning Concept Lengths Accelerates Concept Learning in ALC](https://link.springer.com/chapter/10.1007/978-3-031-06981-9_14) +- **CELOE** → [Class Expression Learning for Ontology Engineering](https://www.sciencedirect.com/science/article/abs/pii/S1570826811000023) + +## Citing + +Currently, we are working on our manuscript describing our framework. +If you find our work useful in your research, please consider citing the respective paper: + +``` +# NCES2 +@inproceedings{kouagou2023nces2, +author={Kouagou, N'Dah Jean and Heindorf, Stefan and Demir, Caglar and Ngonga Ngomo, Axel-Cyrille}, +title={Neural Class Expression Synthesis in ALCHIQ(D)}, +url = {https://papers.dice-research.org/2023/ECML_NCES2/NCES2_public.pdf}, +booktitle={Machine Learning and Knowledge Discovery in Databases}, +year={2023}, +publisher={Springer Nature Switzerland}, +address="Cham" +} + +# NCES +@inproceedings{kouagou2023neural, + title={Neural class expression synthesis}, + author={Kouagou, N’Dah Jean and Heindorf, Stefan and Demir, Caglar and Ngonga Ngomo, Axel-Cyrille}, + booktitle={European Semantic Web Conference}, + pages={209--226}, + year={2023}, + publisher={Springer Nature Switzerland} +} + +# EvoLearner +@inproceedings{heindorf2022evolearner, + title={Evolearner: Learning description logics with evolutionary algorithms}, + author={Heindorf, Stefan and Bl{\"u}baum, Lukas and D{\"u}sterhus, Nick and Werner, Till and Golani, Varun Nandkumar and Demir, Caglar and Ngonga Ngomo, Axel-Cyrille}, + booktitle={Proceedings of the ACM Web Conference 2022}, + pages={818--828}, + year={2022} +} + + +# CLIP +@inproceedings{kouagou2022learning, + title={Learning Concept Lengths Accelerates Concept Learning in ALC}, + author={Kouagou, N’Dah Jean and Heindorf, Stefan and Demir, Caglar and Ngonga Ngomo, Axel-Cyrille}, + booktitle={European Semantic Web Conference}, + pages={236--252}, + year={2022}, + publisher={Springer Nature Switzerland} +} +``` + +## More Inside the Project + +Examples and test cases provide a good starting point to get to know +the project better. Find them in the folders `examples` and `tests`. + +## Contribution + +Feel free to create a pull request and our developers will take a look on it. +We appreciate your commitment. + +## Questions + +In case you have any question, please contact: `onto-learn@lists.uni-paderborn.de` +or open an issue on our [GitHub issues page](https://github.com/dice-group/Ontolearn/issues). diff --git a/docs/usage/08_architecture.md b/docs/usage/architecture.md similarity index 100% rename from docs/usage/08_architecture.md rename to docs/usage/architecture.md diff --git a/docs/usage/see_examples.md b/docs/usage/see_examples.md deleted file mode 100644 index b2956944..00000000 --- a/docs/usage/see_examples.md +++ /dev/null @@ -1,5 +0,0 @@ -# Further reading - -Further references and material can be found by inspecting the existing -tests and the code in the examples folder. - diff --git a/download_external_resources.sh b/download_external_resources.sh new file mode 100644 index 00000000..5f169acf --- /dev/null +++ b/download_external_resources.sh @@ -0,0 +1,9 @@ +# Datasets +wget https://files.dice-research.org/projects/Ontolearn/KGs.zip -O ./KGs.zip +unzip KGs.zip # or `tar -xf KGs.zip` for windows +rm KGs.zip + +# NCES Data +wget https://files.dice-research.org/projects/NCES/NCES_Ontolearn_Data/NCESData.zip -O ./NCESData.zip +unzip NCESData.zip # or `tar -xf NCESData.zip` for windows +rm NCESData.zip diff --git a/environment.yml b/environment.yml index a4fde72b..c4714c65 100644 --- a/environment.yml +++ b/environment.yml @@ -32,6 +32,8 @@ dependencies: # PIP - pip=21.0.1 - pip: + - tokenizers==0.12.1 + - transformers==4.19.2 # testing - tox-run-before==0.1 # docs diff --git a/examples/advanced-usage-NCES.ipynb b/examples/advanced-usage-NCES.ipynb index c917f844..6c04bd93 100644 --- a/examples/advanced-usage-NCES.ipynb +++ b/examples/advanced-usage-NCES.ipynb @@ -1,16 +1,18 @@ { "cells": [ { + "attachments": {}, "cell_type": "markdown", - "id": "controlling-tissue", + "id": "immune-fluid", "metadata": {}, "source": [ - "From the main directory \"Ontolearn\", run `./big_gitext/download_nces_data` to download pretrained models and datasets" + "From the main directory \"Ontolearn\", run the commands for NCES data in [`./download_external_resources.sh`](../download_external_resources.sh) to download pretrained models and datasets." ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "brief-cooperative", + "id": "dominant-delivery", "metadata": {}, "source": [ "## Inference with NCES" @@ -19,27 +21,19 @@ { "cell_type": "code", "execution_count": 1, - "id": "living-veteran", + "id": "settled-complexity", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "* Owlready2 * Warning: optimized Cython parser module 'owlready2_optimized' is not available, defaulting to slower Python implementation\n" - ] - } - ], + "outputs": [], "source": [ "from ontolearn.concept_learner import NCES\n", "from ontolearn.knowledge_base import KnowledgeBase\n", - "from owlapy.parser import DLSyntaxParser" + "from ontolearn.owlapy.parser import DLSyntaxParser" ] }, { "cell_type": "code", "execution_count": 2, - "id": "saved-decade", + "id": "massive-reply", "metadata": {}, "outputs": [ { @@ -61,7 +55,7 @@ { "cell_type": "code", "execution_count": 3, - "id": "cathedral-survey", + "id": "structured-houston", "metadata": {}, "outputs": [], "source": [ @@ -71,7 +65,7 @@ { "cell_type": "code", "execution_count": 4, - "id": "uniform-eating", + "id": "broken-salon", "metadata": {}, "outputs": [], "source": [ @@ -81,7 +75,7 @@ { "cell_type": "code", "execution_count": 5, - "id": "attached-equation", + "id": "italian-cabinet", "metadata": {}, "outputs": [], "source": [ @@ -89,8 +83,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "blessed-hebrew", + "id": "running-prototype", "metadata": {}, "source": [ "### Let's learn the concept ``Father''" @@ -99,7 +94,7 @@ { "cell_type": "code", "execution_count": 6, - "id": "orange-wound", + "id": "advised-feeling", "metadata": {}, "outputs": [], "source": [ @@ -109,7 +104,7 @@ { "cell_type": "code", "execution_count": 7, - "id": "facial-british", + "id": "oriental-disney", "metadata": {}, "outputs": [], "source": [ @@ -119,7 +114,7 @@ { "cell_type": "code", "execution_count": 8, - "id": "bronze-midwest", + "id": "thorough-intermediate", "metadata": {}, "outputs": [], "source": [ @@ -129,7 +124,7 @@ { "cell_type": "code", "execution_count": 9, - "id": "comparative-calvin", + "id": "cleared-chocolate", "metadata": {}, "outputs": [], "source": [ @@ -137,8 +132,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "brutal-house", + "id": "frank-front", "metadata": {}, "source": [ "#### Prediction with SetTransformer" @@ -147,7 +143,7 @@ { "cell_type": "code", "execution_count": 10, - "id": "specialized-transition", + "id": "objective-response", "metadata": {}, "outputs": [ { @@ -165,7 +161,7 @@ { "cell_type": "code", "execution_count": 11, - "id": "homeless-hardwood", + "id": "adopted-retirement", "metadata": {}, "outputs": [ { @@ -184,8 +180,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "vulnerable-phrase", + "id": "hungarian-transsexual", "metadata": {}, "source": [ "#### Prediction with GRU" @@ -194,7 +191,7 @@ { "cell_type": "code", "execution_count": 12, - "id": "planned-magic", + "id": "streaming-wayne", "metadata": {}, "outputs": [ { @@ -216,8 +213,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "affiliated-appointment", + "id": "killing-determination", "metadata": {}, "source": [ "#### Prediction with LSTM" @@ -226,7 +224,7 @@ { "cell_type": "code", "execution_count": 13, - "id": "detected-coordinate", + "id": "mathematical-denial", "metadata": {}, "outputs": [ { @@ -248,8 +246,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "awful-honolulu", + "id": "divided-respondent", "metadata": {}, "source": [ "#### Prediction with ensemble SetTransformer+GRU+LSTM" @@ -258,7 +257,7 @@ { "cell_type": "code", "execution_count": 14, - "id": "external-rapid", + "id": "systematic-gothic", "metadata": {}, "outputs": [ { @@ -288,8 +287,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "public-opinion", + "id": "square-upper", "metadata": {}, "source": [ "### Scalability of NCES (solving multiple learning problems in a go!)" @@ -298,7 +298,7 @@ { "cell_type": "code", "execution_count": 15, - "id": "diagnostic-hearing", + "id": "young-internet", "metadata": {}, "outputs": [], "source": [ @@ -308,7 +308,7 @@ { "cell_type": "code", "execution_count": 16, - "id": "egyptian-architect", + "id": "technological-evans", "metadata": {}, "outputs": [], "source": [ @@ -321,7 +321,7 @@ { "cell_type": "code", "execution_count": 17, - "id": "provincial-distance", + "id": "thousand-blind", "metadata": {}, "outputs": [], "source": [ @@ -332,14 +332,14 @@ { "cell_type": "code", "execution_count": 18, - "id": "streaming-incentive", + "id": "closing-fantasy", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Duration: 5.849813461303711 seconds!\n" + "Duration: 3.079460620880127 seconds!\n" ] } ], @@ -353,7 +353,7 @@ { "cell_type": "code", "execution_count": 19, - "id": "built-freeze", + "id": "measured-observation", "metadata": {}, "outputs": [ { @@ -371,7 +371,7 @@ { "cell_type": "code", "execution_count": 20, - "id": "accessible-paint", + "id": "cheap-acrobat", "metadata": {}, "outputs": [ { @@ -387,8 +387,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "impressive-munich", + "id": "metropolitan-light", "metadata": {}, "source": [ "### Change pretrained model name, e.g., use ensemble model prediction" @@ -397,7 +398,7 @@ { "cell_type": "code", "execution_count": 21, - "id": "facial-commonwealth", + "id": "competitive-result", "metadata": {}, "outputs": [], "source": [ @@ -407,7 +408,7 @@ { "cell_type": "code", "execution_count": 22, - "id": "touched-string", + "id": "outside-munich", "metadata": {}, "outputs": [ { @@ -428,7 +429,7 @@ { "cell_type": "code", "execution_count": 23, - "id": "posted-amber", + "id": "wired-trainer", "metadata": {}, "outputs": [ { @@ -453,14 +454,14 @@ { "cell_type": "code", "execution_count": 24, - "id": "incorrect-customer", + "id": "fabulous-florida", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Duration: 26.70125699043274 seconds!\n" + "Duration: 8.768116474151611 seconds!\n" ] } ], @@ -474,7 +475,7 @@ { "cell_type": "code", "execution_count": 25, - "id": "scheduled-speaker", + "id": "australian-geography", "metadata": {}, "outputs": [ { @@ -493,8 +494,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "global-rough", + "id": "paperback-window", "metadata": {}, "source": [ "## Training NCES" @@ -502,20 +504,20 @@ }, { "cell_type": "code", - "execution_count": 1, - "id": "regional-arcade", + "execution_count": 26, + "id": "confused-sleep", "metadata": {}, "outputs": [], "source": [ - "import json\n", + "import json, time\n", "with open(\"../NCESData/family/training_data/Data.json\") as file:\n", - " data = json.load(file)" + " data = json.load(file) # Training data. Below we use the first 200 datapoints to train the synthesizer. You train on the full data, e.g. on GPU by remobing \"[:200]\"" ] }, { "cell_type": "code", - "execution_count": 2, - "id": "ambient-distribution", + "execution_count": 27, + "id": "alive-preparation", "metadata": {}, "outputs": [], "source": [ @@ -524,8 +526,8 @@ }, { "cell_type": "code", - "execution_count": 3, - "id": "demonstrated-calibration", + "execution_count": 28, + "id": "specialized-biography", "metadata": {}, "outputs": [], "source": [ @@ -536,18 +538,60 @@ }, { "cell_type": "code", - "execution_count": 6, - "id": "removable-replacement", + "execution_count": 29, + "id": "parallel-cleveland", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "********************Trainable model size********************\n", + "Synthesizer: 515296\n", + "********************Trainable model size********************\n", + "\n", + "Training on CPU, it may take long...\n", + "\n", + "##################################################\n", + "\n", + "SetTransformer starts training... \n", + "\n", + "################################################## \n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Loss: 0.5712, Soft Acc: 74.01%, Hard Acc: 71.02%: 100%|██████████| 20/20 [01:12<00:00, 3.63s/it]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Top performance: loss: 0.5712, soft accuracy: 74.65% ... hard accuracy: 72.23%\n", + "\n", + "SetTransformer saved\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], "source": [ - "nces.train(list(data.items())[-200:], epochs=20, learning_rate=0.001, save_model=True, storage_path=\"./new_experiment_ontolearn_nces/\")" + "nces.train(list(data.items())[-200:], epochs=20, learning_rate=0.001, save_model=True, storage_path=f\"./NCES-{time.time()}/\")" ] }, { "cell_type": "code", "execution_count": null, - "id": "narrative-tragedy", + "id": "apparent-kelly", "metadata": {}, "outputs": [], "source": [] @@ -555,7 +599,7 @@ { "cell_type": "code", "execution_count": null, - "id": "classical-contest", + "id": "western-message", "metadata": {}, "outputs": [], "source": [] diff --git a/docs/usage/celoe_notebook.ipynb b/examples/celoe_notebook.ipynb similarity index 81% rename from docs/usage/celoe_notebook.ipynb rename to examples/celoe_notebook.ipynb index bc781a80..7d78ac0c 100644 --- a/docs/usage/celoe_notebook.ipynb +++ b/examples/celoe_notebook.ipynb @@ -3,17 +3,18 @@ { "attachments": {}, "cell_type": "markdown", - "id": "5a271671", + "id": "blond-letter", "metadata": {}, "source": [ "# CELOE Notebook\n", - "This is a jupyter notebook file to execute [CELOE](ontolearn.concept_learner.CELOE) and generate predictive results. We recommend you to see the [concept learners](05_concept_learners.md) guide before continuing with the execution." + "This is a jupyter notebook file to execute [CELOE](ontolearn.concept_learner.CELOE) and generate predictive results. We recommend you to see the [concept learners](../docs/usage/06_concept_learners.md) guide before continuing with the execution.\n", + "Also if you have not done it already, from the main directory \"Ontolearn\", run the commands for Datasets in [`./download_external_resources.sh`](../download_external_resources.sh) to download the datasets." ] }, { "cell_type": "code", "execution_count": 2, - "id": "99ebe420-afcf-47e5-825a-6c283692a481", + "id": "japanese-ivory", "metadata": {}, "outputs": [], "source": [ @@ -21,14 +22,14 @@ "from ontolearn.knowledge_base import KnowledgeBase\n", "from ontolearn.concept_learner import CELOE\n", "from ontolearn.learning_problem import PosNegLPStandard\n", - "from owlapy.model import OWLNamedIndividual, IRI\n", + "from ontolearn.owlapy.model import OWLNamedIndividual, IRI\n", "from ontolearn.utils import setup_logging\n" ] }, { "attachments": {}, "cell_type": "markdown", - "id": "669cbecf", + "id": "pending-coast", "metadata": {}, "source": [ "Open `uncle_lp.json` where we have stored the learning problem for the concept of 'Uncle' and the path to the 'family' ontology." @@ -37,18 +38,18 @@ { "cell_type": "code", "execution_count": 2, - "id": "bb20f1f4", + "id": "beginning-syntax", "metadata": {}, "outputs": [], "source": [ - "with open('../../examples/uncle_lp.json') as json_file:\n", + "with open('uncle_lp.json') as json_file:\n", " settings = json.load(json_file)" ] }, { "attachments": {}, "cell_type": "markdown", - "id": "ccee8b03", + "id": "humanitarian-heating", "metadata": {}, "source": [ "Create an instance of the class `KnowledeBase` by using the path that is stored in `settings`." @@ -57,7 +58,7 @@ { "cell_type": "code", "execution_count": 3, - "id": "9f5839e5", + "id": "caroline-indiana", "metadata": {}, "outputs": [], "source": [ @@ -67,16 +68,16 @@ { "attachments": {}, "cell_type": "markdown", - "id": "8dd9881f", + "id": "lucky-activation", "metadata": {}, "source": [ - "Retreive the IRIs of the positive and negative examples of Uncle from `settings` and create an instance of `PosNegLPStandard`. (more info about this [here](02_learning_problem.md))" + "Retreive the IRIs of the positive and negative examples of Uncle from `settings` and create an instance of `PosNegLPStandard`. (more info about this [here](../docs/usage/06_concept_learners.md#configure-the-learning-problem))" ] }, { "cell_type": "code", "execution_count": 4, - "id": "2661a3eb", + "id": "processed-patrick", "metadata": {}, "outputs": [], "source": [ @@ -91,7 +92,7 @@ { "attachments": {}, "cell_type": "markdown", - "id": "985f6a2d", + "id": "mechanical-latin", "metadata": {}, "source": [ "Create a model of [CELOE](ontolearn.concept_learner.CELOE) and fit the learning problem to the model." @@ -100,7 +101,7 @@ { "cell_type": "code", "execution_count": 8, - "id": "4ef6c110", + "id": "binding-moderator", "metadata": {}, "outputs": [ { @@ -122,7 +123,7 @@ { "attachments": {}, "cell_type": "markdown", - "id": "96ecb16c", + "id": "lesser-cover", "metadata": {}, "source": [ "Retrieve top 3 hypotheses and print them." @@ -131,7 +132,7 @@ { "cell_type": "code", "execution_count": 6, - "id": "94cef573", + "id": "departmental-international", "metadata": {}, "outputs": [ { @@ -162,7 +163,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -176,7 +177,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.16" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/examples/concept_learning_with_celoe_heuristic_ma.py b/examples/concept_learning_with_celoe_heuristic_ma.py index 444d38bd..27a85d9f 100644 --- a/examples/concept_learning_with_celoe_heuristic_ma.py +++ b/examples/concept_learning_with_celoe_heuristic_ma.py @@ -4,7 +4,7 @@ from ontolearn.concept_learner import CELOE from ontolearn.knowledge_base import KnowledgeBase -from ontolearn.model_adapter import ModelAdapter +from ontolearn.model_adapter import ModelAdapter, Trainer from ontolearn.owlapy.model import OWLClass, OWLNamedIndividual, IRI from ontolearn.utils import setup_logging from ontolearn.owlapy.owlready2 import BaseReasoner_Owlready2, OWLOntology_Owlready2 @@ -61,7 +61,7 @@ ignore=concepts_to_ignore, reasoner=reasoner, learner_type=CELOE, - max_runtime=60, + max_runtime=5, max_num_of_concepts_tested=10_000_000_000, iter_bound=10_000_000_000, expansionPenaltyFactor=0.01) @@ -76,4 +76,12 @@ hypotheses=hypotheses) # print(predictions) [print(_) for _ in hypotheses] - # exit(1) + + # Using Trainer + model2 = CELOE(knowledge_base=kb, max_runtime=5) + trainer = Trainer(model, reasoner) + trainer.fit(pos=typed_pos, neg=typed_neg) + hypotheses = list(model2.best_hypotheses(n=3)) + [print(_) for _ in hypotheses] + + diff --git a/examples/custom-LPs-NCES.ipynb b/examples/custom-LPs-NCES.ipynb index 95f44ef4..495f941d 100644 --- a/examples/custom-LPs-NCES.ipynb +++ b/examples/custom-LPs-NCES.ipynb @@ -1,24 +1,25 @@ { "cells": [ { + "attachments": {}, "cell_type": "markdown", - "id": "african-gates", + "id": "supposed-stone", "metadata": {}, "source": [ - "From the main directory \"Ontolearn\", run `./big_gitext/download_nces_data` to download pretrained models and datasets" + "From the main directory \"Ontolearn\", run the commands for NCES data in [`./download_external_resources.sh`](../download_external_resources.sh) to download pretrained models and datasets." ] }, { "cell_type": "code", - "execution_count": 2, - "id": "seventh-hawaiian", + "execution_count": 1, + "id": "conceptual-dryer", "metadata": {}, "outputs": [], "source": [ "from ontolearn.concept_learner import NCES\n", "from ontolearn.knowledge_base import KnowledgeBase\n", - "from owlapy.parser import DLSyntaxParser\n", - "from owlapy.render import DLSyntaxObjectRenderer\n", + "from ontolearn.owlapy.parser import DLSyntaxParser\n", + "from ontolearn.owlapy.render import DLSyntaxObjectRenderer\n", "import sys\n", "sys.path.append(\"examples/\")\n", "from quality_functions import quality\n", @@ -29,7 +30,7 @@ { "cell_type": "code", "execution_count": 4, - "id": "quiet-apple", + "id": "fifth-nomination", "metadata": {}, "outputs": [ { @@ -51,7 +52,7 @@ { "cell_type": "code", "execution_count": 5, - "id": "tested-reviewer", + "id": "juvenile-serial", "metadata": {}, "outputs": [], "source": [ @@ -61,7 +62,7 @@ { "cell_type": "code", "execution_count": 6, - "id": "fifty-utilization", + "id": "reasonable-ecuador", "metadata": {}, "outputs": [], "source": [ @@ -71,7 +72,7 @@ { "cell_type": "code", "execution_count": 7, - "id": "extensive-cleaner", + "id": "capable-threat", "metadata": {}, "outputs": [], "source": [ @@ -81,7 +82,7 @@ { "cell_type": "code", "execution_count": 8, - "id": "expensive-essay", + "id": "reverse-hostel", "metadata": {}, "outputs": [ { @@ -119,7 +120,7 @@ { "cell_type": "code", "execution_count": 9, - "id": "previous-requirement", + "id": "harmful-forge", "metadata": {}, "outputs": [], "source": [ @@ -129,7 +130,7 @@ { "cell_type": "code", "execution_count": 10, - "id": "processed-frame", + "id": "first-trademark", "metadata": {}, "outputs": [], "source": [ @@ -138,8 +139,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "legitimate-mailman", + "id": "completed-laugh", "metadata": {}, "source": [ "#### Input examples can be sets or lists" @@ -148,7 +150,7 @@ { "cell_type": "code", "execution_count": 11, - "id": "inappropriate-classic", + "id": "checked-internship", "metadata": {}, "outputs": [], "source": [ @@ -158,7 +160,7 @@ { "cell_type": "code", "execution_count": 12, - "id": "available-alloy", + "id": "ready-pickup", "metadata": {}, "outputs": [], "source": [ @@ -166,8 +168,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "geological-packing", + "id": "weekly-translator", "metadata": {}, "source": [ "#### Prediction with SetTransformer (default model)" @@ -176,7 +179,7 @@ { "cell_type": "code", "execution_count": 13, - "id": "headed-frederick", + "id": "furnished-lebanon", "metadata": {}, "outputs": [ { @@ -199,7 +202,7 @@ { "cell_type": "code", "execution_count": 14, - "id": "incorporated-walker", + "id": "desperate-allah", "metadata": {}, "outputs": [ { @@ -218,8 +221,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "interstate-government", + "id": "asian-sample", "metadata": {}, "source": [ "### Ensemble prediction" @@ -228,7 +232,7 @@ { "cell_type": "code", "execution_count": 14, - "id": "political-missouri", + "id": "demographic-mounting", "metadata": {}, "outputs": [ { @@ -265,7 +269,7 @@ { "cell_type": "code", "execution_count": 15, - "id": "tired-recall", + "id": "measured-victor", "metadata": {}, "outputs": [ { @@ -286,22 +290,24 @@ { "cell_type": "code", "execution_count": null, - "id": "funky-newton", + "id": "sublime-legislature", "metadata": {}, "outputs": [], "source": [] }, { + "attachments": {}, "cell_type": "markdown", - "id": "utility-arrow", + "id": "inclusive-officer", "metadata": {}, "source": [ "### Complex learning problems, potentially without an exact solution" ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "polyphonic-wrist", + "id": "latest-consolidation", "metadata": {}, "source": [ "#### First learning problem" @@ -310,7 +316,7 @@ { "cell_type": "code", "execution_count": 16, - "id": "advisory-orientation", + "id": "impaired-likelihood", "metadata": {}, "outputs": [], "source": [ @@ -323,7 +329,7 @@ { "cell_type": "code", "execution_count": 17, - "id": "civil-market", + "id": "centered-controversy", "metadata": {}, "outputs": [ { @@ -344,7 +350,7 @@ { "cell_type": "code", "execution_count": 18, - "id": "extreme-pocket", + "id": "young-europe", "metadata": {}, "outputs": [ { @@ -367,7 +373,7 @@ { "cell_type": "code", "execution_count": 19, - "id": "juvenile-stretch", + "id": "breeding-cooler", "metadata": {}, "outputs": [ { @@ -386,8 +392,9 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "vital-whale", + "id": "latin-import", "metadata": {}, "source": [ "#### Second learning problem" @@ -396,7 +403,7 @@ { "cell_type": "code", "execution_count": 20, - "id": "single-respect", + "id": "delayed-diabetes", "metadata": {}, "outputs": [], "source": [ @@ -408,7 +415,7 @@ { "cell_type": "code", "execution_count": 21, - "id": "initial-providence", + "id": "referenced-aquatic", "metadata": {}, "outputs": [ { @@ -431,7 +438,7 @@ { "cell_type": "code", "execution_count": 22, - "id": "tough-worst", + "id": "anonymous-declaration", "metadata": {}, "outputs": [ { @@ -452,14 +459,15 @@ { "cell_type": "code", "execution_count": null, - "id": "desperate-advocate", + "id": "prompt-sodium", "metadata": {}, "outputs": [], "source": [] }, { + "attachments": {}, "cell_type": "markdown", - "id": "arctic-local", + "id": "killing-percentage", "metadata": {}, "source": [ "## Important note\n", @@ -474,7 +482,7 @@ { "cell_type": "code", "execution_count": null, - "id": "unauthorized-rolling", + "id": "ceramic-understanding", "metadata": {}, "outputs": [], "source": [] diff --git a/docs/usage/evolearner_notebook.ipynb b/examples/evolearner_notebook.ipynb similarity index 81% rename from docs/usage/evolearner_notebook.ipynb rename to examples/evolearner_notebook.ipynb index 10d086e5..a12792e5 100644 --- a/docs/usage/evolearner_notebook.ipynb +++ b/examples/evolearner_notebook.ipynb @@ -3,17 +3,17 @@ { "attachments": {}, "cell_type": "markdown", - "id": "5a271671", + "id": "unlike-landscape", "metadata": {}, "source": [ "# EvoLearner Notebook\n", - "This is a jupyter notebook file to execute [EvoLearner](ontolearn.concept_learner.EvoLearner) and generate predictive results. We recommend you to see the [concept learners](05_concept_learners.md) guide before continuing with the execution." + "This is a jupyter notebook file to execute [EvoLearner](ontolearn.concept_learner.EvoLearner) and generate predictive results. We recommend you to see the [concept learners](../docs/usage/06_concept_learners.md) guide before continuing with the execution. Also if you have not done it already, from the main directory \"Ontolearn\", run the commands for Datasets in [`./download_external_resources.sh`](../download_external_resources.sh) to download the datasets." ] }, { "cell_type": "code", "execution_count": 7, - "id": "99ebe420-afcf-47e5-825a-6c283692a481", + "id": "numerous-algorithm", "metadata": {}, "outputs": [], "source": [ @@ -21,14 +21,14 @@ "from ontolearn.knowledge_base import KnowledgeBase\n", "from ontolearn.concept_learner import EvoLearner\n", "from ontolearn.learning_problem import PosNegLPStandard\n", - "from owlapy.model import OWLNamedIndividual, IRI\n", + "from ontolearn.owlapy.model import OWLNamedIndividual, IRI\n", "from ontolearn.utils import setup_logging\n" ] }, { "attachments": {}, "cell_type": "markdown", - "id": "669cbecf", + "id": "direct-color", "metadata": {}, "source": [ "Open `uncle_lp.json` where we have stored the learning problem for the concept of 'Uncle' and the path to the 'family' ontology." @@ -37,18 +37,18 @@ { "cell_type": "code", "execution_count": 8, - "id": "bb20f1f4", + "id": "modular-trunk", "metadata": {}, "outputs": [], "source": [ - "with open('../../examples/uncle_lp.json') as json_file:\n", + "with open('uncle_lp.json') as json_file:\n", " settings = json.load(json_file)" ] }, { "attachments": {}, "cell_type": "markdown", - "id": "ccee8b03", + "id": "creative-necklace", "metadata": {}, "source": [ "Create an instance of the class `KnowledeBase` by using the path that is stored in `settings`." @@ -57,7 +57,7 @@ { "cell_type": "code", "execution_count": 9, - "id": "9f5839e5", + "id": "wanted-reward", "metadata": {}, "outputs": [], "source": [ @@ -67,16 +67,16 @@ { "attachments": {}, "cell_type": "markdown", - "id": "8dd9881f", + "id": "eleven-creation", "metadata": {}, "source": [ - "Retreive the IRIs of the positive and negative examples of Uncle from `settings` and create an instance of `PosNegLPStandard`. (more info about this [here](02_learning_problem.md))" + "Retreive the IRIs of the positive and negative examples of Uncle from `settings` and create an instance of `PosNegLPStandard`. (more info about this [here](../docs/usage/06_concept_learners.md#configure-the-learning-problem))" ] }, { "cell_type": "code", "execution_count": 10, - "id": "2661a3eb", + "id": "entitled-cooling", "metadata": {}, "outputs": [], "source": [ @@ -91,7 +91,7 @@ { "attachments": {}, "cell_type": "markdown", - "id": "985f6a2d", + "id": "clear-tracy", "metadata": {}, "source": [ "Create a model of EvoLearner and fit the learning problem to the model." @@ -100,7 +100,7 @@ { "cell_type": "code", "execution_count": 14, - "id": "4ef6c110", + "id": "prescribed-explosion", "metadata": {}, "outputs": [ { @@ -122,7 +122,7 @@ { "attachments": {}, "cell_type": "markdown", - "id": "96ecb16c", + "id": "exempt-monaco", "metadata": {}, "source": [ "Retrieve top 3 hypotheses and print them." @@ -131,7 +131,7 @@ { "cell_type": "code", "execution_count": 12, - "id": "94cef573", + "id": "proud-dependence", "metadata": {}, "outputs": [ { @@ -162,7 +162,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -176,7 +176,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.16" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/examples/example_reasoner.py b/examples/example_reasoner.py index b1b55e17..a2878ef3 100644 --- a/examples/example_reasoner.py +++ b/examples/example_reasoner.py @@ -1,4 +1,5 @@ -from ontolearn.owlapy.model import OWLSubClassOfAxiom, OWLEquivalentObjectPropertiesAxiom, OWLObjectPropertyDomainAxiom, OWLDataProperty +from ontolearn.owlapy.model import OWLSubClassOfAxiom, OWLEquivalentObjectPropertiesAxiom, \ + OWLObjectPropertyDomainAxiom, OWLDataProperty from ontolearn.owlapy.owlready2 import OWLReasoner_Owlready2, BaseReasoner_Owlready2 from ontolearn.knowledge_base import KnowledgeBase from ontolearn.owlapy.model import OWLObjectProperty, IRI, OWLObjectSomeValuesFrom, \ @@ -9,8 +10,7 @@ NS = 'http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#' """ ----------Object Properties--------- - +---------Object Properties--------- Domain(r1) = S ⊓ T, Range(r1) = G r2 ⊑ r1 r3 ⊑ r4 @@ -18,12 +18,11 @@ r5 ⊓ r1 = ∅ r5 ≡ r6 ----------Data Properties--------- +---------Data Properties--------- dp2 ⊑ dp1 dp3 ⊓ dp1 = ∅ ---------Classes----------- - AB ≡ (A ⊓ B), AB ⊑ C D ⊑ (r7.E ⊓ B) F ≡ r2.G, F ⊑ H @@ -35,7 +34,6 @@ (S ⊓ T) ⊑ U ---------Individuals----------- - o is O p is P a is A ^ B @@ -53,7 +51,6 @@ ind1 has r5.q, r2.g, r6.(S ⊓ T) r is R s is S ^ T - """ a = OWLNamedIndividual(IRI(NS, "a")) @@ -287,13 +284,3 @@ debug_breakpoint = "Place a breakpoint at this line" - - - - - - - - - - diff --git a/docs/usage/ocel_notebook.ipynb b/examples/ocel_notebook.ipynb similarity index 82% rename from docs/usage/ocel_notebook.ipynb rename to examples/ocel_notebook.ipynb index e55fb711..618f07bb 100644 --- a/docs/usage/ocel_notebook.ipynb +++ b/examples/ocel_notebook.ipynb @@ -3,17 +3,17 @@ { "attachments": {}, "cell_type": "markdown", - "id": "5a271671", + "id": "verified-temple", "metadata": {}, "source": [ "# OCEL Notebook\n", - "This is a jupyter notebook file to execute [OCEL](ontolearn.concept_learner.OCEL) and generate predictive results. We recommend you to see the [concept learners](05_concept_learners.md) guide before continuing with the execution." + "This is a jupyter notebook file to execute [OCEL](ontolearn.concept_learner.OCEL) and generate predictive results. We recommend you to see the [concept learners](../docs/usage/06_concept_learners.md) guide before continuing with the execution. Also if you have not done it already, from the main directory \"Ontolearn\", run the commands for Datasets in [`./download_external_resources.sh`](../download_external_resources.sh) to download the datasets." ] }, { "cell_type": "code", "execution_count": 8, - "id": "99ebe420-afcf-47e5-825a-6c283692a481", + "id": "sustainable-poland", "metadata": {}, "outputs": [], "source": [ @@ -21,14 +21,14 @@ "from ontolearn.knowledge_base import KnowledgeBase\n", "from ontolearn.concept_learner import OCEL\n", "from ontolearn.learning_problem import PosNegLPStandard\n", - "from owlapy.model import OWLNamedIndividual, IRI\n", + "from ontolearn.owlapy.model import OWLNamedIndividual, IRI\n", "from ontolearn.utils import setup_logging\n" ] }, { "attachments": {}, "cell_type": "markdown", - "id": "669cbecf", + "id": "happy-colorado", "metadata": {}, "source": [ "Open `uncle_lp.json` where we have stored the learning problem for the concept of 'Uncle' and the path to the 'family' ontology." @@ -37,18 +37,18 @@ { "cell_type": "code", "execution_count": 9, - "id": "bb20f1f4", + "id": "buried-miami", "metadata": {}, "outputs": [], "source": [ - "with open('../../examples/uncle_lp.json') as json_file:\n", + "with open('uncle_lp.json') as json_file:\n", " settings = json.load(json_file)" ] }, { "attachments": {}, "cell_type": "markdown", - "id": "ccee8b03", + "id": "refined-yellow", "metadata": {}, "source": [ "Create an instance of the class `KnowledeBase` by using the path that is stored in `settings`." @@ -57,7 +57,7 @@ { "cell_type": "code", "execution_count": 10, - "id": "9f5839e5", + "id": "outdoor-player", "metadata": {}, "outputs": [], "source": [ @@ -67,16 +67,16 @@ { "attachments": {}, "cell_type": "markdown", - "id": "8dd9881f", + "id": "fabulous-sucking", "metadata": {}, "source": [ - "Retreive the IRIs of the positive and negative examples of Uncle from `settings` and create an instance of `PosNegLPStandard`. (more info about this [here](02_learning_problem.md))" + "Retreive the IRIs of the positive and negative examples of Uncle from `settings` and create an instance of `PosNegLPStandard`. (more info about this [here](../docs/usage/06_concept_learners.md#configure-the-learning-problem))" ] }, { "cell_type": "code", "execution_count": 11, - "id": "2661a3eb", + "id": "right-organizer", "metadata": {}, "outputs": [], "source": [ @@ -91,7 +91,7 @@ { "attachments": {}, "cell_type": "markdown", - "id": "985f6a2d", + "id": "earlier-peripheral", "metadata": {}, "source": [ "Create a model of [OCEL](ontolearn.concept_learner.CELOE) and fit the learning problem to the model." @@ -100,7 +100,7 @@ { "cell_type": "code", "execution_count": 12, - "id": "4ef6c110", + "id": "permanent-alabama", "metadata": {}, "outputs": [ { @@ -122,7 +122,7 @@ { "attachments": {}, "cell_type": "markdown", - "id": "96ecb16c", + "id": "future-elevation", "metadata": {}, "source": [ "Retrieve top 3 hypotheses and print them." @@ -131,7 +131,7 @@ { "cell_type": "code", "execution_count": 13, - "id": "94cef573", + "id": "incoming-debate", "metadata": {}, "outputs": [ { @@ -162,7 +162,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -176,7 +176,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.16" + "version": "3.9.12" } }, "nbformat": 4, diff --git a/examples/quality_functions.py b/examples/quality_functions.py index 570fe8fa..40b5e7ec 100644 --- a/examples/quality_functions.py +++ b/examples/quality_functions.py @@ -1,14 +1,18 @@ from ontolearn.metrics import F1, Accuracy, Precision, Recall + def quality(KB, solution, pos, neg): - f1 = F1().score2; accuracy = Accuracy().score2; precision = Precision().score2; recall = Recall().score2 + f1 = F1().score2 + accuracy = Accuracy().score2 + precision = Precision().score2 + recall = Recall().score2 instances = set(KB.individuals(solution)) if isinstance(list(pos)[0], str): instances = {ind.get_iri().as_str().split("/")[-1] for ind in instances} - tp=len(pos.intersection(instances)) - fn=len(pos.difference(instances)) - fp=len(neg.intersection(instances)) - tn=len(neg.difference(instances)) + tp = len(pos.intersection(instances)) + fn = len(pos.difference(instances)) + fp = len(neg.intersection(instances)) + tn = len(neg.difference(instances)) acc = 100*accuracy(tp, fn, fp, tn)[-1] prec = 100*precision(tp, fn, fp, tn)[-1] rec = 100*recall(tp, fn, fp, tn)[-1] @@ -17,4 +21,4 @@ def quality(KB, solution, pos, neg): print("Precision: {}%".format(prec)) print("Recall: {}%".format(rec)) print("F1: {}%".format(f_1)) - return acc, prec, rec, f_1 \ No newline at end of file + return acc, prec, rec, f_1 diff --git a/examples/simple-usage-NCES.ipynb b/examples/simple-usage-NCES.ipynb index 6ee51a88..6eab7ddc 100644 --- a/examples/simple-usage-NCES.ipynb +++ b/examples/simple-usage-NCES.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": 6, - "id": "nutritional-globe", + "id": "exclusive-politics", "metadata": {}, "outputs": [ { @@ -46,7 +46,7 @@ { "cell_type": "code", "execution_count": 1, - "id": "banned-dealer", + "id": "portable-english", "metadata": {}, "outputs": [ { @@ -79,9 +79,10 @@ "source": [ "from ontolearn.concept_learner import NCES\n", "from ontolearn.knowledge_base import KnowledgeBase\n", - "from owlapy.parser import DLSyntaxParser\n", - "from owlapy.render import DLSyntaxObjectRenderer\n", + "from ontolearn.owlapy.parser import DLSyntaxParser\n", + "from ontolearn.owlapy.render import DLSyntaxObjectRenderer\n", "import sys\n", + "sys.path.append(\"examples/\")\n", "from quality_functions import quality\n", "import time\n", "\n", @@ -113,7 +114,7 @@ { "cell_type": "code", "execution_count": null, - "id": "iraqi-might", + "id": "executive-opera", "metadata": {}, "outputs": [], "source": [] diff --git a/examples/train_nces.py b/examples/train_nces.py index 5253b029..a8b13a40 100644 --- a/examples/train_nces.py +++ b/examples/train_nces.py @@ -1,12 +1,12 @@ -""" +""" (1) To get the data: wget https://hobbitdata.informatik.uni-leipzig.de/NCES_Ontolearn_Data/NCESData.zip (2) pip install ontolearn """ -import os from ontolearn.concept_learner import NCES -import argparse, json +import argparse +import json def str2bool(v): @@ -18,7 +18,8 @@ def str2bool(v): return False else: raise ValueError('Invalid boolean value.') - + + parser = argparse.ArgumentParser() parser.add_argument('--kbs', type=str, nargs='+', default=['carcinogenesis'], help='Knowledge base name(s)') parser.add_argument('--models', type=str, nargs='+', default=['SetTransformer', 'LSTM', 'GRU'], help='Neural models') @@ -34,7 +35,8 @@ def str2bool(v): training_data = list(json.load(file).items()) nces = NCES(knowledge_base_path=knowledge_base_path, learner_name="SetTransformer", - path_of_embeddings=path_of_embeddings, max_length=48, proj_dim=128, rnn_n_layers=2, drop_prob=0.1, num_heads=4, num_seeds=1, num_inds=32, load_pretrained=args.load_pretrained) + path_of_embeddings=path_of_embeddings, max_length=48, proj_dim=128, rnn_n_layers=2, drop_prob=0.1, + num_heads=4, num_seeds=1, num_inds=32, load_pretrained=args.load_pretrained) for model in args.models: nces.learner_name = model diff --git a/examples/uncle_lp.json b/examples/uncle_lp.json index 09f88ff7..f8a71cb2 100644 --- a/examples/uncle_lp.json +++ b/examples/uncle_lp.json @@ -1,5 +1,5 @@ { - "data_path": "../../KGs/Family/family-benchmark_rich_background.owl", + "data_path": "../KGs/Family/family-benchmark_rich_background.owl", "Uncle": { "positive_examples": ["http://www.benchmark.org/family#F2M13" ,"http://www.benchmark.org/family#F2M11" diff --git a/ontolearn/__init__.py b/ontolearn/__init__.py index 225dca63..9a38ff2e 100644 --- a/ontolearn/__init__.py +++ b/ontolearn/__init__.py @@ -1,7 +1,7 @@ -"""Structured Machine learning modules for Python +"""Structured Machine learning modules for Python. -Ontolearn is an open-source software library for structured machine learning in Python -The goal of ontolearn is to provide efficient solutions for concept learning on RDF knowledge bases +Ontolearn is an open-source software library for structured machine learning in Python. +The goal of ontolearn is to provide efficient solutions for concept learning on RDF knowledge bases. Author: diff --git a/ontolearn/abstracts.py b/ontolearn/abstracts.py index 6207bf85..16eae08a 100644 --- a/ontolearn/abstracts.py +++ b/ontolearn/abstracts.py @@ -1,3 +1,5 @@ +"""The main abstract classes.""" + import logging from abc import ABCMeta, abstractmethod from typing import Set, List, Tuple, Iterable, TypeVar, Generic, ClassVar, Optional @@ -15,13 +17,17 @@ # @TODO:CD: Each Class definiton in abstract.py should share a prefix, e.g., BaseX or AbstractX. + class EncodedLearningProblem(metaclass=ABCMeta): - """Encoded Abstract learning problem for use in Scorers""" + """Encoded Abstract learning problem for use in Scorers.""" __slots__ = () + class EncodedPosNegLPStandardKind(EncodedLearningProblem, metaclass=ABCMeta): + """Encoded Abstract learning problem following pos-neg lp standard.""" __slots__ = () + # @TODO: Why we need Generic[_N] and if we need it why we di not use it in all other abstract classes? class AbstractScorer(Generic[_N], metaclass=ABCMeta): """ @@ -32,19 +38,19 @@ class AbstractScorer(Generic[_N], metaclass=ABCMeta): name: ClassVar[str] def __init__(self, *args, **kwargs): - """Create a new quality function""" + """Create a new quality function.""" pass - def score_elp(self, instances:set, learning_problem: EncodedLearningProblem) -> Tuple[bool, Optional[float]]: - """Quality score for a set of instances with regard to the learning problem + def score_elp(self, instances: set, learning_problem: EncodedLearningProblem) -> Tuple[bool, Optional[float]]: + """Quality score for a set of instances with regard to the learning problem. Args: - instances (set): instances to calculate a quality score for - learning_problem: underlying learning problem to compare the quality to + instances (set): Instances to calculate a quality score for. + learning_problem: Underlying learning problem to compare the quality to. Returns: Tuple, first position indicating if the function could be applied, second position the quality value - in the range 0.0--1.0 + in the range 0.0--1.0. """ if len(instances) == 0: return False, 0 @@ -63,28 +69,28 @@ def score_elp(self, instances:set, learning_problem: EncodedLearningProblem) -> @abstractmethod def score2(self, tp: int, fn: int, fp: int, tn: int) -> Tuple[bool, Optional[float]]: - """Quality score for a coverage count + """Quality score for a coverage count. Args: - tp: true positive count - fn: false negative count - fp: false positive count - tn: true negative count + tp: True positive count. + fn: False negative count. + fp: False positive count. + tn: True negative count. Returns: Tuple, first position indicating if the function could be applied, second position the quality value - in the range 0.0--1.0 + in the range 0.0--1.0. """ pass # @TODO:CD: Why there is '..' in AbstractNode def apply(self, node: 'AbstractNode', instances, learning_problem: EncodedLearningProblem) -> bool: - """Apply the quality function to a search tree node after calculating the quality score on the given instances + """Apply the quality function to a search tree node after calculating the quality score on the given instances. Args: - node: search tree node to set the quality on - instances (set): instances to calculate the quality for - learning_problem: underlying learning problem to compare the quality to + node: search tree node to set the quality on. + instances (set): Instances to calculate the quality for. + learning_problem: Underlying learning problem to compare the quality to. Returns: True if the quality function was applied successfully @@ -102,6 +108,7 @@ def apply(self, node: 'AbstractNode', instances, learning_problem: EncodedLearni node.quality = q return ret + class AbstractHeuristic(Generic[_N], metaclass=ABCMeta): """Abstract base class for heuristic functions. @@ -110,20 +117,21 @@ class AbstractHeuristic(Generic[_N], metaclass=ABCMeta): @abstractmethod def __init__(self): - """Create a new heuristic function""" + """Create a new heuristic function.""" pass @abstractmethod def apply(self, node: _N, instances, learning_problem: EncodedLearningProblem): - """Apply the heuristic on a search tree node and set its heuristic property to the calculated value + """Apply the heuristic on a search tree node and set its heuristic property to the calculated value. Args: - node: node to set the heuristic on - instances (set, optional): set of instances covered by this node - learning_problem: underlying learning problem to compare the heuristic to + node: Node to set the heuristic on. + instances (set, optional): Set of instances covered by this node. + learning_problem: Underlying learning problem to compare the heuristic to. """ pass + class AbstractFitness(metaclass=ABCMeta): """Abstract base class for fitness functions. @@ -134,15 +142,15 @@ class AbstractFitness(metaclass=ABCMeta): @abstractmethod def __init__(self): - """Create a new fitness function""" + """Create a new fitness function.""" pass @abstractmethod def apply(self, individual): - """Apply the fitness function on an individual and set its fitness attribute to the calculated value + """Apply the fitness function on an individual and set its fitness attribute to the calculated value. Args: - individual: individual to set the fitness on + individual: Individual to set the fitness on. """ pass @@ -165,9 +173,12 @@ class BaseRefinement(Generic[_N], metaclass=ABCMeta): *) Defining a top-down refimenent operator that is a proper is crutial. 4.1.3 Achieving Properness [1] - *) Figure 4.1 [1] defines of the refinement operator + *) Figure 4.1 [1] defines of the refinement operator. - [1] Learning OWL Class Expressions + [1] Learning OWL Class Expressions. + + Attributes: + kb (AbstractKnowledgeBase): The knowledge base used by this refinement operator. """ __slots__ = 'kb' @@ -175,117 +186,153 @@ class BaseRefinement(Generic[_N], metaclass=ABCMeta): @abstractmethod def __init__(self, knowledge_base: _KB): - """Construct a new base refinement operator + """Construct a new base refinement operator. Args: - knowledge_base: knowledge base to operate on + knowledge_base: Knowledge base to operate on. """ self.kb = knowledge_base @abstractmethod def refine(self, *args, **kwargs) -> Iterable[OWLClassExpression]: - """Refine a given concept + """Refine a given concept. Args: - ce (OWLClassExpression): concept to refine + ce (OWLClassExpression): Concept to refine. Returns: - new refined concepts + New refined concepts. """ pass def len(self, concept: OWLClassExpression) -> int: - """The length of a concept + """The length of a concept. Args: - concept: concept + concept: The concept to measure the length for. Returns: - length of concept according to some metric configured in the knowledge base + Length of concept according to some metric configured in the knowledge base. """ return self.kb.concept_len(concept) class AbstractNode(metaclass=ABCMeta): - """Abstract search tree node""" + """Abstract search tree node.""" __slots__ = () @abstractmethod def __init__(self): - """Create an abstract search tree node""" + """Create an abstract search tree node.""" pass def __str__(self): - """string representation of node, by default its internal memory address""" + """String representation of node, by default its internal memory address.""" addr = hex(id(self)) addr = addr[0:2] + addr[6:-1] return f'{type(self)} at {addr}' class AbstractOEHeuristicNode(metaclass=ABCMeta): - """Abstract Node for the CELOEHeuristic heuristic function + """Abstract Node for the CELOEHeuristic heuristic function. - This node must support quality, horizontal expansion (h_exp), is_root, parent_node and refinement_count + This node must support quality, horizontal expansion (h_exp), is_root, parent_node and refinement_count. """ __slots__ = () @property @abstractmethod def quality(self) -> Optional[float]: + """Get the quality of the node. + + Returns: + Quality of the node. + """ pass @property @abstractmethod def h_exp(self) -> int: + """Get horizontal expansion. + + Returns: + Horizontal expansion. + """ pass @property @abstractmethod def is_root(self) -> bool: + """Is this the root node? + + Returns: + True if this is the root node, otherwise False. + """ pass @property @abstractmethod def parent_node(self: _N) -> Optional[_N]: + """Get the parent node. + + Returns: + Parent node. + """ pass @property @abstractmethod def refinement_count(self) -> int: + """Get the refinement count for this node. + + Returns: + Refinement count. + """ pass @property @abstractmethod def heuristic(self) -> Optional[float]: + """Get the heuristic value. + + Returns: + Heuristic value. + """ pass @heuristic.setter @abstractmethod def heuristic(self, v: float): + """Set the heuristic value.""" pass class AbstractConceptNode(metaclass=ABCMeta): - """Abstract search tree node which has a concept""" + """Abstract search tree node which has a concept.""" __slots__ = () @property @abstractmethod def concept(self) -> OWLClassExpression: + """Get the concept representing this node. + + Returns: + The concept representing this node. + """ pass class AbstractKnowledgeBase(metaclass=ABCMeta): - """Abstract knowledge base""" + """Abstract knowledge base.""" __slots__ = () @abstractmethod def ontology(self) -> OWLOntology: - """The base ontology of this knowledge base""" + """The base ontology of this knowledge base.""" pass def describe(self) -> None: - """Print a short description of the Knowledge Base to the info logger output""" + """Print a short description of the Knowledge Base to the info logger output.""" properties_count = iter_count(self.ontology().object_properties_in_signature()) + iter_count( self.ontology().data_properties_in_signature()) logger.info(f'Number of named classes: {iter_count(self.ontology().classes_in_signature())}\n' @@ -294,12 +341,12 @@ def describe(self) -> None: @abstractmethod def clean(self) -> None: - """This method should reset any caches and statistics in the knowledge base""" + """This method should reset any caches and statistics in the knowledge base.""" raise NotImplementedError @abstractmethod def individuals_count(self) -> int: - """Total number of individuals in this knowledge base""" + """Total number of individuals in this knowledge base.""" pass @abstractmethod @@ -308,107 +355,107 @@ def individuals_set(self, *args, **kwargs) -> Set: into a set. Args: - arg (OWLNamedIndividual): individual to encode - arg (Iterable[OWLNamedIndividual]): individuals to encode - arg (OWLClassExpression): encode individuals that are instances of this concept + arg (OWLNamedIndividual): Individual to encode. + arg (Iterable[OWLNamedIndividual]): Individuals to encode. + arg (OWLClassExpression): Encode individuals that are instances of this concept. Returns: - encoded set representation of individual(s) + Encoded set representation of individual(s). """ pass @abstractmethod def concept_len(self, ce: OWLClassExpression) -> int: - """Calculate the length of a concept + """Calculate the length of a concept. Args: - ce: concept + ce: The concept to measure the length for. Returns: - length of the concept + Length of concept. """ pass class AbstractLearningProblem(metaclass=ABCMeta): - """Abstract learning problem""" + """Abstract learning problem.""" __slots__ = () @abstractmethod def __init__(self, *args, **kwargs): - """create a new abstract learning problem""" + """Create a new abstract learning problem.""" pass @abstractmethod def encode_kb(self, knowledge_base: AbstractKnowledgeBase) -> 'EncodedLearningProblem': - """encode the learning problem into the knowledge base""" + """Encode the learning problem into the knowledge base.""" pass class LBLSearchTree(Generic[_N], metaclass=ABCMeta): - """Abstract search tree for the Length based learner""" + """Abstract search tree for the Length based learner.""" @abstractmethod def get_most_promising(self) -> _N: - """Find most "promising" node in the search tree that should be refined next + """Find most "promising" node in the search tree that should be refined next. Returns: - most promising search tree node + Most promising search tree node. """ pass @abstractmethod def add_node(self, node: _N, parent_node: _N, kb_learning_problem: EncodedLearningProblem): - """Add a node to the search tree + """Add a node to the search tree. Args: - node: node to add - parent_node: parent of that node - kb_learning_problem: underlying learning problem to compare the quality to + node: Node to add. + parent_node: Parent of that node. + kb_learning_problem: Underlying learning problem to compare the quality to. """ pass @abstractmethod def clean(self): - """Reset the search tree state""" + """Reset the search tree state.""" pass @abstractmethod def get_top_n(self, n: int) -> List[_N]: - """Retrieve the best n search tree nodes + """Retrieve the best n search tree nodes. Args: - n: maximum number of nodes + n: Maximum number of nodes. Returns: - list of top n search tree nodes + List of top n search tree nodes. """ pass @abstractmethod def show_search_tree(self, root_concept: OWLClassExpression, heading_step: str): - """Debugging function to print the search tree to standard output + """Debugging function to print the search tree to standard output. Args: - root_concept: the tree is printed starting from this search tree node - heading_step: message to print at top of the output + root_concept: The tree is printed starting from this search tree node. + heading_step: Message to print at top of the output. """ pass @abstractmethod def add_root(self, node: _N, kb_learning_problem: EncodedLearningProblem): - """Add the root node to the search tree + """Add the root node to the search tree. Args: - node: root node to add - kb_learning_problem: underlying learning problem to compare the quality to + node: Root node to add. + kb_learning_problem: Underlying learning problem to compare the quality to. """ pass class AbstractDrill: """ - Abstract class for Convolutional DQL concept learning + Abstract class for Convolutional DQL concept learning. """ def __init__(self, path_of_embeddings, reward_func, learning_rate=None, @@ -479,20 +526,17 @@ def attributes_sanity_checking_rl(self): def init_training(self, *args, **kwargs): """ Initialize training for a given E+,E- and K. - @param args: - @param kwargs: - @return: """ @abstractmethod def terminate_training(self): """ Save weights and training data after training phase. - @return: """ class DRILLAbstractTree: + """Abstract Tree for DRILL.""" @abstractmethod def __init__(self): self._nodes = dict() @@ -566,9 +610,8 @@ def show_best_nodes(self, top_n, key=None): @staticmethod def save_current_top_n_nodes(key=None, n=10, path=None): - """ - Save current top_n nodes + Save current top_n nodes. """ assert path assert key diff --git a/ontolearn/base_concept_learner.py b/ontolearn/base_concept_learner.py index 1fe74e86..3677b975 100644 --- a/ontolearn/base_concept_learner.py +++ b/ontolearn/base_concept_learner.py @@ -1,3 +1,5 @@ +"""Base classes of concept learners.""" + import logging import time from abc import ABCMeta, abstractmethod @@ -12,7 +14,7 @@ from ontolearn.refinement_operators import ModifiedCELOERefinement from ontolearn.search import _NodeQuality -from ontolearn.owlapy.model import OWLDeclarationAxiom, OWLNamedIndividual, OWLOntologyManager, OWLOntology, AddImport, \ +from ontolearn.owlapy.model import OWLDeclarationAxiom, OWLNamedIndividual, OWLOntologyManager, OWLOntology, AddImport,\ OWLImportsDeclaration, OWLClass, OWLEquivalentClassesAxiom, OWLAnnotationAssertionAxiom, OWLAnnotation, \ OWLAnnotationProperty, OWLLiteral, IRI, OWLClassExpression, OWLReasoner, OWLAxiom, OWLThing from ontolearn.owlapy.owlready2 import OWLOntologyManager_Owlready2, OWLOntology_Owlready2 @@ -31,7 +33,7 @@ class BaseConceptLearner(Generic[_N], metaclass=ABCMeta): """ - Base class for Concept Learning approaches + Base class for Concept Learning approaches. Learning problem definition, Let * K = (TBOX, ABOX) be a knowledge base. @@ -49,6 +51,16 @@ class BaseConceptLearner(Generic[_N], metaclass=ABCMeta): The goal is to learn a set of concepts $\\hypotheses \\subseteq \\ALCConcepts$ such that ∀ H \\in \\hypotheses: { (K \\wedge H \\models E^+) \\wedge \\neg( K \\wedge H \\models E^-) }. + Attributes: + kb (KnowledgeBase): The knowledge base that the concept learner is using. + quality_func (AbstractScorer) The quality function to be used. + max_num_of_concepts_tested (int) Limit to stop the algorithm after n concepts tested. + terminate_on_goal (bool): Whether to stop the algorithm if a perfect solution is found. + max_runtime (int): Limit to stop the algorithm after n seconds. + _number_of_tested_concepts (int): Yes, you got it. This stores the number of tested concepts. + reasoner (OWLReasoner): The reasoner that this model is using. + start_time (float): The time when :meth:`fit` starts the execution. Used to calculate the total time :meth:`fit` + takes to execute. """ __slots__ = 'kb', 'reasoner', 'quality_func', 'max_num_of_concepts_tested', 'terminate_on_goal', 'max_runtime', \ 'start_time', '_goal_found', '_number_of_tested_concepts' @@ -75,14 +87,14 @@ def __init__(self, """Create a new base concept learner Args: - knowledge_base: knowledge base which is used to learn and test concepts. required, but can be taken - from the learning problem if not specified - quality_func: function to evaluate the quality of solution concepts. defaults to `F1` - max_num_of_concepts_tested: limit to stop the algorithm after n concepts tested. defaults to 10_000 - max_runtime: limit to stop the algorithm after n seconds. defaults to 5 - terminate_on_goal: whether to stop the algorithm if a perfect solution is found. defaults to True - reasoner: Optionally use a different reasoner. If reasoner=None, the knowledge base of the concept - learner is used. + knowledge_base: Knowledge base which is used to learn and test concepts. required, but can be taken + from the learning problem if not specified. + quality_func: Function to evaluate the quality of solution concepts. Defaults to `F1`. + max_num_of_concepts_tested: Limit to stop the algorithm after n concepts tested. Defaults to 10'000. + max_runtime: Limit to stop the algorithm after n seconds. Defaults to 5. + terminate_on_goal: Whether to stop the algorithm if a perfect solution is found. Defaults to True. + reasoner: Optionally use a different reasoner. If reasoner=None, the reasoner of the :attr:`knowledge_base` + is used. """ self.kb = knowledge_base self.reasoner = reasoner @@ -120,22 +132,27 @@ def __sanity_checking(self): @abstractmethod def clean(self): """ - Clear all states of the concept learner + Clear all states of the concept learner. """ self._number_of_tested_concepts = 0 self._goal_found = False self.start_time = None def train(self, *args, **kwargs): + """Train RL agent on learning problems. + + Returns: + self. + """ pass def terminate(self): - """This method is called when the search algorithm terminates + """This method is called when the search algorithm terminates. - If INFO log level is enabled, it prints out some statistics like runtime and concept tests to the logger + If INFO log level is enabled, it prints out some statistics like runtime and concept tests to the logger. Returns: - the concept learner object itself + The concept learner object itself. """ # if self.store_onto_flag: # self.store_ontology() @@ -157,12 +174,12 @@ def construct_learning_problem(self, type_: Type[_X], xargs: Tuple, xkwargs: Dic with args and kwargs as parameters. Args: - type_: type of the learning problem - xargs: the positional arguments - xkwargs: the keyword arguments + type_: Type of the learning problem. + xargs: The positional arguments. + xkwargs: The keyword arguments. Returns: - the learning problem + The learning problem. """ learning_problem = xkwargs.pop("learning_problem", None) if learning_problem is None and xargs and isinstance(xargs[0], AbstractLearningProblem): @@ -175,20 +192,20 @@ def construct_learning_problem(self, type_: Type[_X], xargs: Tuple, xkwargs: Dic @abstractmethod def fit(self, *args, **kwargs): - """Run the concept learning algorithm according to its configuration + """Run the concept learning algorithm according to its configuration. - Once finished, the results can be queried with the `best_hypotheses` function""" + Once finished, the results can be queried with the `best_hypotheses` function.""" pass @abstractmethod def best_hypotheses(self, n=10) -> Iterable[_N]: - """Get the current best found hypotheses according to the quality + """Get the current best found hypotheses according to the quality. Args: - n: Maximum number of results + n: Maximum number of results. Returns: - iterable with hypotheses in form of search tree nodes + Iterable with hypotheses in form of search tree nodes. """ pass @@ -204,7 +221,7 @@ def _assign_labels_to_individuals(self, individuals: List[OWLNamedIndividual], hypotheses: A list of class expressions. Returns: - matrix of \\|individuals\\| x \\|hypotheses\\| + Matrix of \\|individuals\\| x \\|hypotheses\\|. """ retrieval_func = self.kb.individuals_set if reasoner is None else reasoner.instances @@ -238,7 +255,7 @@ def predict(self, individuals: List[OWLNamedIndividual], Returns: Pandas data frame with dimensions |individuals|*|hypotheses| indicating for each individual and each - hypothesis whether the individual is entailed in the hypothesis + hypothesis whether the individual is entailed in the hypothesis. """ reasoner = self.reasoner new_individuals = set(individuals) - self.kb.individuals_set(OWLThing) @@ -279,12 +296,12 @@ def number_of_tested_concepts(self): return self._number_of_tested_concepts def save_best_hypothesis(self, n: int = 10, path: str = 'Predictions', rdf_format: str = 'rdfxml') -> None: - """Serialise the best hypotheses to a file + """Serialise the best hypotheses to a file. Args: - n: maximum number of hypotheses to save - path: filename base (extension will be added automatically) - rdf_format: serialisation format. currently supported: "rdfxml" + n: Maximum number of hypotheses to save. + path: Filename base (extension will be added automatically). + rdf_format: Serialisation format. currently supported: "rdfxml". """ SNS: Final = 'https://dice-research.org/predictions-schema/' NS: Final = 'https://dice-research.org/predictions/' + str(time.time()) + '#' @@ -328,10 +345,10 @@ def save_best_hypothesis(self, n: int = 10, path: str = 'Predictions', rdf_forma manager.save_ontology(ontology, IRI.create('file:/' + path + '.owl')) def load_hypotheses(self, path: str) -> Iterable[OWLClassExpression]: - """Loads hypotheses (class expressions) from a file saved by :func:`BaseConceptLearner.save_best_hypothesis` + """Loads hypotheses (class expressions) from a file saved by :func:`BaseConceptLearner.save_best_hypothesis`. Args: - path: Path to the file containing hypotheses + path: Path to the file containing hypotheses. """ manager: OWLOntologyManager_Owlready2 = OWLOntologyManager_Owlready2() ontology: OWLOntology_Owlready2 = manager.load_ontology(IRI.create('file://' + path)) @@ -344,7 +361,24 @@ def load_hypotheses(self, path: str) -> Iterable[OWLClassExpression]: class RefinementBasedConceptLearner(BaseConceptLearner[_N]): """ - Base class for refinement based Concept Learning approaches + Base class for refinement based Concept Learning approaches. + + Attributes: + kb (KnowledgeBase): The knowledge base that the concept learner is using. + quality_func (AbstractScorer) The quality function to be used. + max_num_of_concepts_tested (int) Limit to stop the algorithm after n concepts tested. + terminate_on_goal (bool): Whether to stop the algorithm if a perfect solution is found. + max_runtime (int): Limit to stop the algorithm after n seconds. + _number_of_tested_concepts (int): Yes, you got it. This stores the number of tested concepts. + reasoner (OWLReasoner): The reasoner that this model is using. + start_time (float): The time when :meth:`fit` starts the execution. Used to calculate the total time :meth:`fit` + takes to execute. + iter_bound (int): Limit to stop the algorithm after n refinement steps are done. + heuristic_func (AbstractHeuristic): Function to guide the search heuristic. + operator (BaseRefinement): Operator used to generate refinements. + start_class (OWLClassExpression): The starting class expression for the refinement operation. + max_child_length (int): Limit the length of concepts generated by the refinement operator. + """ __slots__ = 'operator', 'heuristic_func', 'max_child_length', 'start_class', 'iter_bound' @@ -368,21 +402,21 @@ def __init__(self, iter_bound: Optional[int] = None, max_child_length: Optional[int] = None, root_concept: Optional[OWLClassExpression] = None): - """Create a new base concept learner + """Create a new base concept learner. Args: - knowledge_base: knowledge base which is used to learn and test concepts. required, but can be taken - from the learning problem if not specified - refinement_operator: operator used to generate refinements. defaults to `ModifiedCELOERefinement` - heuristic_func: function to guide the search heuristic. defaults to `CELOEHeuristic` - quality_func: function to evaluate the quality of solution concepts. defaults to `F1` - max_num_of_concepts_tested: limit to stop the algorithm after n concepts tested. defaults to 10_000 - max_runtime: limit to stop the algorithm after n seconds. defaults to 5 - terminate_on_goal: whether to stop the algorithm if a perfect solution is found. defaults to True - iter_bound: limit to stop the algorithm after n refinement steps were done. defaults to 10_000 - max_child_length: limit the length of concepts generated by the refinement operator. defaults to 10. - only used if refinement_operator is not specified. - root_concept: the start concept to begin the search from. defaults to OWL Thing + knowledge_base: Knowledge base which is used to learn and test concepts. required, but can be taken + from the learning problem if not specified. + refinement_operator: Operator used to generate refinements. Defaults to `ModifiedCELOERefinement`. + heuristic_func: Function to guide the search heuristic. Defaults to `CELOEHeuristic`. + quality_func: Function to evaluate the quality of solution concepts. Defaults to `F1`. + max_num_of_concepts_tested: Limit to stop the algorithm after n concepts tested. Defaults to 10_000. + max_runtime: Limit to stop the algorithm after n seconds. Defaults to 5. + terminate_on_goal: Whether to stop the algorithm if a perfect solution is found. Defaults to True. + iter_bound: Limit to stop the algorithm after n refinement steps are done. Defaults to 10_000. + max_child_length: Limit the length of concepts generated by the refinement operator. defaults to 10. + Only used if refinement_operator is not specified. + root_concept: The start concept to begin the search from. Defaults to OWL Thing. """ super().__init__(knowledge_base=knowledge_base, reasoner=reasoner, @@ -431,32 +465,32 @@ def terminate(self): @abstractmethod def next_node_to_expand(self, *args, **kwargs): """ - Return from the search tree the most promising search tree node to use for the next refinement step + Return from the search tree the most promising search tree node to use for the next refinement step. Returns: - _N: next search tree node to refine + _N: Next search tree node to refine. """ pass @abstractmethod def downward_refinement(self, *args, **kwargs): - """execute one refinement step of a refinement based learning algorithm + """Execute one refinement step of a refinement based learning algorithm. Args: - node (_N): the search tree node on which to refine + node (_N): the search tree node on which to refine. Returns: - Iterable[_N]: refinement results as new search tree nodes (they still need to be added to the tree) + Iterable[_N]: Refinement results as new search tree nodes (they still need to be added to the tree). """ pass @abstractmethod def show_search_tree(self, heading_step: str, top_n: int = 10) -> None: """A debugging function to print out the current search tree and the current n best found hypotheses to - standard output + standard output. Args: - heading_step: a message to display at the beginning of the output - top_n: the number of currently best hypotheses to print out + heading_step: A message to display at the beginning of the output. + top_n: The number of current best hypotheses to print out. """ pass diff --git a/ontolearn/base_nces.py b/ontolearn/base_nces.py index 5db9ad63..e6176cf7 100644 --- a/ontolearn/base_nces.py +++ b/ontolearn/base_nces.py @@ -1,3 +1,5 @@ +"""The base class of NCES.""" + from ontolearn.knowledge_base import KnowledgeBase from ontolearn.owlapy.render import DLSyntaxObjectRenderer import numpy as np @@ -6,9 +8,11 @@ from .utils import read_csv from abc import abstractmethod + class BaseNCES: - - def __init__(self, knowledge_base_path, learner_name, path_of_embeddings, batch_size=256, learning_rate=1e-4, decay_rate=0.0, clip_value=5.0, num_workers=8): + + def __init__(self, knowledge_base_path, learner_name, path_of_embeddings, batch_size=256, learning_rate=1e-4, + decay_rate=0.0, clip_value=5.0, num_workers=8): self.name = "NCES" kb = KnowledgeBase(path=knowledge_base_path) self.kb_namespace = list(kb.ontology().classes_in_signature())[0].get_iri().get_namespace() @@ -23,7 +27,7 @@ def __init__(self, knowledge_base_path, learner_name, path_of_embeddings, batch_ self.kb = kb self.all_individuals = set([ind.get_iri().as_str().split("/")[-1] for ind in kb.individuals()]) self.inv_vocab = np.array(vocab, dtype='object') - self.vocab = {vocab[i]:i for i in range(len(vocab))} + self.vocab = {vocab[i]: i for i in range(len(vocab))} self.learner_name = learner_name self.num_examples = self.find_optimal_number_of_examples(kb) self.batch_size = batch_size @@ -33,13 +37,13 @@ def __init__(self, knowledge_base_path, learner_name, path_of_embeddings, batch_ self.num_workers = num_workers self.instance_embeddings = read_csv(path_of_embeddings) self.input_size = self.instance_embeddings.shape[1] - - @staticmethod + + @staticmethod def find_optimal_number_of_examples(kb): if kb.individuals_count() >= 600: return min(kb.individuals_count()//2, 1000) return kb.individuals_count() - + def collate_batch(self, batch): pos_emb_list = [] neg_emb_list = [] @@ -58,7 +62,7 @@ def collate_batch(self, batch): neg_emb_list = pad_sequence(neg_emb_list, batch_first=True, padding_value=0) target_labels = pad_sequence(target_labels, batch_first=True, padding_value=-100) return pos_emb_list, neg_emb_list, target_labels - + def collate_batch_inference(self, batch): pos_emb_list = [] neg_emb_list = [] @@ -74,11 +78,11 @@ def collate_batch_inference(self, batch): neg_emb_list[0] = F.pad(neg_emb_list[0], (0, 0, 0, self.num_examples - neg_emb_list[0].shape[0]), "constant", 0) neg_emb_list = pad_sequence(neg_emb_list, batch_first=True, padding_value=0) return pos_emb_list, neg_emb_list - - @abstractmethod + + @abstractmethod def get_synthesizer(self): pass - + @abstractmethod def load_pretrained(self): - pass \ No newline at end of file + pass diff --git a/ontolearn/binders.py b/ontolearn/binders.py index 203a953b..b159dab7 100644 --- a/ontolearn/binders.py +++ b/ontolearn/binders.py @@ -1,3 +1,4 @@ +"""Pyhon binders of other concept learners.""" import subprocess from datetime import datetime from typing import List, Dict @@ -28,11 +29,14 @@ def __init__(self, binary_path=None, model=None, kb_path=None, max_runtime=3): self.config_name_identifier = None def write_dl_learner_config(self, pos: List[str], neg: List[str]) -> str: - """ - Writes config file for dl-learner. - @param pos: A list of URIs of individuals indicating positive examples in concept learning problem. - @param neg: A list of URIs of individuals indicating negatives examples in concept learning problem. - @return: path of generated config file. + """Writes config file for dl-learner. + + Args: + pos: A list of URIs of individuals indicating positive examples in concept learning problem. + neg: A list of URIs of individuals indicating negatives examples in concept learning problem. + + Returns: + str: Path of generated config file. """ assert len(pos) > 0 assert len(neg) > 0 @@ -106,12 +110,15 @@ def write_dl_learner_config(self, pos: List[str], neg: List[str]) -> str: return pathToConfig def fit(self, pos: List[str], neg: List[str], max_runtime: int = None): - """ - Fit dl-learner model on a given positive and negative examples. - @param pos: A list of URIs of individuals indicating positive examples in concept learning problem - @param neg: A list of URIs of individuals indicating negatives examples in concept learning problem. - @param max_runtime: - @return: self. + """Fit dl-learner model on a given positive and negative examples. + + Args: + pos: A list of URIs of individuals indicating positive examples in concept learning problem. + neg: A list of URIs of individuals indicating negatives examples in concept learning problem. + max_runtime: Limit to stop the algorithm after n seconds. + + Returns: + self. """ try: assert len(pos) > 0 @@ -131,18 +138,25 @@ def fit(self, pos: List[str], neg: List[str], max_runtime: int = None): return self def best_hypothesis(self): - """ - return predictions if exists. + """ Return predictions if exists. + + Returns: + The prediction or the string 'No prediction found.' """ if self.best_predictions: return self.best_predictions else: - print('Not prediction found.') + print('No prediction found.') - def parse_dl_learner_output(self, output_of_dl_learner, file_path) -> Dict: - """ - Parse the output received from executing dl-learner. - @return: A dictionary of {'Prediction': ..., 'Accuracy': ..., 'F-measure': ...} + def parse_dl_learner_output(self, output_of_dl_learner: List[str], file_path: str) -> Dict: + """Parse the output received from executing dl-learner. + + Args: + output_of_dl_learner: The output of dl-learner to parse. + file_path: The file path to store the output. + + Returns: + A dictionary of {'Prediction': ..., 'Accuracy': ..., 'F-measure': ...}. """ solutions = None best_concept_str = None @@ -275,17 +289,20 @@ def parse_dl_learner_output(self, output_of_dl_learner, file_path) -> Dict: @staticmethod def train(dataset: List = None) -> None: - """ do nothing """ + """ Dummy method, currently it does nothing.""" def fit_from_iterable(self, dataset: List = None, max_runtime=None) -> List[Dict]: - """ - Fit dl-learner model on a list of given positive and negative examples. - @param dataset:A list of tuple (s,p,n) where - s => string representation of target concept - p => positive examples, i.e. s(p)=1. - n => negative examples, i.e. s(n)=0. - @param max_runtime: - @return: + """Fit dl-learner model on a list of given positive and negative examples. + + Args: + dataset: A list of tuple (s,p,n) where + s => string representation of target concept, + p => positive examples, i.e. s(p)=1 and + n => negative examples, i.e. s(n)=0. + max_runtime: Limit to stop the algorithm after n seconds. + + Returns: + self. """ assert len(dataset) > 0 if max_runtime: diff --git a/ontolearn/concept_generator.py b/ontolearn/concept_generator.py index a708403d..7e6611f1 100644 --- a/ontolearn/concept_generator.py +++ b/ontolearn/concept_generator.py @@ -1,3 +1,5 @@ +"""A module to generate concepts.""" + from typing import Iterable, List, Generator from ontolearn.utils import parametrized_performance_debugger @@ -9,17 +11,17 @@ class ConceptGenerator: - """A class that can generate some sorts of OWL Class Expressions""" + """A class that can generate some sorts of OWL Class Expressions.""" @parametrized_performance_debugger() def negation_from_iterables(self, class_expressions: Iterable[OWLClassExpression]): - """Negate a sequence of Class Expressions + """Negate a sequence of Class Expressions. Args: - class_expressions: iterable of class expressions to negate + class_expressions: Iterable of class expressions to negate. Returns: - negated form of input + Negated form of input. { x \\| ( x \\equv not s} """ for item in class_expressions: @@ -29,7 +31,7 @@ def negation_from_iterables(self, class_expressions: Iterable[OWLClassExpression @staticmethod def intersect_from_iterables(a_operands: Iterable[OWLClassExpression], b_operands: Iterable[OWLClassExpression]) \ -> Iterable[OWLObjectIntersectionOf]: - """ Create an intersection of each class expression in a_operands with each class expression in b_operands""" + """ Create an intersection of each class expression in a_operands with each class expression in b_operands.""" assert isinstance(a_operands, Generator) is False and isinstance(b_operands, Generator) is False seen = set() # TODO: if input sizes say 10^4, we can employ multiprocessing @@ -45,7 +47,7 @@ def intersect_from_iterables(a_operands: Iterable[OWLClassExpression], b_operand @staticmethod def union_from_iterables(a_operands: Iterable[OWLClassExpression], b_operands: Iterable[OWLClassExpression]) -> Iterable[OWLObjectUnionOf]: - """ Create an union of each class expression in a_operands with each class expression in b_operands""" + """ Create an union of each class expression in a_operands with each class expression in b_operands.""" assert (isinstance(a_operands, Generator) is False) and (isinstance(b_operands, Generator) is False) # TODO: if input sizes say 10^4, we can employ multiprocessing seen = set() @@ -60,13 +62,13 @@ def union_from_iterables(a_operands: Iterable[OWLClassExpression], # noinspection PyMethodMayBeStatic def intersection(self, ops: Iterable[OWLClassExpression]) -> OWLObjectIntersectionOf: - """Create intersection of class expression + """Create intersection of class expression. Args: - ops: operands of the intersection + ops: Operands of the intersection. Returns: - intersection with all operands (intersections are merged) + Intersection with all operands (intersections are merged). """ # TODO CD: I would rather prefer def intersection(self, a: OWLClassExpression, b: OWLClassExpression). This is # TODO CD: more advantages as one does not need to create a tuple of a list before intersection two expressions. @@ -82,13 +84,13 @@ def intersection(self, ops: Iterable[OWLClassExpression]) -> OWLObjectIntersecti # noinspection PyMethodMayBeStatic def union(self, ops: Iterable[OWLClassExpression]) -> OWLObjectUnionOf: - """Create union of class expressions + """Create union of class expressions. Args: - ops: operands of the union + ops: Operands of the union Returns: - union with all operands (unions are merged) + Union with all operands (unions are merged). """ operands: List[OWLClassExpression] = [] for c in ops: @@ -103,14 +105,14 @@ def union(self, ops: Iterable[OWLClassExpression]) -> OWLObjectUnionOf: # noinspection PyMethodMayBeStatic def existential_restriction(self, filler: OWLClassExpression, property: OWLObjectPropertyExpression) \ -> OWLObjectSomeValuesFrom: - """Create existential restriction + """Create existential restriction. Args: - property: property - filler: filler of the restriction + property: Property. + filler: Filler of the restriction. Returns: - existential restriction + Existential restriction. """ assert isinstance(property, OWLObjectPropertyExpression) return OWLObjectSomeValuesFrom(property=property, filler=filler) @@ -118,11 +120,11 @@ def existential_restriction(self, filler: OWLClassExpression, property: OWLObjec # noinspection PyMethodMayBeStatic def universal_restriction(self, filler: OWLClassExpression, property: OWLObjectPropertyExpression) \ -> OWLObjectAllValuesFrom: - """Create universal restriction + """Create universal restriction. Args: - property: property - filler: filler of the restriction + property: Property. + filler: Filler of the restriction. Returns: universal restriction @@ -132,14 +134,14 @@ def universal_restriction(self, filler: OWLClassExpression, property: OWLObjectP def has_value_restriction(self, individual: OWLIndividual, property: OWLObjectPropertyExpression) \ -> OWLObjectHasValue: - """Create object has value restriction + """Create object has value restriction. Args: - property: property - individual: individual of the restriction + property: Property. + individual: Individual of the restriction. Returns: - object has value restriction + Object has value restriction. """ assert isinstance(property, OWLObjectPropertyExpression) return OWLObjectHasValue(property=property, individual=individual) @@ -147,15 +149,15 @@ def has_value_restriction(self, individual: OWLIndividual, property: OWLObjectPr def min_cardinality_restriction(self, filler: OWLClassExpression, property: OWLObjectPropertyExpression, card: int) \ -> OWLObjectMinCardinality: - """Create min cardinality restriction + """Create min cardinality restriction. Args: - filler: filler of the restriction - property: property - card: cardinality of the restriction + filler: Filler of the restriction. + property: Property. + card: Cardinality of the restriction. Returns: - min cardinality restriction + Min cardinality restriction. """ assert isinstance(property, OWLObjectPropertyExpression) return OWLObjectMinCardinality(cardinality=card, property=property, filler=filler) @@ -163,15 +165,15 @@ def min_cardinality_restriction(self, filler: OWLClassExpression, def max_cardinality_restriction(self, filler: OWLClassExpression, property: OWLObjectPropertyExpression, card: int) \ -> OWLObjectMaxCardinality: - """Create max cardinality restriction + """Create max cardinality restriction. Args: - filler: filler of the restriction - property: property - card: cardinality of the restriction + filler: Filler of the restriction. + property: Property. + card: Cardinality of the restriction. Returns: - max cardinality restriction + Max cardinality restriction. """ assert isinstance(property, OWLObjectPropertyExpression) return OWLObjectMaxCardinality(cardinality=card, property=property, filler=filler) @@ -179,69 +181,69 @@ def max_cardinality_restriction(self, filler: OWLClassExpression, def exact_cardinality_restriction(self, filler: OWLClassExpression, property: OWLObjectPropertyExpression, card: int) \ -> OWLObjectExactCardinality: - """Create exact cardinality restriction + """Create exact cardinality restriction. Args: - filler: filler of the restriction - property: property - card: cardinality of the restriction + filler: Filler of the restriction. + property: Property. + card: Cardinality of the restriction. Returns: - exact cardinality restriction + Exact cardinality restriction. """ assert isinstance(property, OWLObjectPropertyExpression) return OWLObjectExactCardinality(cardinality=card, property=property, filler=filler) def data_existential_restriction(self, filler: OWLDataRange, property: OWLDataPropertyExpression) \ -> OWLDataSomeValuesFrom: - """Create data existential restriction + """Create data existential restriction. Args: - filler: filler of the restriction - property: property + filler: Filler of the restriction. + property: Property. Returns: - data existential restriction + Data existential restriction. """ assert isinstance(property, OWLDataPropertyExpression) return OWLDataSomeValuesFrom(property=property, filler=filler) def data_universal_restriction(self, filler: OWLDataRange, property: OWLDataPropertyExpression) \ -> OWLDataAllValuesFrom: - """Create data universal restriction + """Create data universal restriction. Args: - filler: filler of the restriction - property: property + filler: Filler of the restriction. + property: Property. Returns: - data universal restriction + Data universal restriction. """ assert isinstance(property, OWLDataPropertyExpression) return OWLDataAllValuesFrom(property=property, filler=filler) def data_has_value_restriction(self, value: OWLLiteral, property: OWLDataPropertyExpression) \ -> OWLDataHasValue: - """Create data has value restriction + """Create data has value restriction. Args: - value: value of the restriction - property: property + value: Value of the restriction. + property: Property. Returns: - data has value restriction + Data has value restriction. """ assert isinstance(property, OWLDataPropertyExpression) return OWLDataHasValue(property=property, value=value) def negation(self, concept: OWLClassExpression) -> OWLClassExpression: - """Create negation of a concept + """Create negation of a concept. Args: - concept: class expression + concept: Class expression. Returns: - negation of concept + Negation of concept. """ if concept.is_owl_thing(): return self.nothing @@ -252,10 +254,10 @@ def negation(self, concept: OWLClassExpression) -> OWLClassExpression: @property def thing(self) -> OWLClass: - """OWL Thing""" + """OWL Thing.""" return OWLThing @property def nothing(self) -> OWLClass: - """OWL Nothing""" - return OWLNothing \ No newline at end of file + """OWL Nothing.""" + return OWLNothing diff --git a/ontolearn/concept_learner.py b/ontolearn/concept_learner.py index 0967c364..e442cd92 100644 --- a/ontolearn/concept_learner.py +++ b/ontolearn/concept_learner.py @@ -1,3 +1,5 @@ +"""Concept learning algorithms of Ontolearn.""" + import logging import operator import random @@ -20,7 +22,8 @@ AbstractHeuristic, EncodedPosNegLPStandardKind from ontolearn.base_concept_learner import BaseConceptLearner, RefinementBasedConceptLearner from ontolearn.core.owl.utils import EvaluatedDescriptionSet, ConceptOperandSorter, OperandSetTransform -from ontolearn.data_struct import PrepareBatchOfTraining, PrepareBatchOfPrediction, NCESDataLoader, NCESDataLoaderInference +from ontolearn.data_struct import PrepareBatchOfTraining, PrepareBatchOfPrediction, NCESDataLoader, \ + NCESDataLoaderInference from ontolearn.ea_algorithms import AbstractEvolutionaryAlgorithm, EASimple from ontolearn.ea_initialization import AbstractEAInitialization, EARandomInitialization, EARandomWalkInitialization from ontolearn.ea_utils import PrimitiveFactory, OperatorVocabulary, ToolboxVocabulary, Tree, escape, ind_to_string, \ @@ -54,6 +57,33 @@ class CELOE(RefinementBasedConceptLearner[OENode]): + """Class Expression Learning for Ontology Engineering. + + Attributes: + best_descriptions (EvaluatedDescriptionSet[OENode, QualityOrderedNode]): Best hypotheses ordered. + best_only (bool): If False pick only nodes with quality < 1.0, else pick without quality restrictions. + calculate_min_max (bool): Calculate minimum and maximum horizontal expansion? Statistical purpose only. + heuristic_func (AbstractHeuristic): Function to guide the search heuristic. + heuristic_queue (SortedSet[OENode]): A sorted set that compares the nodes based on Heuristic. + iter_bound (int): Limit to stop the algorithm after n refinement steps are done. + kb (KnowledgeBase): The knowledge base that the concept learner is using. + max_child_length (int): Limit the length of concepts generated by the refinement operator. + max_he (int): Maximal value of horizontal expansion. + max_num_of_concepts_tested (int) Limit to stop the algorithm after n concepts tested. + max_runtime (int): Limit to stop the algorithm after n seconds. + min_he (int): Minimal value of horizontal expansion. + name (str): Name of the model = 'celoe_python'. + _number_of_tested_concepts (int): Yes, you got it. This stores the number of tested concepts. + operator (BaseRefinement): Operator used to generate refinements. + quality_func (AbstractScorer) The quality function to be used. + reasoner (OWLReasoner): The reasoner that this model is using. + search_tree (Dict[OWLClassExpression, TreeNode[OENode]]): Dict to store the TreeNode for a class expression. + start_class (OWLClassExpression): The starting class expression for the refinement operation. + start_time (float): The time when :meth:`fit` starts the execution. Used to calculate the total time :meth:`fit` + takes to execute. + terminate_on_goal (bool): Whether to stop the algorithm if a perfect solution is found. + + """ __slots__ = 'best_descriptions', 'max_he', 'min_he', 'best_only', 'calculate_min_max', 'heuristic_queue', \ 'search_tree', '_learning_problem', '_max_runtime', '_seen_norm_concepts' @@ -84,6 +114,28 @@ def __init__(self, max_results: int = 10, best_only: bool = False, calculate_min_max: bool = True): + """ Create a new instance of CELOE. + + Args: + best_only (bool): If False pick only nodes with quality < 1.0, else pick without quality restrictions. + Defaults to False. + calculate_min_max (bool): Calculate minimum and maximum horizontal expansion? Statistical purpose only. + Defaults to True. + refinement_operator (BaseRefinement[OENode]): Operator used to generate refinements. + Defaults to `ModifiedCELOERefinement`. + heuristic_func (AbstractHeuristic): Function to guide the search heuristic. Defaults to `CELOEHeuristic`. + iter_bound (int): Limit to stop the algorithm after n refinement steps are done. Defaults to 10'000. + knowledge_base (KnowledgeBase): The knowledge base that the concept learner is using. + max_num_of_concepts_tested (int) Limit to stop the algorithm after n concepts tested. Defaults to 10'000. + max_runtime (int): Limit to stop the algorithm after n seconds. Defaults to 5. + max_results (int): Maximum hypothesis to store. Defaults to 10. + quality_func (AbstractScorer) The quality function to be used. Defaults to `F1`. + reasoner (OWLReasoner): Optionally use a different reasoner. If reasoner=None, the reasoner of + the :attr:`knowledge_base` is used. + terminate_on_goal (bool): Whether to stop the algorithm if a perfect solution is found. Defaults to True. + + + """ super().__init__(knowledge_base=knowledge_base, reasoner=reasoner, refinement_operator=refinement_operator, @@ -132,11 +184,31 @@ def best_hypotheses(self, n=10) -> Iterable[OENode]: yield from islice(self.best_descriptions, n) def make_node(self, c: OWLClassExpression, parent_node: Optional[OENode] = None, is_root: bool = False) -> OENode: + """ + Create a node for CELOE. + + Args: + c: The class expression of this node. + parent_node: Parent node. + is_root: Is this the root node? + + Returns: + OENode: The node. + """ r = OENode(c, self.kb.concept_len(c), parent_node=parent_node, is_root=is_root) return r @contextmanager def updating_node(self, node: OENode): + """ + Removes the node from the heuristic sorted set and inserts it again. + + Args: + Node to update. + + Yields: + The node itself. + """ self.heuristic_queue.discard(node) yield node self.heuristic_queue.add(node) @@ -226,7 +298,7 @@ def fit(self, *args, **kwargs): async def fit_async(self, *args, **kwargs): """ - Find hypotheses that explain pos and neg. + Async method of fit. """ self.clean() max_runtime = kwargs.pop("max_runtime", None) @@ -296,10 +368,19 @@ async def fit_async(self, *args, **kwargs): return self.terminate() def encoded_learning_problem(self) -> Optional[EncodedPosNegLPStandardKind]: - """Fetch the most recently used learning problem from the fit method""" + """Fetch the most recently used learning problem from the fit method.""" return self._learning_problem def tree_node(self, node: OENode) -> TreeNode[OENode]: + """ + Get the TreeNode of the given node. + + Args: + node: The node. + + Returns: + TreeNode of the given node. + """ tree_parent = self.search_tree[node.concept] return tree_parent @@ -466,6 +547,32 @@ def clean(self): class OCEL(CELOE): + """A limited version of CELOE. + + Attributes: + best_descriptions (EvaluatedDescriptionSet[OENode, QualityOrderedNode]): Best hypotheses ordered. + best_only (bool): If False pick only nodes with quality < 1.0, else pick without quality restrictions. + calculate_min_max (bool): Calculate minimum and maximum horizontal expansion? Statistical purpose only. + heuristic_func (AbstractHeuristic): Function to guide the search heuristic. + heuristic_queue (SortedSet[OENode]): A sorted set that compares the nodes based on Heuristic. + iter_bound (int): Limit to stop the algorithm after n refinement steps are done. + kb (KnowledgeBase): The knowledge base that the concept learner is using. + max_child_length (int): Limit the length of concepts generated by the refinement operator. + max_he (int): Maximal value of horizontal expansion. + max_num_of_concepts_tested (int) Limit to stop the algorithm after n concepts tested. + max_runtime (int): Limit to stop the algorithm after n seconds. + min_he (int): Minimal value of horizontal expansion. + name (str): Name of the model = 'ocel_python'. + _number_of_tested_concepts (int): Yes, you got it. This stores the number of tested concepts. + operator (BaseRefinement): Operator used to generate refinements. + quality_func (AbstractScorer) The quality function to be used. + reasoner (OWLReasoner): The reasoner that this model is using. + search_tree (Dict[OWLClassExpression, TreeNode[OENode]]): Dict to store the TreeNode for a class expression. + start_class (OWLClassExpression): The starting class expression for the refinement operation. + start_time (float): The time when :meth:`fit` starts the execution. Used to calculate the total time :meth:`fit` + takes to execute. + terminate_on_goal (bool): Whether to stop the algorithm if a perfect solution is found. + """ __slots__ = () name = 'ocel_python' @@ -483,6 +590,28 @@ def __init__(self, max_results: int = 10, best_only: bool = False, calculate_min_max: bool = True): + """ Create a new instance of OCEL. + + Args: + best_only (bool): If False pick only nodes with quality < 1.0, else pick without quality restrictions. + Defaults to False. + calculate_min_max (bool): Calculate minimum and maximum horizontal expansion? Statistical purpose only. + Defaults to True. + refinement_operator (BaseRefinement[OENode]): Operator used to generate refinements. + Defaults to `ModifiedCELOERefinement`. + heuristic_func (AbstractHeuristic): Function to guide the search heuristic. Defaults to `OCELHeuristic`. + iter_bound (int): Limit to stop the algorithm after n refinement steps are done. Defaults to 10'000. + knowledge_base (KnowledgeBase): The knowledge base that the concept learner is using. + max_num_of_concepts_tested (int) Limit to stop the algorithm after n concepts tested. Defaults to 10'000. + max_runtime (int): Limit to stop the algorithm after n seconds. Defaults to 5. + max_results (int): Maximum hypothesis to store. Defaults to 10. + quality_func (AbstractScorer) The quality function to be used. Defaults to `F1`. + reasoner (OWLReasoner): Optionally use a different reasoner. If reasoner=None, the reasoner of + the :attr:`knowledge_base` is used. + terminate_on_goal (bool): Whether to stop the algorithm if a perfect solution is found. Defaults to True. + + + """ if heuristic_func is None: heuristic_func = OCELHeuristic() @@ -501,6 +630,17 @@ def __init__(self, calculate_min_max=calculate_min_max) def make_node(self, c: OWLClassExpression, parent_node: Optional[OENode] = None, is_root: bool = False) -> OENode: + """ + Create a node for OCEL. + + Args: + c: The class expression of this node. + parent_node: Parent node. + is_root: Is this the root node? + + Returns: + OENode: The node. + """ assert parent_node is None or isinstance(parent_node, LBLNode) r = LBLNode(c, self.kb.concept_len(c), self.kb.individuals_set(c), parent_node=parent_node, is_root=is_root) if parent_node is not None: @@ -509,6 +649,7 @@ def make_node(self, c: OWLClassExpression, parent_node: Optional[OENode] = None, class Drill(AbstractDrill, RefinementBasedConceptLearner): + """Deep Reinforcement Learning for Refinement Operators in ALC.""" kb: KnowledgeBase def __init__(self, knowledge_base, @@ -586,9 +727,7 @@ def downward_refinement(self, *args, **kwargs): def next_node_to_expand(self, t: int = None) -> RL_State: """ - Return a node that maximizes the heuristic function at time t - @param t: - @return: + Return a node that maximizes the heuristic function at time t. """ if self.verbose > 5: self.search_tree.show_search_tree(t) @@ -695,7 +834,8 @@ def fit_from_iterable(self, dataset: List[Tuple[object, Set[OWLNamedIndividual], Set[OWLNamedIndividual]]], max_runtime: int = None) -> List: """ - dataset is a list of tuples where the first item is either str or OWL class expression indicating target concept + Dataset is a list of tuples where the first item is either str or OWL class expression indicating target + concept. """ if max_runtime: self.max_runtime = max_runtime @@ -727,9 +867,6 @@ def fit_from_iterable(self, def init_training(self, pos_uri: Set[OWLNamedIndividual], neg_uri: Set[OWLNamedIndividual]) -> None: """ Initialize training. - - - @return: """ """ (1) Generate a Learning Problem """ self._learning_problem = PosNegLPStandard(pos=pos_uri, neg=neg_uri).encode_kb(self.kb) @@ -761,7 +898,7 @@ def init_training(self, pos_uri: Set[OWLNamedIndividual], neg_uri: Set[OWLNamedI def create_rl_state(self, c: OWLClassExpression, parent_node: Optional[RL_State] = None, is_root: bool = False) -> RL_State: - """ Create an RL_State instance """ + """ Create an RL_State instance.""" # Create State rl_state = RL_State(c, parent_node=parent_node, is_root=is_root) # Assign Embeddings to it. Later, assign_embeddings can be also done in RL_STATE @@ -770,19 +907,19 @@ def create_rl_state(self, c: OWLClassExpression, parent_node: Optional[RL_State] return rl_state def compute_quality_of_class_expression(self, state: RL_State) -> None: - """ Compute Quality of owl class expression of""" + """ Compute Quality of owl class expression.""" self.quality_func.apply(state, state.instances_bitset, self._learning_problem) self._number_of_tested_concepts += 1 def apply_refinement(self, rl_state: RL_State) -> Generator: """ - Refine an OWL Class expression \\|= Observing next possible states + Refine an OWL Class expression \\|= Observing next possible states. - 1. Generate concepts by refining a node - 1.1. Compute allowed length of refinements - 1.2. Convert concepts if concepts do not belong to self.concepts_to_ignore + 1. Generate concepts by refining a node. + 1.1. Compute allowed length of refinements. + 1.2. Convert concepts if concepts do not belong to self.concepts_to_ignore. Note that i.str not in self.concepts_to_ignore => O(1) if a set is being used. - 3. Return Generator + 3. Return Generator. """ assert isinstance(rl_state, RL_State) # 1. @@ -792,7 +929,8 @@ def apply_refinement(self, rl_state: RL_State) -> Generator: def learn_from_illustration(self, sequence_of_goal_path: List[RL_State]): """ - sequence_of_goal_path: ⊤,Parent,Parent ⊓ Daughter + Args: + sequence_of_goal_path: ⊤,Parent,Parent ⊓ Daughter. """ current_state = sequence_of_goal_path.pop(0) rewards = [] @@ -817,12 +955,12 @@ def learn_from_illustration(self, sequence_of_goal_path: List[RL_State]): def rl_learning_loop(self, pos_uri: Set[OWLNamedIndividual], neg_uri: Set[OWLNamedIndividual], goal_path: List[RL_State] = None) -> List[float]: """ - Standard RL training loop + Standard RL training loop. - 1. Initialize RL environment for training + 1. Initialize RL environment for training. - 2. Learn from an illustration if possible - 2. Training Loop + 2. Learn from an illustration if possible. + 2. Training Loop. """ """ (1) Initialize RL environment for training """ self.init_training(pos_uri=pos_uri, neg_uri=neg_uri) @@ -903,14 +1041,14 @@ def form_experiences(self, state_pairs: List, rewards: List) -> None: """ Form experiences from a sequence of concepts and corresponding rewards. - state_pairs - a list of tuples containing two consecutive states - reward - a list of reward. + state_pairs - A list of tuples containing two consecutive states. + reward - A list of reward. Gamma is 1. Return - X - a list of embeddings of current concept, next concept, positive examples, negative examples - y - argmax Q value. + X - A list of embeddings of current concept, next concept, positive examples, negative examples. + y - Argmax Q value. """ if self.verbose > 1: @@ -923,8 +1061,7 @@ def form_experiences(self, state_pairs: List, rewards: List) -> None: def learn_from_replay_memory(self) -> None: """ - Learning by replaying memory - @return: + Learning by replaying memory. """ if self.verbose > 1: print('Learn from Experience') @@ -993,8 +1130,8 @@ def update_search(self, concepts, predicted_Q_values): def assign_embeddings(self, rl_state: RL_State) -> None: """ - Assign embeddings to an rl state. An rl state is represented with vector representation of - all individuals belonging to a respective OWLClassExpression + Assign embeddings to a rl state. A rl state is represented with vector representation of + all individuals belonging to a respective OWLClassExpression. """ assert isinstance(rl_state, RL_State) @@ -1067,7 +1204,6 @@ def assign_embeddings(self, rl_state: RL_State) -> None: def save_weights(self): """ Save pytorch weights. - @return: """ # Save model. torch.save(self.heuristic_func.net.state_dict(), @@ -1077,8 +1213,8 @@ def exploration_exploitation_tradeoff(self, current_state: AbstractNode, next_states: List[AbstractNode]) -> AbstractNode: """ Exploration vs Exploitation tradeoff at finding next state. - (1) Exploration - (2) Exploitation + (1) Exploration. + (2) Exploitation. """ if np.random.random() < self.epsilon: next_state = random.choice(next_states) @@ -1092,9 +1228,9 @@ def exploitation(self, current_state: AbstractNode, next_states: List[AbstractNo """ Find next node that is assigned with highest predicted Q value. - (1) Predict Q values : predictions.shape => torch.Size([n, 1]) where n = len(next_states) + (1) Predict Q values : predictions.shape => torch.Size([n, 1]) where n = len(next_states). - (2) Find the index of max value in predictions + (2) Find the index of max value in predictions. (3) Use the index to obtain next state. @@ -1116,9 +1252,9 @@ def exploitation(self, current_state: AbstractNode, next_states: List[AbstractNo def predict_Q(self, current_state: AbstractNode, next_states: List[AbstractNode]) -> torch.Tensor: """ Predict promise of next states given current state. - @param current_state: - @param next_states: - @return: predicted Q values. + + Returns: + Predicted Q values. """ self.assign_embeddings(current_state) assert len(next_states) > 0 @@ -1150,19 +1286,22 @@ def retrieve_concept_chain(rl_state: RL_State) -> List[RL_State]: def train(self, dataset: Iterable[Tuple[str, Set, Set]], relearn_ratio: int = 2): """ Train RL agent on learning problems with relearn_ratio. - @param dataset: An iterable containing training data. Each item corresponds to a tuple of string representation - of target concept, a set of positive examples in the form of URIs amd a set of negative examples in the form of - URIs, respectively. - @param relearn_ratio: An integer indicating the number of times dataset is iterated. - Computation - 1. Dataset and relearn_ratio loops: Learn each problem relearn_ratio times, + Args: + dataset: An iterable containing training data. Each item corresponds to a tuple of string representation + of target concept, a set of positive examples in the form of URIs amd a set of negative examples in + the form of URIs, respectively. + relearn_ratio: An integer indicating the number of times dataset is iterated. + + Computation: + 1. Dataset and relearn_ratio loops: Learn each problem relearn_ratio times. - 2. Learning loop + 2. Learning loop. 3. Take post process action that implemented by subclass. - @return: self + Returns: + self. """ if self.verbose > 0: logger.info(f'Training starts.\nNumber of learning problem:{len(dataset)},\t Relearn ratio:{relearn_ratio}') @@ -1233,11 +1372,11 @@ class DrillNet(nn.Module): """ A neural model for Deep Q-Learning. - An input Drill has the following form - 1. indexes of individuals belonging to current state (s). - 2. indexes of individuals belonging to next state state (s_prime). - 3. indexes of individuals provided as positive examples. - 4. indexes of individuals provided as negative examples. + An input Drill has the following form: + 1. Indexes of individuals belonging to current state (s). + 2. Indexes of individuals belonging to next state (s_prime). + 3. Indexes of individuals provided as positive examples. + 4. Indexes of individuals provided as negative examples. Given such input, we from a sparse 3D Tensor where each slice is a **** N *** by ***D*** where N is the number of individuals and D is the number of dimension of embeddings. @@ -1280,19 +1419,39 @@ def forward(self, X: torch.FloatTensor): return self.fc2(X) -class CustomConceptLearner(CELOE): - def __init__(self, knowledge_base, reasoner=None, quality_func=None, iter_bound=None, - max_num_of_concepts_tested=None, heuristic_func=None, terminate_on_goal=None): - super().__init__(knowledge_base=knowledge_base, - reasoner=reasoner, - quality_func=quality_func, - heuristic_func=heuristic_func, - terminate_on_goal=terminate_on_goal, - iter_bound=iter_bound, max_num_of_concepts_tested=max_num_of_concepts_tested) - self.name = heuristic_func.name +class EvoLearner(BaseConceptLearner[EvoLearnerNode]): + """An evolutionary approach to learn concepts in ALCQ(D). + + Attributes: + algorithm (AbstractEvolutionaryAlgorithm): The evolutionary algorithm. + card_limit (int): The upper card limit if using card restriction. + fitness_func (AbstractFitness): Fitness function. + height_limit (int): The maximum value allowed for the height of the Crossover and Mutation operations. + init_method (AbstractEAInitialization): The evolutionary algorithm initialization method. + kb (KnowledgeBase): The knowledge base that the concept learner is using. + max_num_of_concepts_tested (int): Limit to stop the algorithm after n concepts tested. + max_runtime (int): max_runtime: Limit to stop the algorithm after n seconds. + mut_uniform_gen (AbstractEAInitialization): The initialization method to create the tree for mutation operation. + name (str): Name of the model = 'evolearner'. + num_generations (int): Number of generation for the evolutionary algorithm. + _number_of_tested_concepts (int): Yes, you got it. This stores the number of tested concepts. + population_size (int): Population size for the evolutionary algorithm. + pset (gp.PrimitiveSetTyped): Contains the primitives that can be used to solve a Strongly Typed GP problem. + quality_func: Function to evaluate the quality of solution concepts. + reasoner (OWLReasoner): The reasoner that this model is using. + start_time (float): The time when :meth:`fit` starts the execution. Used to calculate the total time :meth:`fit` + takes to execute. + terminate_on_goal (bool): Whether to stop the algorithm if a perfect solution is found. + toolbox (base.Toolbox): A toolbox for evolution that contains the evolutionary operators. + tournament_size (int): The number of evolutionary individuals participating in each tournament. + use_card_restrictions (bool): Use card restriction? + use_data_properties (bool): Consider data properties? + use_inverse (bool): Consider inversed concepts? + value_splitter (AbstractValueSplitter): Used to calculate the splits for data properties values. -class EvoLearner(BaseConceptLearner[EvoLearnerNode]): + + """ __slots__ = 'fitness_func', 'init_method', 'algorithm', 'value_splitter', 'tournament_size', \ 'population_size', 'num_generations', 'height_limit', 'use_data_properties', 'pset', 'toolbox', \ @@ -1344,6 +1503,35 @@ def __init__(self, population_size: int = 800, num_generations: int = 200, height_limit: int = 17): + """ Create a new instance of EvoLearner + + Args: + algorithm (AbstractEvolutionaryAlgorithm): The evolutionary algorithm. Defaults to `EASimple`. + card_limit (int): The upper card limit if using card restriction. Defaults to 10. + fitness_func (AbstractFitness): Fitness function. Defaults to `LinearPressureFitness`. + height_limit (int): The maximum value allowed for the height of the Crossover and Mutation operations. + Defaults to 17. + init_method (AbstractEAInitialization): The evolutionary algorithm initialization method. Defaults + to EARandomWalkInitialization. + knowledge_base (KnowledgeBase): The knowledge base that the concept learner is using. + max_runtime (int): max_runtime: Limit to stop the algorithm after n seconds. Defaults to 5. + mut_uniform_gen (AbstractEAInitialization): The initialization method to create the tree for mutation + operation. Defaults to + EARandomInitialization(min_height=1, max_height=3). + num_generations (int): Number of generation for the evolutionary algorithm. Defaults to 200. + population_size (int): Population size for the evolutionary algorithm. Defaults to 800. + quality_func: Function to evaluate the quality of solution concepts. Defaults to `Accuracy`. + reasoner (OWLReasoner): Optionally use a different reasoner. If reasoner=None, the reasoner of + the :attr:`knowledge_base` is used. + terminate_on_goal (bool): Whether to stop the algorithm if a perfect solution is found. Defaults to True. + tournament_size (int): The number of evolutionary individuals participating in each tournament. + Defaults to 7. + use_card_restrictions (bool): Use card restriction? Default to True. + use_data_properties (bool): Consider data properties? Defaults to True. + use_inverse (bool): Consider inversed concepts? Defaults to False. + value_splitter (AbstractValueSplitter): Used to calculate the splits for data properties values. Defaults to + `EntropyValueSplitter`. + """ if quality_func is None: quality_func = Accuracy() @@ -1472,8 +1660,10 @@ class Bool(object): for class_ in self.kb.get_concepts(): pset.addTerminal(class_, OWLClassExpression, name=escape(class_.get_iri().get_remainder())) - pset.addTerminal(self.kb.generator.thing, OWLClassExpression, name=escape(self.kb.generator.thing.get_iri().get_remainder())) - pset.addTerminal(self.kb.generator.nothing, OWLClassExpression, name=escape(self.kb.generator.nothing.get_iri().get_remainder())) + pset.addTerminal(self.kb.generator.thing, OWLClassExpression, + name=escape(self.kb.generator.thing.get_iri().get_remainder())) + pset.addTerminal(self.kb.generator.nothing, OWLClassExpression, + name=escape(self.kb.generator.nothing.get_iri().get_remainder())) return pset def __build_toolbox(self) -> base.Toolbox: @@ -1524,6 +1714,20 @@ def __set_splitting_values(self): self.pset.addTerminal(split, self._dp_to_prim_type[p], name=terminal_name) def register_op(self, alias: str, function: Callable, *args, **kargs): + """Register a *function* in the toolbox under the name *alias*. + You may provide default arguments that will be passed automatically when + calling the registered function. Fixed arguments can then be overriden + at function call time. + + Args: + alias: The name the operator will take in the toolbox. If the + alias already exist it will overwrite the operator + already present. + function: The function to which refer the alias. + args: One or more argument (and keyword argument) to pass + automatically to the registered function when called, + optional. + """ self.toolbox.register(alias, function, *args, **kargs) if alias == ToolboxVocabulary.CROSSOVER or alias == ToolboxVocabulary.MUTATION: self.toolbox.decorate(alias, gp.staticLimit(key=operator.attrgetter(ToolboxVocabulary.HEIGHT_KEY), @@ -1621,11 +1825,15 @@ def clean(self): super().clean() - + class NCES(BaseNCES): - - def __init__(self, knowledge_base_path, learner_name, path_of_embeddings, proj_dim, rnn_n_layers, drop_prob, num_heads, num_seeds, num_inds, ln=False, learning_rate=1e-4, decay_rate=0.0, clip_value=5.0, batch_size=256, num_workers=8, max_length=48, load_pretrained=True, sorted_examples=True, pretrained_model_name=None): - super().__init__(knowledge_base_path, learner_name, path_of_embeddings, batch_size, learning_rate, decay_rate, clip_value, num_workers) + """Neural Class Expression Synthesis.""" + def __init__(self, knowledge_base_path, learner_name, path_of_embeddings, proj_dim, rnn_n_layers, drop_prob, + num_heads, num_seeds, num_inds, ln=False, learning_rate=1e-4, decay_rate=0.0, clip_value=5.0, + batch_size=256, num_workers=8, max_length=48, load_pretrained=True, sorted_examples=True, + pretrained_model_name=None): + super().__init__(knowledge_base_path, learner_name, path_of_embeddings, batch_size, learning_rate, decay_rate, + clip_value, num_workers) self.path_of_embeddings = path_of_embeddings self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') self.max_length = max_length @@ -1640,15 +1848,19 @@ def __init__(self, knowledge_base_path, learner_name, path_of_embeddings, proj_d self.sorted_examples = sorted_examples self.pretrained_model_name = pretrained_model_name self.model = self.get_synthesizer() - + def get_synthesizer(self): def load_model(learner_name, load_pretrained): if learner_name == 'SetTransformer': - model = SetTransformer(self.knowledge_base_path, self.vocab, self.inv_vocab, self.max_length, self.input_size, self.proj_dim, self.num_heads, self.num_seeds, self.num_inds, self.ln) + model = SetTransformer(self.knowledge_base_path, self.vocab, self.inv_vocab, self.max_length, + self.input_size, self.proj_dim, self.num_heads, self.num_seeds, self.num_inds, + self.ln) elif learner_name == 'GRU': - model = GRU(self.knowledge_base_path, self.vocab, self.inv_vocab, self.max_length, self.input_size, self.proj_dim, self.rnn_n_layers, self.drop_prob) + model = GRU(self.knowledge_base_path, self.vocab, self.inv_vocab, self.max_length, self.input_size, + self.proj_dim, self.rnn_n_layers, self.drop_prob) elif learner_name == 'LSTM': - model = LSTM(self.knowledge_base_path, self.vocab, self.inv_vocab, self.max_length, self.input_size, self.proj_dim, self.rnn_n_layers, self.drop_prob) + model = LSTM(self.knowledge_base_path, self.vocab, self.inv_vocab, self.max_length, self.input_size, + self.proj_dim, self.rnn_n_layers, self.drop_prob) if load_pretrained: model_path = self.path_of_embeddings.split("embeddings")[0]+"trained_models/trained_"+learner_name+".pt" model.load_state_dict(torch.load(model_path, map_location=self.device)) @@ -1661,15 +1873,15 @@ def load_model(learner_name, load_pretrained): return [load_model(self.pretrained_model_name, self.load_pretrained)] elif self.load_pretrained and isinstance(self.pretrained_model_name, list): return [load_model(name, self.load_pretrained) for name in self.pretrained_model_name] - + def refresh(self): self.model = self.get_synthesizer() - + def sample_examples(self, pos, neg): - assert type(pos[0]) == type(neg[0]), "The two interables pos and neg must be of same type" + assert type(pos[0]) == type(neg[0]), "The two iterables pos and neg must be of same type" num_ex = self.num_examples oversample = False - if min(len(pos),len(neg)) >= num_ex//2: + if min(len(pos), len(neg)) >= num_ex//2: if len(pos) > len(neg): num_neg_ex = num_ex//2 num_pos_ex = num_ex-num_neg_ex @@ -1682,7 +1894,7 @@ def sample_examples(self, pos, neg): elif len(pos) + len(neg) >= num_ex and len(pos) < len(neg): num_pos_ex = len(pos) num_neg_ex = num_ex-num_pos_ex - #elif len(pos) + len(neg) < num_ex: + # elif len(pos) + len(neg) < num_ex: # num_pos_ex = max(num_ex//3, len(pos)) # num_neg_ex = max(num_ex-num_pos_ex, len(neg)) # oversample = True @@ -1691,17 +1903,17 @@ def sample_examples(self, pos, neg): num_neg_ex = len(neg) if oversample: remaining = list(self.all_individuals.difference(set(pos).union(set(neg)))) - positive = pos + random.sample(remaining, min(max(0,num_pos_ex-len(pos)), len(remaining))) + positive = pos + random.sample(remaining, min(max(0, num_pos_ex-len(pos)), len(remaining))) remaining = list(set(remaining).difference(set(positive))) - negative = neg + random.sample(remaining, min(max(0,num_neg_ex-len(neg)), len(remaining))) + negative = neg + random.sample(remaining, min(max(0, num_neg_ex-len(neg)), len(remaining))) else: positive = random.sample(pos, min(num_pos_ex, len(pos))) negative = random.sample(neg, min(num_neg_ex, len(neg))) return positive, negative - + @staticmethod def get_prediction(models, x1, x2): - for i,model in enumerate(models): + for i, model in enumerate(models): model.eval() if i == 0: _, scores = model(x1, x2) @@ -1711,8 +1923,9 @@ def get_prediction(models, x1, x2): scores = scores/len(models) prediction = model.inv_vocab[scores.argmax(1)] return prediction - - def fit(self, pos: Union[Set[OWLNamedIndividual], Set[str]] , neg: Union[Set[OWLNamedIndividual], Set[str]], shuffle_examples=False, verbose=True, **kwargs): + + def fit(self, pos: Union[Set[OWLNamedIndividual], Set[str]], neg: Union[Set[OWLNamedIndividual], Set[str]], + shuffle_examples=False, verbose=True, **kwargs): pos = list(pos) neg = list(neg) if isinstance(pos[0], OWLNamedIndividual): @@ -1725,14 +1938,17 @@ def fit(self, pos: Union[Set[OWLNamedIndividual], Set[str]] , neg: Union[Set[OWL raise ValueError(f"Invalid input type, was expecting OWLNamedIndividual or str but found {type(pos[0])}") if self.sorted_examples: pos_str, neg_str = sorted(pos_str), sorted(neg_str) - - assert self.load_pretrained and self.pretrained_model_name, "No pretrained model found. Please first train NCES, see the <> method below" - - dataset = NCESDataLoaderInference([("", pos_str, neg_str)], self.instance_embeddings, self.vocab, self.inv_vocab, shuffle_examples, self.sorted_examples) - dataloader = DataLoader(dataset, batch_size=self.batch_size, num_workers=self.num_workers, collate_fn=self.collate_batch_inference, shuffle=False) + + assert self.load_pretrained and self.pretrained_model_name, \ + "No pretrained model found. Please first train NCES, see the <> method below" + + dataset = NCESDataLoaderInference([("", pos_str, neg_str)], self.instance_embeddings, + self.vocab, self.inv_vocab, shuffle_examples, self.sorted_examples) + dataloader = DataLoader(dataset, batch_size=self.batch_size, num_workers=self.num_workers, + collate_fn=self.collate_batch_inference, shuffle=False) x_pos, x_neg = next(iter(dataloader)) simpleSolution = SimpleSolution(list(self.vocab), self.atomic_concept_names) - dl_parser = DLSyntaxParser(namespace = self.kb_namespace) + dl_parser = DLSyntaxParser(namespace=self.kb_namespace) prediction = self.get_prediction(self.model, x_pos, x_neg) try: prediction_str = "".join(before_pad(prediction.squeeze())) @@ -1745,10 +1961,11 @@ def fit(self, pos: Union[Set[OWLNamedIndividual], Set[str]] , neg: Union[Set[OWL if verbose: print("Prediction: ", prediction_str) return prediction_as_owl_class_expression - + def convert_to_list_str_from_iterable(self, data): target_concept_str, examples = data[0], data[1:] - pos = list(examples[0]); neg = list(examples[1]) + pos = list(examples[0]) + neg = list(examples[1]) if isinstance(pos[0], OWLNamedIndividual): pos_str = [ind.get_iri().as_str().split("/")[-1] for ind in pos] neg_str = [ind.get_iri().as_str().split("/")[-1] for ind in neg] @@ -1760,19 +1977,22 @@ def convert_to_list_str_from_iterable(self, data): if self.sorted_examples: pos_str, neg_str = sorted(pos_str), sorted(neg_str) return (target_concept_str, pos_str, neg_str) - - + def fit_from_iterable(self, dataset: Union[List[Tuple[str, Set[OWLNamedIndividual], Set[OWLNamedIndividual]]], - List[Tuple[str, Set[str], Set[str]]]], shuffle_examples=False, verbose=False, **kwargs) -> List: + List[Tuple[str, Set[str], Set[str]]]], shuffle_examples=False, + verbose=False, **kwargs) -> List: """ - dataset is a list of tuples where the first items are strings corresponding to target concepts + Dataset is a list of tuples where the first items are strings corresponding to target concepts. """ - assert self.load_pretrained and self.pretrained_model_name, "No pretrained model found. Please first train NCES, see the <> method" + assert self.load_pretrained and self.pretrained_model_name, \ + "No pretrained model found. Please first train NCES, see the <> method" dataset = [self.convert_to_list_str_from_iterable(datapoint) for datapoint in dataset] - dataset = NCESDataLoaderInference(dataset, self.instance_embeddings, self.vocab, self.inv_vocab, shuffle_examples) - dataloader = DataLoader(dataset, batch_size=self.batch_size, num_workers=self.num_workers, collate_fn=self.collate_batch_inference, shuffle=False) + dataset = NCESDataLoaderInference(dataset, self.instance_embeddings, self.vocab, self.inv_vocab, + shuffle_examples) + dataloader = DataLoader(dataset, batch_size=self.batch_size, num_workers=self.num_workers, + collate_fn=self.collate_batch_inference, shuffle=False) simpleSolution = SimpleSolution(list(self.vocab), self.atomic_concept_names) - dl_parser = DLSyntaxParser(namespace = self.kb_namespace) + dl_parser = DLSyntaxParser(namespace=self.kb_namespace) predictions_as_owl_class_expressions = [] predictions_str = [] for x_pos, x_neg in dataloader: @@ -1790,18 +2010,21 @@ def fit_from_iterable(self, dataset: Union[List[Tuple[str, Set[OWLNamedIndividua if verbose: print("Predictions: ", predictions_str) return predictions_as_owl_class_expressions - - - def train(self, data: Iterable[List[Tuple]], epochs=300, batch_size=None, learning_rate=1e-4, decay_rate=0.0, clip_value=5.0, num_workers=8, save_model=True, storage_path=None, optimizer='Adam', record_runtime=True, example_sizes=[], shuffle_examples=False): + + def train(self, data: Iterable[List[Tuple]], epochs=300, batch_size=None, learning_rate=1e-4, decay_rate=0.0, + clip_value=5.0, num_workers=8, save_model=True, storage_path=None, optimizer='Adam', record_runtime=True, + example_sizes=None, shuffle_examples=False): if batch_size is None: batch_size = self.batch_size - train_dataset = NCESDataLoader(data, self.instance_embeddings, self.vocab, self.inv_vocab, shuffle_examples=shuffle_examples, max_length=self.max_length, example_sizes=example_sizes) - train_dataloader = DataLoader(train_dataset, batch_size=batch_size, num_workers=self.num_workers, collate_fn=self.collate_batch, shuffle=True) - if storage_path == None: + train_dataset = NCESDataLoader(data, self.instance_embeddings, self.vocab, self.inv_vocab, + shuffle_examples=shuffle_examples, max_length=self.max_length, + example_sizes=example_sizes) + train_dataloader = DataLoader(train_dataset, batch_size=batch_size, num_workers=self.num_workers, + collate_fn=self.collate_batch, shuffle=True) + if storage_path is None: storage_path = self.knowledge_base_path[:self.knowledge_base_path.rfind("/")] elif not os.path.exists(storage_path): os.mkdir(storage_path) - trainer = NCESTrainer(self, epochs=epochs, learning_rate=learning_rate, decay_rate=decay_rate, clip_value=clip_value, num_workers=num_workers, storage_path=storage_path) + trainer = NCESTrainer(self, epochs=epochs, learning_rate=learning_rate, decay_rate=decay_rate, + clip_value=clip_value, num_workers=num_workers, storage_path=storage_path) trainer.train(train_dataloader, save_model, optimizer, record_runtime) - - \ No newline at end of file diff --git a/ontolearn/core/__init__.py b/ontolearn/core/__init__.py index e69de29b..47ea38fc 100644 --- a/ontolearn/core/__init__.py +++ b/ontolearn/core/__init__.py @@ -0,0 +1 @@ +"""Core utils.""" diff --git a/ontolearn/core/owl/__init__.py b/ontolearn/core/owl/__init__.py index e69de29b..ac65f1ea 100644 --- a/ontolearn/core/owl/__init__.py +++ b/ontolearn/core/owl/__init__.py @@ -0,0 +1,2 @@ +"""Owl utils. +""" \ No newline at end of file diff --git a/ontolearn/core/owl/hierarchy.py b/ontolearn/core/owl/hierarchy.py index f19c2b5f..141abc75 100644 --- a/ontolearn/core/owl/hierarchy.py +++ b/ontolearn/core/owl/hierarchy.py @@ -1,3 +1,5 @@ +"""Classes representing hierarchy in OWL.""" + import operator from abc import ABCMeta, abstractmethod from functools import reduce @@ -11,11 +13,11 @@ class AbstractHierarchy(Generic[_S], metaclass=ABCMeta): - """Representation of an abstract hierarchy which can be used for classes or properties + """Representation of an abstract hierarchy which can be used for classes or properties. Args: - hierarchy_down: a downwards hierarchy given as a mapping of Entities to sub-entities - reasoner: alternatively, a reasoner whose root_ontology is queried for entities + hierarchy_down: A downwards hierarchy given as a mapping of Entities to sub-entities. + reasoner: Alternatively, a reasoner whose root_ontology is queried for entities. """ __slots__ = '_Type', '_ent_set', '_parents_map', '_parents_map_trans', '_children_map', '_children_map_trans', \ '_leaf_set', '_root_set', \ @@ -49,33 +51,33 @@ def __init__(self, factory: Type[_S], arg): @abstractmethod def _hierarchy_down_generator(self, reasoner: OWLReasoner) -> Iterable[Tuple[_S, Iterable[_S]]]: - """Generate the suitable downwards hierarchy based on the reasoner""" + """Generate the suitable downwards hierarchy based on the reasoner.""" pass @classmethod @abstractmethod def get_top_entity(cls) -> _S: - """The most general entity in this hierarchy, which contains all the entities""" + """The most general entity in this hierarchy, which contains all the entities.""" pass @classmethod @abstractmethod def get_bottom_entity(cls) -> _S: - """The most specific entity in this hierarchy, which contains none of the entities""" + """The most specific entity in this hierarchy, which contains none of the entities.""" pass @staticmethod def restrict(hierarchy: _U, *, remove: Iterable[_S] = None, allow: Iterable[_S] = None) \ -> _U: - """Restrict a given hierarchy to a set of allowed/removed entities + """Restrict a given hierarchy to a set of allowed/removed entities. Args: - hierarchy: an existing Entity hierarchy to restrict - remove: set of entities which should be ignored - allow: set of entities which should be used + hierarchy: An existing Entity hierarchy to restrict. + remove: Set of entities which should be ignored. + allow: Set of entities which should be used. Returns: - the restricted hierarchy + The restricted hierarchy. """ remove_set = frozenset(remove) if remove is not None else None @@ -94,9 +96,9 @@ def _filter(_: _S): def restrict_and_copy(self: _U, *, remove: Iterable[_S] = None, allow: Iterable[_S] = None) \ -> _U: - """Restrict this hierarchy + """Restrict this hierarchy. - See restrict for more info + See restrict for more info. """ return type(self).restrict(self, remove=remove, allow=allow) @@ -139,14 +141,14 @@ def _init(self, hierarchy_down: Iterable[Tuple[_S, Iterable[_S]]]) -> None: self._parents_map, self._root_set = _reduce_transitive(self._parents_map_trans, self._children_map_trans) def parents(self, entity: _S, direct: bool = True) -> Iterable[_S]: - """Parents of an entity + """Parents of an entity. Args: - entity: entity for which to query parent entities - direct: False to return transitive parents + entity: Entity for which to query parent entities. + direct: False to return transitive parents. Returns: - super-entities + Super-entities. """ if entity == type(self).get_bottom_entity(): @@ -166,7 +168,7 @@ def is_parent_of(self, a: _S, b: _S) -> bool: """if A is a parent of B. Note: - A is always a parent of A""" + A is always a parent of A.""" if a == b: return True if a == type(self).get_top_entity(): @@ -179,7 +181,7 @@ def is_child_of(self, a: _S, b: _S) -> bool: """If A is a child of B. Note: - A is always a child of A""" + A is always a child of A.""" if a == b: return True if a == type(self).get_bottom_entity(): @@ -189,14 +191,14 @@ def is_child_of(self, a: _S, b: _S) -> bool: return False def children(self, entity: _S, direct: bool = True) -> Iterable[_S]: - """Children of an entitiy + """Children of an entity. Args: - entity: entity for which to query child entities - direct: False to return transitive children + entity: Entity for which to query child entities. + direct: False to return transitive children. Returns: - sub-entities + Sub-entities. """ if entity == type(self).get_top_entity(): @@ -243,11 +245,11 @@ def __len__(self): class ClassHierarchy(AbstractHierarchy[OWLClass]): - """Representation of a class hierarchy + """Representation of a class hierarchy. Args: - hierarchy_down: a downwards hierarchy given as a mapping of Class to sub-classes - reasoner: alternatively, a reasoner whose root_ontology is queried for classes and sub-classes + hierarchy_down: A downwards hierarchy given as a mapping of Class to sub-classes. + reasoner: Alternatively, a reasoner whose root_ontology is queried for classes and sub-classes. """ @classmethod @@ -282,6 +284,7 @@ def __init__(self, arg): class ObjectPropertyHierarchy(AbstractHierarchy[OWLObjectProperty]): + """Representation of an objet property hierarchy.""" @classmethod def get_top_entity(cls) -> OWLObjectProperty: return OWLTopObjectProperty @@ -329,6 +332,7 @@ def __init__(self, arg): class DatatypePropertyHierarchy(AbstractHierarchy[OWLDataProperty]): + """Representation of a data property hierarchy.""" @classmethod def get_top_entity(cls) -> OWLDataProperty: return OWLTopDataProperty @@ -374,14 +378,14 @@ def __init__(self, arg): def _children_transitive(hier_trans: Dict[_S, Set[_S]], ent: _S, seen_set: Set[_S]): - """add transitive links to map_trans + """Add transitive links to map_trans. Note: - changes map_trans + Changes map_trans. Args: - hier_trans: map to which transitive links are added - ent: class in map_trans for which to add transitive sub-classes + hier_trans: Map to which transitive links are added. + ent: Class in map_trans for which to add transitive sub-classes. """ sub_classes_ent = frozenset(hier_trans[ent]) @@ -394,18 +398,18 @@ def _children_transitive(hier_trans: Dict[_S, Set[_S]], ent: _S, seen_set: Set[_ def _reduce_transitive(hier: Dict[_S, Set[_S]], hier_inverse: Dict[_S, Set[_S]]) \ -> Tuple[Dict[_S, Set[_S]], FrozenSet[_S]]: - """Remove all transitive links + """Remove all transitive links. Takes a downward hierarchy and an upward hierarchy with transitive links, and removes all links that can be - implicitly detected since they are transitive + implicitly detected since they are transitive. Args: - hier: downward hierarchy with all transitive links, from Class => sub-classes - hier_inverse: upward hierarchy with all transitive links, from Class => super-classes + hier: downward hierarchy with all transitive links, from Class => sub-classes. + hier_inverse: upward hierarchy with all transitive links, from Class => super-classes. Returns: - thin map with only direct sub-classes - set of classes without sub-classes + Thin map with only direct sub-classes. + Set of classes without sub-classes. """ result_hier: Dict[_S, Set[_S]] = dict() @@ -422,13 +426,13 @@ def _reduce_transitive(hier: Dict[_S, Set[_S]], hier_inverse: Dict[_S, Set[_S]]) def _strongly_connected_components(graph: Dict[_S, Set[_S]]) -> Iterable[FrozenSet[_S]]: - """Strongly connected component algorithm + """Strongly connected component algorithm. Args: - graph: Directed Graph dictionary, vertex => set of vertices (there is an edge from v to each V) + graph: Directed Graph dictionary, vertex => set of vertices (there is an edge from v to each V). Returns: - the strongly connected components + The strongly connected components. Author: Mario Alviano Source: https://github.com/alviano/python/blob/master/rewrite_aggregates/scc.py diff --git a/ontolearn/core/owl/utils.py b/ontolearn/core/owl/utils.py index c9ba6948..454e6de7 100644 --- a/ontolearn/core/owl/utils.py +++ b/ontolearn/core/owl/utils.py @@ -2,13 +2,13 @@ from functools import singledispatchmethod from typing import Iterable, Generic, TypeVar, Callable, List -from ontolearn.owlapy.model import OWLDataRange, OWLLiteral, OWLObject, OWLClass, OWLObjectProperty, OWLObjectSomeValuesFrom, \ +from ontolearn.owlapy.model import OWLDataRange, OWLLiteral, OWLObject, OWLClass, OWLObjectProperty, \ OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectInverseOf, \ OWLObjectCardinalityRestriction, OWLObjectHasSelf, OWLObjectHasValue, OWLObjectOneOf, OWLNamedIndividual, \ OWLObjectMinCardinality, OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLClassExpression, OWLThing, \ OWLDataSomeValuesFrom, OWLDataOneOf, OWLDatatypeRestriction, OWLDataComplementOf, OWLDataAllValuesFrom, \ OWLDataCardinalityRestriction, OWLDatatype, OWLDataHasValue, OWLDataUnionOf, OWLDataIntersectionOf, \ - OWLDataExactCardinality, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataProperty + OWLDataExactCardinality, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataProperty, OWLObjectSomeValuesFrom from ontolearn.owlapy.util import OrderedOWLObject, iter_count from sortedcontainers import SortedSet diff --git a/ontolearn/data_struct.py b/ontolearn/data_struct.py index d2dcda6d..a0594b68 100644 --- a/ontolearn/data_struct.py +++ b/ontolearn/data_struct.py @@ -1,3 +1,5 @@ +"""Data structures.""" + import torch from collections import deque import pandas as pd @@ -5,11 +7,14 @@ # @Todo CD:Could we combine PrepareBatchOfPrediction and PrepareBatchOfTraining? + class PrepareBatchOfPrediction(torch.utils.data.Dataset): def __init__(self, current_state: torch.FloatTensor, next_state_batch: torch.Tensor, p: torch.FloatTensor, n: torch.FloatTensor): """ + Batch of prediction preparation class. + Args: current_state: a Tensor of torch.Size([1, 1, dim]) corresponds to embeddings of current_state next_state_batch: a Tensor of torch.Size([n, 1, dim]) corresponds to embeddings of next_states, i.e. @@ -112,10 +117,10 @@ def __len__(self): def append(self, e): """ + Append. Args: - e: a tuple of s_i, s_j and reward, where s_i and s_j represent refining s_i and reaching s_j. + e: A tuple of s_i, s_j and reward, where s_i and s_j represent refining s_i and reaching s_j. - Returns: """ assert len(self.current_states) == len(self.next_states) == len(self.rewards) s_i, s_j, r = e @@ -132,16 +137,15 @@ def clear(self): self.next_states.clear() self.rewards.clear() - class BaseDataLoader: - + def __init__(self, vocab, inv_vocab): - + self.vocab = vocab self.inv_vocab = inv_vocab self.vocab_df = pd.DataFrame(self.vocab.values(), index=self.vocab.keys()) - + @staticmethod def decompose(concept_name: str) -> list: list_ordered_pieces = [] @@ -159,16 +163,17 @@ def decompose(concept_name: str) -> list: list_ordered_pieces.append(concept_name[i]) i += 1 return list_ordered_pieces - + def get_labels(self, target): target = self.decompose(target) labels = [self.vocab[atm] for atm in target] return labels, len(target) - + class NCESDataLoader(BaseDataLoader, torch.utils.data.Dataset): - - def __init__(self, data: list, embeddings, vocab, inv_vocab, shuffle_examples, max_length, example_sizes=None, sorted_examples=True): + + def __init__(self, data: list, embeddings, vocab, inv_vocab, shuffle_examples, max_length, example_sizes=None, + sorted_examples=True): self.data_raw = data self.embeddings = embeddings self.max_length = max_length @@ -179,7 +184,7 @@ def __init__(self, data: list, embeddings, vocab, inv_vocab, shuffle_examples, m def __len__(self): return len(self.data_raw) - + def __getitem__(self, idx): key, value = self.data_raw[idx] pos = value['positive examples'] @@ -196,10 +201,12 @@ def __getitem__(self, idx): datapoint_pos = torch.FloatTensor(self.embeddings.loc[selected_pos].values.squeeze()) datapoint_neg = torch.FloatTensor(self.embeddings.loc[selected_neg].values.squeeze()) labels, length = self.get_labels(key) - return datapoint_pos, datapoint_neg, torch.cat([torch.tensor(labels), self.vocab['PAD']*torch.ones(self.max_length-length)]).long() - + return datapoint_pos, datapoint_neg, torch.cat([torch.tensor(labels), + self.vocab['PAD']*torch.ones(self.max_length-length)]).long() + + class NCESDataLoaderInference(BaseDataLoader, torch.utils.data.Dataset): - + def __init__(self, data: list, embeddings, vocab, inv_vocab, shuffle_examples, sorted_examples=True): self.data_raw = data self.embeddings = embeddings @@ -209,7 +216,7 @@ def __init__(self, data: list, embeddings, vocab, inv_vocab, shuffle_examples, s def __len__(self): return len(self.data_raw) - + def __getitem__(self, idx): _, pos, neg = self.data_raw[idx] if self.sorted_examples: @@ -219,4 +226,4 @@ def __getitem__(self, idx): random.shuffle(neg) datapoint_pos = torch.FloatTensor(self.embeddings.loc[pos].values) datapoint_neg = torch.FloatTensor(self.embeddings.loc[neg].values) - return datapoint_pos, datapoint_neg \ No newline at end of file + return datapoint_pos, datapoint_neg diff --git a/ontolearn/ea_algorithms.py b/ontolearn/ea_algorithms.py index 91884f3a..781e0246 100644 --- a/ontolearn/ea_algorithms.py +++ b/ontolearn/ea_algorithms.py @@ -1,3 +1,5 @@ +"""Evolutionary algorithms (for Evolearner).""" + from abc import ABCMeta, abstractmethod from typing import ClassVar, Final, List, Optional, Tuple from deap.algorithms import varAnd @@ -22,7 +24,7 @@ class AbstractEvolutionaryAlgorithm(metaclass=ABCMeta): @abstractmethod def __init__(self): - """Create a new evolutionary algorithm""" + """Create a new evolutionary algorithm.""" pass @abstractmethod diff --git a/ontolearn/ea_initialization.py b/ontolearn/ea_initialization.py index fd5f1380..7848fc49 100644 --- a/ontolearn/ea_initialization.py +++ b/ontolearn/ea_initialization.py @@ -1,3 +1,5 @@ +"""Initialization for evolutionary algorithms.""" + from dataclasses import dataclass from functools import lru_cache from enum import Enum, auto @@ -51,9 +53,9 @@ def __init__(self, min_height: int = 3, max_height: int = 6, method: RandomInitMethod = RandomInitMethod.RAMPED_HALF_HALF): """ Args: - min_height: minimum height of trees - max_height: maximum height of trees - method: random initialization method possible values: rhh, grow, full + min_height: Minimum height of trees. + max_height: Maximum height of trees. + method: Random initialization method possible values: rhh, grow, full. """ self.min_height = min_height self.max_height = max_height @@ -127,9 +129,10 @@ class EARandomWalkInitialization(AbstractEAInitialization): def __init__(self, max_t: int = 2, jump_pr: float = 0.5): """ + Random walk initialization for description logic learning. Args: - max_t: number of paths - jump_pr: probability to explore paths of length 2 + max_t: Number of paths. + jump_pr: Probability to explore paths of length 2. """ self.max_t = max_t self.jump_pr = jump_pr diff --git a/ontolearn/ea_utils.py b/ontolearn/ea_utils.py index f977629c..ab930207 100644 --- a/ontolearn/ea_utils.py +++ b/ontolearn/ea_utils.py @@ -1,3 +1,5 @@ +"""Utils for evolutionary algorithms.""" + from enum import Enum from typing import Callable, Final, List, Optional, Tuple, Union diff --git a/ontolearn/endpoint/__init__.py b/ontolearn/endpoint/__init__.py index e69de29b..e5971a86 100644 --- a/ontolearn/endpoint/__init__.py +++ b/ontolearn/endpoint/__init__.py @@ -0,0 +1 @@ +"""Endpoints.""" diff --git a/ontolearn/experiments.py b/ontolearn/experiments.py index e4c23b40..e140ddea 100644 --- a/ontolearn/experiments.py +++ b/ontolearn/experiments.py @@ -1,3 +1,5 @@ +"""Experiments to validate a concept learning model.""" + import json import time from random import shuffle @@ -17,13 +19,16 @@ def __init__(self, max_test_time_per_concept=3): @staticmethod def store_report(model, learning_problems: List[Iterable], test_report: List[dict]) -> Tuple[str, Dict[str, Any]]: """ + Create a report for concepts generated for a particular learning problem. + Args: + model: Concept learner. + learning_problems: A list of learning problems (lps) where lp corresponds to target concept, positive and + negative examples, respectively. + test_report: A list of predictions (preds) where test_report => { 'Prediction': str, 'F-measure': float, + 'Accuracy', 'Runtime':float}. + Returns: + Both report as string and report as dictionary. - @param model: concept learner - @param learning_problems: A list of learning problems (lps) where lp corresponds to [target concept, positive - and negative examples, respectively. - @param test_report: A list of predictions (preds) where - test_report => { 'Prediction': str, 'F-measure': float, 'Accuracy', 'Runtime':float} - @return: """ assert len(learning_problems) == len(test_report) assert isinstance(learning_problems, list) # and isinstance(learning_problems[0], list) @@ -68,12 +73,15 @@ def store_report(model, learning_problems: List[Iterable], test_report: List[dic def start_KFold(self, k=None, dataset: List[Tuple[str, Set, Set]] = None, models: Iterable = None): """ - Perform KFold cross validation - @param models: - @param k: - @param dataset: A list of tuples where a tuple (i,j,k) where i denotes the target concept - j denotes the set of positive examples and k denotes the set of negative examples. - @return: + Perform KFold cross validation. + + Args: + models: concept learners. + k: k value of k-fold. + dataset: A list of tuples where a tuple (i,j,k) where i denotes the target concept j denotes the set of + positive examples and k denotes the set of negative examples. + Note: + This method returns nothing. It just prints the report results. """ models = {i for i in models} assert len(models) > 0 @@ -102,14 +110,6 @@ def start_KFold(self, k=None, dataset: List[Tuple[str, Set, Set]] = None, models self.report_results(results) def start(self, dataset: List[Tuple[str, Set, Set]] = None, models: List = None): - """ - Perform KFold cross validation - @param models: - @param k: - @param dataset: A list of tuples where a tuple (i,j,k) where i denotes the target concept - j denotes the set of positive examples and k denotes the set of negative examples. - @return: - """ assert len(models) > 0 assert len(dataset) > 0 assert isinstance(dataset[0], tuple) @@ -136,6 +136,8 @@ def start(self, dataset: List[Tuple[str, Set, Set]] = None, models: List = None) @staticmethod def report_results(results, num_problems): + """Prints the result generated from validations. + """ print(f'\n##### RESULTS on {num_problems} number of learning problems#####') for learner_name, v in results.items(): r = np.array([[report['F-measure'], report['Accuracy'], report['NumClassTested'], report['Runtime']] for diff --git a/ontolearn/fitness_functions.py b/ontolearn/fitness_functions.py index 6e0698a7..4607143c 100644 --- a/ontolearn/fitness_functions.py +++ b/ontolearn/fitness_functions.py @@ -1,10 +1,12 @@ +"""Fitness functions.""" + from typing import Final from ontolearn.abstracts import AbstractFitness from ontolearn.ea_utils import Tree class LinearPressureFitness(AbstractFitness): - """Linear parametric parsimony pressure""" + """Linear parametric parsimony pressure.""" __slots__ = 'gain', 'penalty' diff --git a/ontolearn/heuristics.py b/ontolearn/heuristics.py index 0ec87849..797e9aaf 100644 --- a/ontolearn/heuristics.py +++ b/ontolearn/heuristics.py @@ -1,3 +1,5 @@ +"""Heuristic functions.""" + from typing import Final import numpy as np @@ -9,7 +11,7 @@ class CELOEHeuristic(AbstractHeuristic[AbstractOEHeuristicNode]): - """Heuristic like the CELOE Heuristic in DL-Learner""" + """Heuristic like the CELOE Heuristic in DL-Learner.""" __slots__ = 'gainBonusFactor', 'startNodeBonus', 'nodeRefinementPenalty', 'expansionPenaltyFactor' name: Final = 'CELOE_Heuristic' @@ -24,14 +26,14 @@ def __init__(self, *, startNodeBonus: float = 0.1, nodeRefinementPenalty: float = 0.001, expansionPenaltyFactor: float = 0.1): - """Create a new CELOE Heuristic + """Create a new CELOE Heuristic. Args: - gainBonusFactor: factor that weighs the increase in quality compared to the parent node - startNodeBonus: special value added to the root node - nodeRefinementPenalty: value that is substracted from the heuristic for each refinement attempt of this node - expansionPenaltyFactor: value that is substracted from the heuristic for each horizontal expansion of this - node + gainBonusFactor: Factor that weighs the increase in quality compared to the parent node. + startNodeBonus: Special value added to the root node. + nodeRefinementPenalty: Value that is subtracted from the heuristic for each refinement attempt of this node. + expansionPenaltyFactor: Value that is subtracted from the heuristic for each horizontal expansion of this + node. """ self.gainBonusFactor = gainBonusFactor self.startNodeBonus = startNodeBonus @@ -55,6 +57,7 @@ def apply(self, node: AbstractOEHeuristicNode, instances, learning_problem: Enco class DLFOILHeuristic(AbstractHeuristic): + """DLFOIL Heuristic.""" __slots__ = () name: Final = 'custom_dl_foil' @@ -91,6 +94,7 @@ def apply(self, node, instances, learning_problem: EncodedPosNegUndLP): class OCELHeuristic(AbstractHeuristic): + """OCEL Heuristic.""" __slots__ = 'accuracy_method', 'gainBonusFactor', 'expansionPenaltyFactor' name: Final = 'OCEL_Heuristic' @@ -119,6 +123,7 @@ def apply(self, node: LBLNode, instances, learning_problem: EncodedPosNegLPStand class Reward: + """Reward function for DRILL.""" def __init__(self, reward_of_goal=5.0, beta=.04, alpha=.5): self.name = 'DRILL_Reward' self.lp = None diff --git a/ontolearn/knowledge_base.py b/ontolearn/knowledge_base.py index c349bb26..50e746aa 100644 --- a/ontolearn/knowledge_base.py +++ b/ontolearn/knowledge_base.py @@ -1,13 +1,15 @@ +""" Knowledge Base.""" + import logging import random from functools import singledispatchmethod from typing import Iterable, Optional, Callable, overload, Union, FrozenSet, Set, Dict from ontolearn.owlapy.owlready2 import OWLOntology_Owlready2, OWLOntologyManager_Owlready2, OWLReasoner_Owlready2 from ontolearn.owlapy.fast_instance_checker import OWLReasoner_FastInstanceChecker -from ontolearn.owlapy.model import OWLOntologyManager, OWLOntology, OWLReasoner, OWLClassExpression, OWLNamedIndividual, \ - OWLObjectProperty, OWLClass, OWLDataProperty, IRI, OWLDataRange, OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom, \ - OWLDatatype, BooleanOWLDatatype, NUMERIC_DATATYPES, TIME_DATATYPES, OWLThing, OWLObjectPropertyExpression, \ - OWLLiteral, OWLDataPropertyExpression +from ontolearn.owlapy.model import OWLOntologyManager, OWLOntology, OWLReasoner, OWLClassExpression, \ + OWLNamedIndividual, OWLObjectProperty, OWLClass, OWLDataProperty, IRI, OWLDataRange, OWLObjectSomeValuesFrom, \ + OWLObjectAllValuesFrom, OWLDatatype, BooleanOWLDatatype, NUMERIC_DATATYPES, TIME_DATATYPES, OWLThing, \ + OWLObjectPropertyExpression, OWLLiteral, OWLDataPropertyExpression from ontolearn.owlapy.render import DLSyntaxObjectRenderer from ontolearn.owlapy.util import iter_count, LRUCache from .abstracts import AbstractKnowledgeBase, AbstractScorer, EncodedLearningProblem, AbstractLearningProblem @@ -40,9 +42,10 @@ def _Default_ClassExpressionLengthMetricFactory() -> OWLClassExpressionLengthMet class EvaluatedConcept: - """This class is used to explicitly declare the attributes that should be returned by the evaluate_concept method. + """Explicitly declare the attributes that should be returned by the evaluate_concept method. + This way, Python uses a more efficient way to store the instance attributes, which can significantly reduce the - memory usage + memory usage. """ __slots__ = 'q', 'inds', 'ic' pass @@ -53,18 +56,22 @@ class EvaluatedConcept: class KnowledgeBase(AbstractKnowledgeBase): - """Knowledge Base Class is used to represent an OWL knowledge base in Ontolearn, meaning that it represents the - Tbox and Abox along with concept hierarchies + """Representation of an OWL knowledge base in Ontolearn. Args: - path: path to an ontology file that is to be loaded - ontologymanager_factory: factory that creates an ontology manager to be used to load the file - ontology: OWL ontology object - reasoner_factory: factory that creates a reasoner to reason about the ontology - reasoner: reasoner over the ontology - length_metric_factory: see `length_metric` - length_metric: length metric that is used in calculation of class expresion lengths - individuals_cache_size: how many individuals of class expressions to cache + path: Path to an ontology file that is to be loaded. + ontologymanager_factory: Factory that creates an ontology manager to be used to load the file. + ontology: OWL ontology object. + reasoner_factory: Factory that creates a reasoner to reason about the ontology. + reasoner: reasoner Over the ontology. + length_metric_factory: See :attr:`length_metric`. + length_metric: Length metric that is used in calculation of class expression lengths. + individuals_cache_size: How many individuals of class expressions to cache. + + Attributes: + generator (ConceptGenerator): Instance of concept generator. + path (str): Path of the ontology file. + use_individuals_cache (bool): Whether to use individuals cache to store individuals for method efficiency. """ __slots__ = '_manager', '_ontology', '_reasoner', '_length_metric', \ '_ind_set', '_ind_cache', 'path', 'use_individuals_cache', 'generator', '_class_hierarchy', \ @@ -202,19 +209,19 @@ def __init__(self, *, self.describe() def ontology(self) -> OWLOntology: - """Get the root Ontology loaded in this knowledge base + """Get the root Ontology loaded in this knowledge base. Returns: - The Ontology + The Ontology. """ return self._ontology def reasoner(self) -> OWLReasoner: - """Get the Reasoner loaded in this knowledge base + """Get the Reasoner loaded in this knowledge base. Returns: - The Reasoner + The Reasoner. """ return self._reasoner @@ -222,14 +229,14 @@ def reasoner(self) -> OWLReasoner: def ignore_and_copy(self, ignored_classes: Optional[Iterable[OWLClass]] = None, ignored_object_properties: Optional[Iterable[OWLObjectProperty]] = None, ignored_data_properties: Optional[Iterable[OWLDataProperty]] = None) -> 'KnowledgeBase': - """Makes a copy of the knowledge base while ignoring specified concepts and properties + """Makes a copy of the knowledge base while ignoring specified concepts and properties. Args: - ignored_classes: classes to ignore - ignored_object_properties: object properties to ignore - ignored_data_properties: data properties to ignore + ignored_classes: Classes to ignore. + ignored_object_properties: Object properties to ignore. + ignored_data_properties: Data properties to ignore. Returns: - A new KnowledgeBase with the hierarchies restricted as requested + A new KnowledgeBase with the hierarchies restricted as requested. """ new = object.__new__(KnowledgeBase) @@ -274,7 +281,8 @@ def ignore_and_copy(self, ignored_classes: Optional[Iterable[OWLClass]] = None, new._object_property_hierarchy = self._object_property_hierarchy if ignored_data_properties is not None: - new._data_property_hierarchy = self._data_property_hierarchy.restrict_and_copy(remove=ignored_data_properties) + new._data_property_hierarchy = self._data_property_hierarchy.restrict_and_copy( + remove=ignored_data_properties) else: new._data_property_hierarchy = self._data_property_hierarchy @@ -282,18 +290,18 @@ def ignore_and_copy(self, ignored_classes: Optional[Iterable[OWLClass]] = None, def concept_len(self, ce: OWLClassExpression) -> int: """Calculates the length of a concept and is used by some concept learning algorithms to - find the best results considering also the length of the concepts + find the best results considering also the length of the concepts. Args: - ce: the concept to be measured + ce: The concept to be measured. Returns: - Length of the concept + Length of the concept. """ return self._length_metric.length(ce) def clean(self): - """Clean all stored values (states and caches) if there is any + """Clean all stored values (states and caches) if there is any. Note: 1. If you have more than one learning problem that you want to fit to the same model (i.e. to learn the @@ -336,12 +344,12 @@ def _maybe_cache_individuals_count(self, ce: OWLClassExpression) -> int: def individuals(self, concept: Optional[OWLClassExpression] = None) -> Iterable[OWLNamedIndividual]: """Retrieve all individuals belonging to the concept in the ontology. If the concept property is not - specified then it returns all the individuals + specified then it returns all the individuals. Args: - concept: class expression of which to list individuals + concept: Class expression of which to list individuals. Returns: - Individuals belonging to the given class + Individuals belonging to the given class. """ if concept is None or concept.is_owl_thing(): @@ -351,12 +359,12 @@ def individuals(self, concept: Optional[OWLClassExpression] = None) -> Iterable[ yield from self._maybe_cache_individuals(concept) def individuals_count(self, concept: Optional[OWLClassExpression] = None) -> int: - """Returns the number of all individuals belonging to the concept in the ontology + """Returns the number of all individuals belonging to the concept in the ontology. Args: - concept: class expression of the individuals to count + concept: Class expression of the individuals to count. Returns: - Number of the individuals belonging to the given class + Number of the individuals belonging to the given class. """ if concept is None or concept.is_owl_thing(): @@ -378,14 +386,12 @@ def individuals_set(self, individuals: Iterable[OWLNamedIndividual]): def individuals_set(self, arg: Union[Iterable[OWLNamedIndividual], OWLNamedIndividual, OWLClassExpression]): """Retrieve the individuals specified in the arg as a frozenset. If `arg` is an OWLClassExpression then this - method behaves as the method "individuals" but will return the final result as a frozenset + method behaves as the method "individuals" but will return the final result as a frozenset. Args: - arg: more than one individual - single individual - class expression of which to list individuals + arg: more than one individual/ single individual/ class expression of which to list individuals. Returns: - frozenset of the individuals depending on the arg type + Frozenset of the individuals depending on the arg type. """ if isinstance(arg, OWLClassExpression): @@ -401,10 +407,10 @@ class expression of which to list individuals return frozenset(arg) def all_individuals_set(self): - """Retrieve all the individuals of the knowledge base + """Retrieve all the individuals of the knowledge base. Returns: - frozenset of the all individuals + Frozenset of the all individuals. """ if self._ind_set is not None: @@ -414,6 +420,12 @@ def all_individuals_set(self): def most_general_object_properties(self, *, domain: OWLClassExpression, inverse: bool = False) \ -> Iterable[OWLObjectProperty]: + """Find the most general object property. + + Args: + domain: Domain for which to search properties. + inverse: Inverse order? + """ assert isinstance(domain, OWLClassExpression) func = self.get_object_property_ranges if inverse else self.get_object_property_domains @@ -449,17 +461,17 @@ def encode_learning_problem(self, lp: AbstractLearningProblem): def _(self, lp: PosNegLPStandard): """Provides the encoded learning problem (lp), i.e. the class containing the set of OWLNamedIndividuals as follows: - kb_pos --> the positive examples set - kb_neg --> the negative examples set - kb_all --> all lp individuals / all individuals set - kb_diff --> kb_all - (kb_pos + kb_neg) + kb_pos --> the positive examples set, + kb_neg --> the negative examples set, + kb_all --> all lp individuals / all individuals set, + kb_diff --> kb_all - (kb_pos + kb_neg). Note: Simple access of the learning problem individuals divided in respective sets. You will need the encoded learning problem to use the method evaluate_concept of this class. Args: - lp: the learning problem + lp (PosNegLPStandard): The learning problem. Return: - The encoded learning problem + EncodedPosNegLPStandard: The encoded learning problem. """ assert len(self.class_hierarchy()) > 0 @@ -500,17 +512,17 @@ def _(self, lp: PosNegLPStandard): def evaluate_concept(self, concept: OWLClassExpression, quality_func: AbstractScorer, encoded_learning_problem: EncodedLearningProblem) -> EvaluatedConcept: - """Evaluates a concept by using the encoded learning problem examples, in terms of Accuracy or F1-score + """Evaluates a concept by using the encoded learning problem examples, in terms of Accuracy or F1-score. Note: This method is useful to tell the quality (e.q) of a generated concept by the concept learners, to get the set of individuals (e.inds) that are classified by this concept and the amount of them (e.ic). Args: - concept: the concept to be evaluated - quality_func: quality measurement in terms of Accuracy or F1-score - encoded_learning_problem: the encoded learning problem + concept: The concept to be evaluated. + quality_func: Quality measurement in terms of Accuracy or F1-score. + encoded_learning_problem: The encoded learning problem. Return: - The evaluated concept + The evaluated concept. """ e = EvaluatedConcept() @@ -521,47 +533,43 @@ def evaluate_concept(self, concept: OWLClassExpression, quality_func: AbstractSc async def evaluate_concept_async(self, concept: OWLClassExpression, quality_func: AbstractScorer, encoded_learning_problem: EncodedLearningProblem) -> EvaluatedConcept: - """The asynchronous version of evaluate_concept + """The asynchronous version of evaluate_concept. Raises: - NotImplementedError: This method is not implemented yet + NotImplementedError: This method is not implemented yet. """ raise NotImplementedError def get_leaf_concepts(self, concept: OWLClass): - """Get leaf classes + """Get leaf classes. Args: - concept: atomic class for which to find leaf classes + concept: Atomic class for which to find leaf classes. Returns: - Leaf classes - - { x \\| (x subClassOf concept) AND not exist y: y subClassOf x )} """ + Leaf classes { x \\| (x subClassOf concept) AND not exist y: y subClassOf x )}. """ assert isinstance(concept, OWLClass) yield from self._class_hierarchy.leaves(of=concept) def get_direct_sub_concepts(self, concept: OWLClass) -> Iterable[OWLClass]: - """Direct sub classes of atomic class + """Direct sub-classes of atomic class. Args: - concept: atomic concept + concept: Atomic concept. Returns: - direct sub classes of concept - - { x \\| ( x subClassOf concept )} """ + Direct sub classes of concept { x \\| ( x subClassOf concept )}.""" assert isinstance(concept, OWLClass) yield from self._class_hierarchy.sub_classes(concept, direct=True) def get_object_property_domains(self, prop: OWLObjectProperty) -> OWLClassExpression: - """Get the domains of an object property + """Get the domains of an object property. Args: - prop: object property + prop: Object property. Returns: - domains of the property + Domains of the property. """ if prop not in self._op_domains: domains = list(self._reasoner.object_property_domains(prop, direct=True)) @@ -569,13 +577,13 @@ def get_object_property_domains(self, prop: OWLObjectProperty) -> OWLClassExpres return self._op_domains[prop] def get_object_property_ranges(self, prop: OWLObjectProperty) -> OWLClassExpression: - """Get the ranges of an object property + """Get the ranges of an object property. Args: - prop: object property + prop: Object property. Returns: - ranges of the property + Ranges of the property. """ if prop not in self._op_ranges: ranges = list(self._reasoner.object_property_ranges(prop, direct=True)) @@ -583,13 +591,13 @@ def get_object_property_ranges(self, prop: OWLObjectProperty) -> OWLClassExpress return self._op_ranges[prop] def get_data_property_domains(self, prop: OWLDataProperty) -> OWLClassExpression: - """Get the domains of a data property + """Get the domains of a data property. Args: - prop: data property + prop: Data property. Returns: - domains of the property + Domains of the property. """ if prop not in self._dp_domains: domains = list(self._reasoner.data_property_domains(prop, direct=True)) @@ -597,73 +605,73 @@ def get_data_property_domains(self, prop: OWLDataProperty) -> OWLClassExpression return self._dp_domains[prop] def get_data_property_ranges(self, prop: OWLDataProperty) -> FrozenSet[OWLDataRange]: - """Get the ranges of a data property + """Get the ranges of a data property. Args: - prop: data property + prop: Data property. Returns: - ranges of the property + Ranges of the property. """ if prop not in self._dp_ranges: self._dp_ranges[prop] = frozenset(self._reasoner.data_property_ranges(prop, direct=True)) return self._dp_ranges[prop] def most_general_data_properties(self, *, domain: OWLClassExpression) -> Iterable[OWLDataProperty]: - """Find most general data properties that are applicable to a domain + """Find most general data properties that are applicable to a domain. Args: - domain: domain for which to search properties + domain: Domain for which to search properties. Returns: - most general data properties for the given domain + Most general data properties for the given domain. """ yield from self._data_properties_for_domain(domain, self.get_data_properties()) def most_general_boolean_data_properties(self, *, domain: OWLClassExpression) -> Iterable[OWLDataProperty]: - """Find most general boolean data properties that are applicable to a domain + """Find most general boolean data properties that are applicable to a domain. Args: - domain: domain for which to search properties + domain: Domain for which to search properties. Returns: - most general boolean data properties for the given domain + Most general boolean data properties for the given domain. """ yield from self._data_properties_for_domain(domain, self.get_boolean_data_properties()) def most_general_numeric_data_properties(self, *, domain: OWLClassExpression) -> Iterable[OWLDataProperty]: - """Find most general numeric data properties that are applicable to a domain + """Find most general numeric data properties that are applicable to a domain. Args: - domain: domain for which to search properties + domain: Domain for which to search properties. Returns: - most general numeric data properties for the given domain + Most general numeric data properties for the given domain. """ yield from self._data_properties_for_domain(domain, self.get_numeric_data_properties()) def most_general_time_data_properties(self, *, domain: OWLClassExpression) -> Iterable[OWLDataProperty]: - """Find most general time data properties that are applicable to a domain + """Find most general time data properties that are applicable to a domain. Args: - domain: domain for which to search properties + domain: Domain for which to search properties. Returns: - most general time data properties for the given domain + Most general time data properties for the given domain. """ yield from self._data_properties_for_domain(domain, self.get_time_data_properties()) def most_general_existential_restrictions(self, *, domain: OWLClassExpression, filler: Optional[OWLClassExpression] = None) \ -> Iterable[OWLObjectSomeValuesFrom]: - """Find most general existential restrictions that are applicable to a domain + """Find most general existential restrictions that are applicable to a domain. Args: - domain: domain for which to search properties - filler: optional filler to put in the restriction (not normally used) + domain: Domain for which to search properties. + filler: Optional filler to put in the restriction (not normally used). Returns: - most general existential restrictions for the given domain + Most general existential restrictions for the given domain. """ if filler is None: filler = self.generator.thing @@ -675,14 +683,14 @@ def most_general_existential_restrictions(self, *, def most_general_universal_restrictions(self, *, domain: OWLClassExpression, filler: Optional[OWLClassExpression] = None) \ -> Iterable[OWLObjectAllValuesFrom]: - """Find most general universal restrictions that are applicable to a domain + """Find most general universal restrictions that are applicable to a domain. Args: - domain: domain for which to search properties - filler: optional filler to put in the restriction (not normally used) + domain: Domain for which to search properties. + filler: Optional filler to put in the restriction (not normally used). Returns: - most general universal restrictions for the given domain + Most general universal restrictions for the given domain. """ if filler is None: filler = self.generator.thing @@ -695,14 +703,14 @@ def most_general_existential_restrictions_inverse(self, *, domain: OWLClassExpression, filler: Optional[OWLClassExpression] = None) \ -> Iterable[OWLObjectSomeValuesFrom]: - """Find most general inverse existential restrictions that are applicable to a domain + """Find most general inverse existential restrictions that are applicable to a domain. Args: - domain: domain for which to search properties - filler: optional filler to put in the restriction (not normally used) + domain: Domain for which to search properties. + filler: Optional filler to put in the restriction (not normally used). Returns: - most general existential restrictions over inverse property + Most general existential restrictions over inverse property. """ if filler is None: filler = self.generator.thing @@ -715,14 +723,14 @@ def most_general_universal_restrictions_inverse(self, *, domain: OWLClassExpression, filler: Optional[OWLClassExpression] = None) \ -> Iterable[OWLObjectAllValuesFrom]: - """Find most general inverse universal restrictions that are applicable to a domain + """Find most general inverse universal restrictions that are applicable to a domain. Args: - domain: domain for which to search properties - filler: optional filler to put in the restriction (not normally used) + domain: Domain for which to search properties. + filler: Optional filler to put in the restriction (not normally used). Returns: - most general universal restrictions over inverse property + Most general universal restrictions over inverse property. """ if filler is None: filler = self.generator.thing @@ -732,66 +740,66 @@ def most_general_universal_restrictions_inverse(self, *, yield OWLObjectAllValuesFrom(property=prop.get_inverse_property(), filler=filler) def get_direct_parents(self, concept: OWLClassExpression) -> Iterable[OWLClass]: - """Direct parent concepts + """Direct parent concepts. Args: - concept: concept to find super concepts of + concept: Concept to find super concepts of. Returns: - direct parent concepts + Direct parent concepts. """ assert isinstance(concept, OWLClass) yield from self._class_hierarchy.super_classes(concept, direct=True) def get_all_direct_sub_concepts(self, concept: OWLClassExpression) -> Iterable[OWLClassExpression]: - """All direct sub concepts of a concept + """All direct sub concepts of a concept. Args: - concept: parent concept for which to get sub concepts + concept: Parent concept for which to get sub concepts. Returns: - direct sub concepts + Direct sub concepts. """ assert isinstance(concept, OWLClass) yield from self._class_hierarchy.sub_classes(concept, direct=True) def get_all_sub_concepts(self, concept: OWLClassExpression) -> Iterable[OWLClassExpression]: - """All sub concepts of a concept + """All sub concepts of a concept. Args: - concept: parent concept for which to get sub concepts + concept: Parent concept for which to get sub concepts. Returns: - sub concepts + Sub concepts. """ assert isinstance(concept, OWLClass) yield from self._class_hierarchy.sub_classes(concept, direct=False) def get_concepts(self) -> Iterable[OWLClass]: - """Get all concepts of this concept generator + """Get all concepts of this concept generator. Returns: - concepts + Concepts. """ yield from self._class_hierarchy.items() def get_object_properties(self) -> Iterable[OWLObjectProperty]: - """Get all object properties of this concept generator + """Get all object properties of this concept generator. Returns: - object properties + Object properties. """ yield from self._object_property_hierarchy.items() def get_data_properties(self, ranges: Set[OWLDatatype] = None) -> Iterable[OWLDataProperty]: - """Get all data properties of this concept generator for the given ranges + """Get all data properties of this concept generator for the given ranges. Args: - ranges: ranges for which to extract the data properties + ranges: Ranges for which to extract the data properties. Returns: - data properties for the given range + Data properties for the given range. """ if ranges is not None: for dp in self._data_property_hierarchy.items(): @@ -801,38 +809,38 @@ def get_data_properties(self, ranges: Set[OWLDatatype] = None) -> Iterable[OWLDa yield from self._data_property_hierarchy.items() def get_boolean_data_properties(self) -> Iterable[OWLDataProperty]: - """Get all boolean data properties of this concept generator + """Get all boolean data properties of this concept generator. Returns: - boolean data properties + Boolean data properties. """ yield from self.get_data_properties({BooleanOWLDatatype}) def get_numeric_data_properties(self) -> Iterable[OWLDataProperty]: - """Get all numeric data properties of this concept generator + """Get all numeric data properties of this concept generator. Returns: - numeric data properties + Numeric data properties. """ yield from self.get_data_properties(NUMERIC_DATATYPES) def get_time_data_properties(self) -> Iterable[OWLDataProperty]: - """Get all time data properties of this concept generator + """Get all time data properties of this concept generator. Returns: - time data properties + Time data properties. """ yield from self.get_data_properties(TIME_DATATYPES) def get_types(self, ind: OWLNamedIndividual, direct: bool = False) -> Iterable[OWLClass]: - """Get the named classes which are (direct) types of the specified individual + """Get the named classes which are (direct) types of the specified individual. Args: - ind: individual - direct: whether to consider direct types + ind: Individual. + direct: Whether to consider direct types. Returns: - types of the given individual + Types of the given individual. """ all_types = set(self.get_concepts()) for type_ in self._reasoner.types(ind, direct): @@ -841,16 +849,16 @@ def get_types(self, ind: OWLNamedIndividual, direct: bool = False) -> Iterable[O def get_object_properties_for_ind(self, ind: OWLNamedIndividual, direct: bool = True) \ -> Iterable[OWLObjectProperty]: - """Get the object properties for the given individual + """Get the object properties for the given individual. Args: - ind: individual + ind: Individual direct: Whether only direct properties should be considered (True), or if also indirect properties should be considered (False). Indirect properties - would be super properties super_p of properties p with ObjectPropertyAssertion(p ind obj) + would be super properties super_p of properties p with ObjectPropertyAssertion(p ind obj). Returns: - object properties + Object properties. """ properties = set(self.get_object_properties()) yield from (pe for pe in self._reasoner.ind_object_properties(ind, direct) if pe in properties) @@ -859,13 +867,13 @@ def get_data_properties_for_ind(self, ind: OWLNamedIndividual, direct: bool = Tr """Get the data properties for the given individual Args: - ind: individual + ind: Individual direct: Whether only direct properties should be considered (True), or if also indirect properties should be considered (False). Indirect properties - would be super properties super_p of properties p with ObjectPropertyAssertion(p ind obj) + would be super properties super_p of properties p with ObjectPropertyAssertion(p ind obj). Returns: - data properties + Data properties. """ properties = set(self.get_data_properties()) yield from (pe for pe in self._reasoner.ind_data_properties(ind, direct) if pe in properties) @@ -873,68 +881,67 @@ def get_data_properties_for_ind(self, ind: OWLNamedIndividual, direct: bool = Tr def get_object_property_values(self, ind: OWLNamedIndividual, property_: OWLObjectPropertyExpression, direct: bool = True) -> Iterable[OWLNamedIndividual]: - """Get the object property values for the given individual and property + """Get the object property values for the given individual and property. Args: - ind: individual - property_: object property + ind: Individual. + property_: Object property. direct: Whether only the property property_ should be considered (True), or if also - the values of sub properties of property_ should be considered (False) + the values of sub properties of property_ should be considered (False). Returns: - individuals + Individuals. """ yield from self._reasoner.object_property_values(ind, property_, direct) def get_data_property_values(self, ind: OWLNamedIndividual, property_: OWLDataPropertyExpression, direct: bool = True) -> Iterable[OWLLiteral]: - """Get the data property values for the given individual and property + """Get the data property values for the given individual and property. Args: - ind: individual - property_: data property + ind: Individual. + property_: Data property. direct: Whether only the property property_ should be considered (True), or if also - the values of sub properties of property_ should be considered (False) + the values of sub properties of property_ should be considered (False). Returns: - literals + Literals. """ yield from self._reasoner.data_property_values(ind, property_, direct) def contains_class(self, concept: OWLClassExpression) -> bool: - """Check if an atomic class is contained within this concept generator + """Check if an atomic class is contained within this concept generator. Args: - concept: atomic class + concept: Atomic class. Returns: - whether the class is contained in the concept generator + Whether the class is contained in the concept generator. """ assert isinstance(concept, OWLClass) return concept in self._class_hierarchy def class_hierarchy(self) -> ClassHierarchy: - """Access the Class Hierarchy of this Concept Generator + """Access the Class Hierarchy of this Concept Generator. Returns: - class hierarchy + Class hierarchy. """ return self._class_hierarchy def object_property_hierarchy(self) -> ObjectPropertyHierarchy: - """Access the Object property hierarchy of this concept generator + """Access the Object property hierarchy of this concept generator. Returns: - object property hierarchy + Object property hierarchy. """ return self._object_property_hierarchy def data_property_hierarchy(self) -> DatatypePropertyHierarchy: - """Access the Datatype property hierarchy of this concept generator + """Access the Datatype property hierarchy of this concept generator. Returns: - data property hierarchy + Data property hierarchy. """ return self._data_property_hierarchy - diff --git a/ontolearn/learning_problem.py b/ontolearn/learning_problem.py index f905e0e5..bb13d5ff 100644 --- a/ontolearn/learning_problem.py +++ b/ontolearn/learning_problem.py @@ -1,3 +1,4 @@ +"""Learning problem in Ontolearn.""" import logging from typing import Set, Optional, TYPE_CHECKING @@ -10,6 +11,14 @@ class EncodedPosNegLPStandard(EncodedPosNegLPStandardKind): + """Encoded learning problem standard. + + Attributes: + kb_pos (set): Positive examples. + kb_neg (set): Negative examples. + kb_diff (set): kb_all - (kb_pos + kb_neg). + kb_all (set): All examples/ all individuals set. + """ __slots__ = 'kb_pos', 'kb_neg', 'kb_diff', 'kb_all' kb_pos: set @@ -18,6 +27,14 @@ class EncodedPosNegLPStandard(EncodedPosNegLPStandardKind): kb_all: set def __init__(self, kb_pos, kb_neg, kb_diff, kb_all): + """Create a new instance of EncodedPosNegLPStandard. + + Args: + kb_pos (set): Positive examples. + kb_neg (set): Negative examples. + kb_diff (set): kb_all - (kb_pos + kb_neg). + kb_all (set): All examples/ all individuals set. + """ self.kb_pos = kb_pos self.kb_neg = kb_neg self.kb_diff = kb_diff @@ -25,6 +42,12 @@ def __init__(self, kb_pos, kb_neg, kb_diff, kb_all): class PosNegLPStandard(AbstractLearningProblem): + """Positive-Negative learning problem standard. + Attributes: + pos: Positive examples. + neg: Negative examples. + all: All examples. + """ __slots__ = 'pos', 'neg', 'all' def __init__(self, @@ -36,6 +59,11 @@ def __init__(self, 1) Convert the string representation of an individuals into the owlready2 representation. 2) Sample negative examples if necessary. 3) Initialize the root and search tree. + + Args: + pos: Positive examples. + neg: Negative examples. + all_instances: All examples. """ assert isinstance(pos, set) and isinstance(neg, set) self.pos = frozenset(pos) @@ -50,10 +78,12 @@ def encode_kb(self, knowledge_base: 'KnowledgeBase') -> EncodedPosNegLPStandard: class EncodedPosNegUndLP(EncodedLearningProblem): + """To be implemented.""" ... # XXX: TODO class PosNegUndLP(AbstractLearningProblem): + """To be implemented.""" ... # XXX: TODO diff --git a/ontolearn/learning_problem_generator.py b/ontolearn/learning_problem_generator.py index 8b6dad83..cbb0b57f 100644 --- a/ontolearn/learning_problem_generator.py +++ b/ontolearn/learning_problem_generator.py @@ -1,12 +1,13 @@ +"""Learning problem generator.""" import sys import time from typing import Literal, Iterable, Set, Tuple, Dict, List, Final, Generator import numpy as np -from ontolearn.owlapy.model import OWLClassExpression, OWLOntologyManager, OWLOntology, AddImport, OWLImportsDeclaration, \ - OWLClass, OWLEquivalentClassesAxiom, IRI, OWLNamedIndividual, OWLAnnotationAssertionAxiom, OWLAnnotation, \ - OWLAnnotationProperty, OWLLiteral +from ontolearn.owlapy.model import OWLClassExpression, OWLOntologyManager, OWLOntology, AddImport, \ + OWLImportsDeclaration, OWLClass, OWLEquivalentClassesAxiom, IRI, OWLNamedIndividual, OWLAnnotationAssertionAxiom, \ + OWLAnnotation, OWLAnnotationProperty, OWLLiteral from ontolearn.knowledge_base import KnowledgeBase from .refinement_operators import LengthBasedRefinement from .search import Node, RL_State @@ -16,15 +17,15 @@ class LearningProblemGenerator: - """ Learning problem generator. """ + """Learning problem generator.""" def __init__(self, knowledge_base: KnowledgeBase, refinement_operator=None, num_problems=10_000, num_diff_runs=100, min_num_instances=None, max_num_instances=sys.maxsize, min_length=3, max_length=5, depth=3, search_algo='strict-dfs'): """ Generate concepts via search algorithm to satisfy constraints. - strict-dfs considers (min_length, max_length, min_num_ind, num_problems) as hard constraints. - dfs- considers (min_length, max_length, min_num_ind) as hard constraints and soft (>=num_problems). + 'strict-dfs' considers (min_length, max_length, min_num_ind, num_problems) as hard constraints. + 'dfs' considers (min_length, max_length, min_num_ind) as hard constraints and soft (>=num_problems). Trade-off between num_diff_runs and num_problems. """ @@ -54,11 +55,11 @@ def __init__(self, knowledge_base: KnowledgeBase, refinement_operator=None, num_ self.num_problems = num_problems // self.num_diff_runs def export_concepts(self, concepts: List[Node], path: str): - """Serialise the given concepts to a file + """Serialise the given concepts to a file. Args: - concepts: list of Node objects - path: filename base (extension will be added automatically) + concepts (list): Node objects. + path (str): Filename base (extension will be added automatically). """ SNS: Final = 'https://dice-research.org/predictions-schema/' NS: Final = 'https://dice-research.org/predictions/' + str(time.time()) + '#' @@ -120,17 +121,10 @@ def get_balanced_n_samples_per_examples(self, *, n=5, min_num_problems=None, max search_algo='strict-dfs') \ -> Iterable[Tuple[RL_State, Set[OWLNamedIndividual], Set[OWLNamedIndividual]]]: """ - 1. We generate min_num_problems number of concepts - 2. For each concept, we generate n number of positive and negative examples - 3. Each example contains - @param n: - @param min_num_problems: - @param max_length: - @param min_length: - @param num_diff_runs: - @param min_num_instances: - @param search_algo: - @return: + + 1. We generate min_num_problems number of concepts. + 2. For each concept, we generate n number of positive and negative examples. + 3. Each example contains n samples. """ assert max_length >= min_length @@ -185,21 +179,17 @@ def balanced_n_sampled_lp(self, n: int, string_all_pos: set): def get_balanced_examples(self, *, min_num_problems=None, max_length=None, min_length=None, num_diff_runs=None, min_num_instances=None, search_algo='strict-dfs') -> list: + """ (1) Generate valid examples with input search algorithm. (2) Balance valid examples. - @param min_num_problems: - @param max_length: - @param min_length: - @param num_diff_runs: - @param min_num_instances: - @param search_algo: 'dfs' or 'strict-'dfs=> strict-dfs considers num_problems as a hard constrain. - @return: A list of tuples (s,p,n) where s denotes the string representation of a concept, - p and n denote a set of URIs of individuals indicating positive and negative examples. + Returns: + A list of balanced tuples (s,p,n) where s denotes the string representation of a concept, p and n denote + a set of URIs of individuals indicating positive and negative examples. """ - + # @param search_algo: 'dfs' or 'strict-dfs'=> strict-dfs considers num_problems as a hard constraint. def output_sanity_check(y): try: assert len(y) >= min_num_problems @@ -229,14 +219,9 @@ def get_examples(self, *, num_problems=None, max_length=None, min_length=None, """ (1) Get valid examples with input search algorithm. - @param num_problems: - @param max_length: - @param min_length: - @param num_diff_runs: - @param min_num_ind: - @param search_algo: 'dfs' or 'strict-'dfs=> strict-dfs considers num_problems as hard constriant. - @return: A list of tuples (s,p,n) where s denotes the string representation of a concept, - p and n denote a set of URIs of individuals indicating positive and negative examples. + Returns: + A list of tuples (s,p,n) where s denotes the string representation of a concept, p and n denote + a set of URIs of individuals indicating positive and negative examples. """ res = [] @@ -256,17 +241,7 @@ def get_examples(self, *, num_problems=None, max_length=None, min_length=None, def get_concepts(self, *, num_problems=None, max_length=None, min_length=None, max_num_instances=None, num_diff_runs=None, min_num_instances=None, search_algo=None) -> Generator: - """ - @param max_num_instances: - @param num_problems: - @param max_length: - @param min_length: - @param num_diff_runs: - @param min_num_instances: - @param search_algo: 'dfs' or 'strict-'dfs=> strict-dfs considers num_problems as hard constriant. - @return: A list of tuples (s,p,n) where s denotes the string representation of a concept, - p and n denote a set of URIs of individuals indicating positive and negative examples. - """ + """Calls `generate_examples` """ return self.generate_examples(num_problems=num_problems, max_length=max_length, min_length=min_length, num_diff_runs=num_diff_runs, @@ -278,16 +253,10 @@ def generate_examples(self, *, num_problems=None, max_length=None, min_length=No num_diff_runs=None, max_num_instances=None, min_num_instances=None, search_algo=None) -> Generator: """ - Generate examples via search algorithm that are valid examples w.r.t. given constraints - - @param num_diff_runs: - @param num_problems: - @param max_length: - @param min_length: - @param min_num_instances: - @param max_num_instances: - @param search_algo: - @return: + Generate examples via search algorithm that are valid examples w.r.t. given constraints. + + Returns: + Valid examples """ if num_problems and num_diff_runs: assert isinstance(num_problems, int) @@ -340,8 +309,6 @@ def generate_examples(self, *, num_problems=None, max_length=None, min_length=No def _apply_dfs(self, strict=False) -> Generator: """ Apply depth first search with backtracking to generate concepts. - - @return: """ def f1(x): @@ -415,13 +382,6 @@ def f2(x): @staticmethod # @performance_debugger('_apply_dfs_on_state') def _apply_dfs_on_state(state, depth, apply_rho, constrain_func=None, patience_per_depth=None) -> set: - """ - - @param state: - @param depth: - @param apply_rho: - @return: - """ valid_examples = set() invalid_examples = set() diff --git a/ontolearn/metrics.py b/ontolearn/metrics.py index b54db80c..656d4aa0 100644 --- a/ontolearn/metrics.py +++ b/ontolearn/metrics.py @@ -1,10 +1,15 @@ +"""Quality metrics for concept learners.""" from typing import Final, Tuple from .abstracts import AbstractScorer -from .learning_problem import EncodedPosNegLPStandard class Recall(AbstractScorer): + """Recall quality function. + + Attribute: + name: name of the metric = 'Recall'. + """ __slots__ = () name: Final = 'Recall' @@ -18,6 +23,11 @@ def score2(self, tp: int, fn: int, fp: int, tn: int) -> Tuple[bool, float]: class Precision(AbstractScorer): + """Precision quality function. + + Attribute: + name: name of the metric = 'Precision'. + """ __slots__ = () name: Final = 'Precision' @@ -31,6 +41,11 @@ def score2(self, tp: int, fn: int, fp: int, tn: int) -> Tuple[bool, float]: class F1(AbstractScorer): + """F1-score quality function. + + Attribute: + name: name of the metric = 'F1'. + """ __slots__ = () name: Final = 'F1' @@ -55,19 +70,23 @@ def score2(self, tp: int, fn: int, fp: int, tn: int) -> Tuple[bool, float]: class Accuracy(AbstractScorer): """ - Accuracy is acc = (tp + tn) / (tp + tn + fp+ fn). However, - Concept learning papers (e.g. Learning OWL Class expression) appear to invernt their own accuracy metrics. + Accuracy quality function. + Accuracy is acc = (tp + tn) / (tp + tn + fp+ fn). + However, Concept learning papers (e.g. Learning OWL Class expression) appear to invent their own accuracy metrics. - In OCEL => Accuracy of a concept = 1 - ( \\|E^+ \\ R(C)\\|+ \\|E^- AND R(C)\\|) / \\|E\\|) + In OCEL => Accuracy of a concept = 1 - ( \\|E^+ \\ R(C)\\|+ \\|E^- AND R(C)\\|) / \\|E\\|). - In CELOE => Accuracy of a concept C = 1 - ( \\|R(A) \\ R(C)\\| + \\|R(C) \\ R(A)\\|)/n + In CELOE => Accuracy of a concept C = 1 - ( \\|R(A) \\ R(C)\\| + \\|R(C) \\ R(A)\\|)/n. 1) R(.) is the retrieval function, A is the class to describe and C in CELOE. 2) E^+ and E^- are the positive and negative examples probided. E = E^+ OR E^- . + + Attribute: + name: name of the metric = 'Accuracy'. """ __slots__ = () @@ -81,6 +100,12 @@ def score2(self, tp: int, fn: int, fp: int, tn: int) -> Tuple[bool, float]: class WeightedAccuracy(AbstractScorer): + """ + WeightedAccuracy quality function. + + Attribute: + name: name of the metric = 'WeightedAccuracy'. + """ __slots__ = () name: Final = 'WeightedAccuracy' diff --git a/ontolearn/model_adapter.py b/ontolearn/model_adapter.py index 954723a7..c8708cbb 100644 --- a/ontolearn/model_adapter.py +++ b/ontolearn/model_adapter.py @@ -1,20 +1,22 @@ +"""Model adaptors.""" import inspect import logging -from typing import TypeVar +from typing import TypeVar, List, Optional, Union from ontolearn.abstracts import AbstractHeuristic, AbstractScorer, BaseRefinement, AbstractKnowledgeBase, \ AbstractNode from ontolearn.base_concept_learner import BaseConceptLearner -from ontolearn.owlapy.model import OWLReasoner +from ontolearn.owlapy.model import OWLReasoner, OWLNamedIndividual, OWLClassExpression, OWLAxiom from ontolearn.owlapy.owlready2.complex_ce_instances import OWLReasoner_Owlready2_ComplexCEInstances logger = logging.getLogger(__name__) # TODO:CD: Move all imports to the top of the file + def _get_matching_opts(_Type, optargs, kwargs, *, prefix=None): - """find the keys in kwargs that are parameters of _Type + """Find the keys in kwargs that are parameters of _Type. - if prefix is specified, the keys in kwargs need to be prefixed with prefix_ + If prefix is specified, the keys in kwargs need to be prefixed with prefix_. """ opts = {} if prefix is None: @@ -44,21 +46,34 @@ def p(s): def ModelAdapter(*args, **kwargs): # noqa: C901 - """Create a new Concept learner through the model adapter + """Instantiate a model through the model adapter. + + .. warning :: + You should not specify both: the _type and the object. For + example, you should not give both 'reasoner' and 'reasoner_type' because the ModelAdaptor cant decide + which one to use, the reasoner object or create a new reasoner instance using 'reasoner_type'. + + Note: + If you give `_type` for an argument you can pass further arguments to construct the instance of that + class. The model adapter will arrange every argument automatically and use them to construct an object + for that certain class type. Args: - knowledge_base (AbstractKnowledgeBase): a knowledge base - knowledge_base_type: a knowledge base type - ...: knowledge base arguments - refinement_operator_type: a refinement operator type - ...: refinement operator arguments - quality_type: an Abstract Scorer type - ...: quality arguments - heuristic_func (AbstractHeuristic): a heuristic - heuristic_type: an Abstract Heuristic type - ...: arguments for the heuristic type - learner_type: a Base Concept Learner type - ...: arguments for the learning algorithm + knowledge_base (AbstractKnowledgeBase): A knowledge base. + knowledge_base_type: A knowledge base type. + ...: Knowledge base arguments. + reasoner: A reasoner. + reasoner_type: A reasoner type. + ...: Reasoner constructor arguments. + refinement_operator_type: A refinement operator type. + ...: Refinement operator arguments. + quality_type: An Abstract Scorer type. + ...: Quality arguments. + heuristic_func (AbstractHeuristic): A heuristic. + heuristic_type: An Abstract Heuristic type. + ...: arguments For the heuristic type. + learner_type: A Base Concept Learner type. + ...: Arguments for the learning algorithm. """ if "knowledge_base" in kwargs: kb = kwargs.pop("knowledge_base") @@ -205,3 +220,72 @@ def ModelAdapter(*args, **kwargs): # noqa: C901 )) return learner + + +class Trainer: + def __init__(self, learner: BaseConceptLearner, reasoner: OWLReasoner): + """ + A class to disentangle the learner from its training. + + Args: + learner: The concept learner. + reasoner: The reasoner to use (should have the same ontology as the `kb` argument of the learner). + """ + assert reasoner.get_root_ontology().get_ontology_id().get_ontology_iri().as_str() == \ + learner.kb.ontology().get_ontology_id().get_ontology_iri().as_str(), "New reasoner does not have " + \ + "the same ontology as the learner!" + learner.reasoner = reasoner + self.learner = learner + self.reasoner = reasoner + + def fit(self, *args, **kwargs): + """Run the concept learning algorithm according to its configuration. + + Once finished, the results can be queried with the `best_hypotheses` function.""" + self.learner.fit(*args, **kwargs) + + def best_hypotheses(self, n): + """Get the current best found hypotheses according to the quality. + + Args: + n: Maximum number of results. + + Returns: + Iterable with hypotheses in form of search tree nodes. + """ + return self.learner.best_hypotheses(n) + + def predict(self, individuals: List[OWLNamedIndividual], + hypotheses: Optional[List[Union[_N, OWLClassExpression]]] = None, + axioms: Optional[List[OWLAxiom]] = None, n: int = 10): + """Creates a binary data frame showing for each individual whether it is entailed in the given hypotheses + (class expressions). The individuals do not have to be in the ontology/knowledge base yet. In that case, + axioms describing these individuals must be provided. + + The state of the knowledge base/ontology is not changed, any provided axioms will be removed again. + + Args: + individuals: A list of individuals/instances. + hypotheses: (Optional) A list of search tree nodes or class expressions. If not provided, the + current :func:`BaseConceptLearner.best_hypothesis` of the concept learner are used. + axioms: (Optional) A list of axioms that are not in the current knowledge base/ontology. + If the individual list contains individuals that are not in the ontology yet, axioms + describing these individuals must be provided. The argument can also be used to add + arbitrary axioms to the ontology for the prediction. + n: Integer denoting number of ALC concepts to extract from search tree if hypotheses=None. + + Returns: + Pandas data frame with dimensions |individuals|*|hypotheses| indicating for each individual and each + hypothesis whether the individual is entailed in the hypothesis. + """ + return self.learner.predict(individuals, hypotheses, axioms, n) + + def save_best_hypothesis(self, n: int = 10, path: str = 'Predictions', rdf_format: str = 'rdfxml') -> None: + """Serialise the best hypotheses to a file. + + Args: + n: Maximum number of hypotheses to save. + path: Filename base (extension will be added automatically). + rdf_format: Serialisation format. currently supported: "rdfxml". + """ + self.learner.save_best_hypothesis(n, path, rdf_format) diff --git a/ontolearn/nces_architectures.py b/ontolearn/nces_architectures.py index 8cfa99d9..fa7edcee 100644 --- a/ontolearn/nces_architectures.py +++ b/ontolearn/nces_architectures.py @@ -1,9 +1,11 @@ -import torch, torch.nn as nn, numpy as np -import torch.nn.functional as F +"""NCES architectures.""" from ontolearn.nces_modules import * + class LSTM(nn.Module): - def __init__(self, knowledge_base_path, vocab, inv_vocab, max_length, input_size, proj_dim, rnn_n_layers, drop_prob): + """LSTM module.""" + def __init__(self, knowledge_base_path, vocab, inv_vocab, max_length, input_size, proj_dim, rnn_n_layers, + drop_prob): super().__init__() self.name = 'LSTM' self.max_len = max_length @@ -16,13 +18,13 @@ def __init__(self, knowledge_base_path, vocab, inv_vocab, max_length, input_size self.fc1 = nn.Linear(2*proj_dim, proj_dim) self.fc2 = nn.Linear(proj_dim, proj_dim) self.fc3 = nn.Linear(proj_dim, len(self.vocab)*max_length) - + def forward(self, x1, x2, target_scores=None): seq1, _ = self.lstm(x1) seq2, _ = self.lstm(x2) out1 = seq1.sum(1).view(-1, self.proj_dim) out2 = seq2.sum(1).view(-1, self.proj_dim) - x = torch.cat([out1,out2], 1) + x = torch.cat([out1, out2], 1) x = F.gelu(self.fc1(x)) x = x + F.relu(self.fc2(x)) x = self.bn(x) @@ -31,9 +33,11 @@ def forward(self, x1, x2, target_scores=None): aligned_chars = self.inv_vocab[x.argmax(1).cpu()] return aligned_chars, x - + class GRU(nn.Module): - def __init__(self, knowledge_base_path, vocab, inv_vocab, max_length, input_size, proj_dim, rnn_n_layers, drop_prob): + """GRU module.""" + def __init__(self, knowledge_base_path, vocab, inv_vocab, max_length, input_size, proj_dim, rnn_n_layers, + drop_prob): super().__init__() self.name = 'GRU' self.max_len = max_length @@ -46,13 +50,13 @@ def __init__(self, knowledge_base_path, vocab, inv_vocab, max_length, input_size self.fc1 = nn.Linear(2*proj_dim, proj_dim) self.fc2 = nn.Linear(proj_dim, proj_dim) self.fc3 = nn.Linear(proj_dim, len(self.vocab)*max_length) - + def forward(self, x1, x2, target_scores=None): seq1, _ = self.gru(x1) seq2, _ = self.gru(x2) out1 = seq1.sum(1).view(-1, self.proj_dim) out2 = seq2.sum(1).view(-1, self.proj_dim) - x = torch.cat([out1,out2], 1) + x = torch.cat([out1, out2], 1) x = F.gelu(self.fc1(x)) x = x + F.relu(self.fc2(x)) x = self.bn(x) @@ -61,9 +65,11 @@ def forward(self, x1, x2, target_scores=None): aligned_chars = self.inv_vocab[x.argmax(1).cpu()] return aligned_chars, x - + class SetTransformer(nn.Module): - def __init__(self, knowledge_base_path, vocab, inv_vocab, max_length, input_size, proj_dim, num_heads, num_seeds, num_inds, ln): + """SetTransformer module.""" + def __init__(self, knowledge_base_path, vocab, inv_vocab, max_length, input_size, proj_dim, num_heads, num_seeds, + num_inds, ln): super(SetTransformer, self).__init__() self.name = 'SetTransformer' self.max_len = max_length @@ -80,7 +86,7 @@ def __init__(self, knowledge_base_path, vocab, inv_vocab, max_length, input_size def forward(self, x1, x2): x1 = self.enc(x1) x2 = self.enc(x2) - x = torch.cat([x1,x2], -2) + x = torch.cat([x1, x2], -2) x = self.dec(x).reshape(-1, len(self.vocab), self.max_len) aligned_chars = self.inv_vocab[x.argmax(1).cpu()] return aligned_chars, x diff --git a/ontolearn/nces_data_generator/generate_data.py b/ontolearn/nces_data_generator/generate_data.py index 5301dc97..7b3ac81f 100644 --- a/ontolearn/nces_data_generator/generate_data.py +++ b/ontolearn/nces_data_generator/generate_data.py @@ -1,4 +1,6 @@ -import os, argparse, json +import os +import argparse +import json from helper_classes import RDFTriples, KB2Data base_path = os.path.dirname(os.path.realpath(__file__)).split("ontolearn")[0] @@ -6,11 +8,13 @@ parser = argparse.ArgumentParser() parser.add_argument('--kbs', type=str, nargs='+', default=['carcinogenesis'], help='Knowledge base name') -parser.add_argument('--num_rand_samples', type=int, default=200, help='The number of random samples at each step of the generation process') +parser.add_argument('--num_rand_samples', type=int, default=200, + help='The number of random samples at each step of the generation process') parser.add_argument('--depth', type=int, default=3, help='The depth of refinements') parser.add_argument('--max_child_len', type=int, default=15, help='Maximum child length') parser.add_argument('--refinement_expressivity', type=float, default=0.5) -parser.add_argument('--rho', type=str, default='ExpressRefinement', choices=['ExpressRefinement'], help='Refinement operator to use') +parser.add_argument('--rho', type=str, default='ExpressRefinement', choices=['ExpressRefinement'], + help='Refinement operator to use') args = parser.parse_args() @@ -19,5 +23,7 @@ triples.export_triples() with open(f'{base_path}NCESData/{kb}/data_generation_settings.json', "w") as setting: json.dump(vars(args), setting) - DataGen = KB2Data(path=f'{base_path}NCESData/{kb}/{kb}.owl', rho_name=args.rho, depth=args.depth, max_child_length=args.max_child_len, refinement_expressivity=args.refinement_expressivity, downsample_refinements=True, num_rand_samples=args.num_rand_samples, min_num_pos_examples=1) - DataGen.generate_descriptions().save_data() \ No newline at end of file + DataGen = KB2Data(path=f'{base_path}NCESData/{kb}/{kb}.owl', rho_name=args.rho, depth=args.depth, + max_child_length=args.max_child_len, refinement_expressivity=args.refinement_expressivity, + downsample_refinements=True, num_rand_samples=args.num_rand_samples, min_num_pos_examples=1) + DataGen.generate_descriptions().save_data() diff --git a/ontolearn/nces_data_generator/helper_classes.py b/ontolearn/nces_data_generator/helper_classes.py index db506195..aef68371 100644 --- a/ontolearn/nces_data_generator/helper_classes.py +++ b/ontolearn/nces_data_generator/helper_classes.py @@ -4,7 +4,9 @@ from ontolearn.knowledge_base import KnowledgeBase from ontolearn.owlapy.render import DLSyntaxObjectRenderer from ontolearn.refinement_operators import ExpressRefinement -import os, json +import os +import json + class ConceptDescriptionGenerator: """ @@ -25,31 +27,33 @@ def generate(self): roots = self.apply_rho(self.kb.generator.thing) Refinements = set() Refinements.update(roots) - print ("|Thing refinements|: ", len(roots)) + print("|Thing refinements|: ", len(roots)) roots_sample = random.sample(list(roots), k=self.num_rand_samples) print("Size of sample: ", len(roots_sample)) for root in tqdm(roots_sample, desc="Refining roots..."): Refinements.update(self.apply_rho(root)) return Refinements - - + + class RDFTriples: - """The knowledge graph/base is converted into triples of the form: individual_i ---role_j---> concept_k or individual_i ---role_j---> individual_k - and stored in a txt file for the computation of embeddings.""" - + """The knowledge graph/base is converted into triples of the form: individual_i ---role_j---> concept_k or + individual_i ---role_j---> individual_k and stored in a txt file for the computation of embeddings.""" + def __init__(self, source_kg_path): self.Graph = graph.Graph() self.Graph.parse(source_kg_path) self.source_kg_path = source_kg_path - + def export_triples(self, export_folder_name='triples'): if not os.path.exists(os.path.join(self.source_kg_path[:self.source_kg_path.rfind("/")], export_folder_name)): os.mkdir(os.path.join(self.source_kg_path[:self.source_kg_path.rfind("/")], export_folder_name)) - if os.path.isfile(os.path.join(self.source_kg_path[:self.source_kg_path.rfind("/")], export_folder_name, "train.txt")): + if os.path.isfile(os.path.join(self.source_kg_path[:self.source_kg_path.rfind("/")], export_folder_name, + "train.txt")): print("\n*** Embedding triples exist ***\n") return - train_file = open("%s/train.txt" % os.path.join(self.source_kg_path[:self.source_kg_path.rfind("/")], export_folder_name), mode="w") - for s,p,o in self.Graph: + train_file = open("%s/train.txt" % os.path.join(self.source_kg_path[:self.source_kg_path.rfind("/")], + export_folder_name), mode="w") + for s, p, o in self.Graph: s = s.expandtabs()[s.expandtabs().rfind("/")+1:] p = p.expandtabs()[p.expandtabs().rfind("/")+1:] o = o.expandtabs()[o.expandtabs().rfind("/")+1:] @@ -58,14 +62,18 @@ def export_triples(self, export_folder_name='triples'): train_file.close() print("*********************Finished exporting triples*********************\n") + class KB2Data: """ This class takes an owl file, loads it into a knowledge base using ontolearn.knowledge_base.KnowledgeBase. - A refinement operator is used to generate a large number of concepts, from which we filter and retain the shortest non-redundant concepts. - Finally, we aim at training a deep neural network to predict the syntax of concepts from their instances. Hence, we export each concept and its instances (eventually positive and negative examples) into json files. + A refinement operator is used to generate a large number of concepts, from which we filter and retain the shortest + non-redundant concepts. Finally, we aim at training a deep neural network to predict the syntax of concepts from + their instances. Hence, we export each concept and its instances (eventually positive and negative examples) into + json files. """ - def __init__(self, path, rho_name="ExpressRefinement", depth=5, max_child_length=25, refinement_expressivity=0.6, downsample_refinements=True, k=10, num_rand_samples=150, min_num_pos_examples=1): + def __init__(self, path, rho_name="ExpressRefinement", depth=5, max_child_length=25, refinement_expressivity=0.6, + downsample_refinements=True, k=10, num_rand_samples=150, min_num_pos_examples=1): self.path = path self.dl_syntax_renderer = DLSyntaxObjectRenderer() self.kb = KnowledgeBase(path=path) @@ -73,17 +81,18 @@ def __init__(self, path, rho_name="ExpressRefinement", depth=5, max_child_length self.min_num_pos_examples = min_num_pos_examples atomic_concepts = frozenset(self.kb.ontology().classes_in_signature()) self.atomic_concept_names = frozenset([self.dl_syntax_renderer.render(a) for a in atomic_concepts]) - rho = ExpressRefinement(knowledge_base=self.kb, max_child_length=max_child_length, sample_fillers_count=k, downsample=downsample_refinements,\ - use_inverse=False, use_card_restrictions=False, use_numeric_datatypes=False, use_time_datatypes=False,\ - use_boolean_datatype=False, expressivity=refinement_expressivity) - self.lp_gen = ConceptDescriptionGenerator(knowledge_base=self.kb, refinement_operator=rho, depth=depth, num_rand_samples=num_rand_samples) + rho = ExpressRefinement(knowledge_base=self.kb, max_child_length=max_child_length, sample_fillers_count=k, + downsample=downsample_refinements, use_inverse=False, use_card_restrictions=False, + use_numeric_datatypes=False, use_time_datatypes=False, use_boolean_datatype=False, + expressivity=refinement_expressivity) + self.lp_gen = ConceptDescriptionGenerator(knowledge_base=self.kb, refinement_operator=rho, depth=depth, + num_rand_samples=num_rand_samples) - def find_optimal_number_of_examples(self): if self.kb.individuals_count() >= 600: return min(self.kb.individuals_count()//2, 1000) return self.kb.individuals_count() - + def generate_descriptions(self): print() print("#"*60) @@ -96,22 +105,25 @@ def generate_descriptions(self): non_redundancy_hash_map = dict() show_some_length = True for concept in tqdm(sorted(Concepts, key=lambda c: self.kb.concept_len(c)), desc="Filtering process..."): - if not self.kb.individuals_set(concept) in non_redundancy_hash_map and self.min_num_pos_examples <= self.kb.individuals_count(concept): + if not self.kb.individuals_set(concept) in non_redundancy_hash_map and \ + self.min_num_pos_examples <= self.kb.individuals_count(concept): non_redundancy_hash_map[self.kb.individuals_set(concept)] = concept - else: continue + else: + continue if self.kb.concept_len(concept) >= 15 and show_some_length: print("A long concept found: ", self.kb.concept_len(concept)) show_some_length = False print("Concepts generation done!\n") print("Number of atomic concepts: ", len(self.atomic_concept_names)) - print("Longest concept length: ", max({l for l in [self.kb.concept_len(c) for c in non_redundancy_hash_map.values()]}), "\n") + print("Longest concept length: ", + max({l for l in [self.kb.concept_len(c) for c in non_redundancy_hash_map.values()]}), "\n") print("Total number of concepts: ", len(non_redundancy_hash_map), "\n") self.train_concepts = list(non_redundancy_hash_map.values()) print("Data generation completed") return self - + def sample_examples(self, pos, neg): - if min(len(pos),len(neg)) >= self.num_examples//2: + if min(len(pos), len(neg)) >= self.num_examples//2: if len(pos) > len(neg): num_neg_ex = self.num_examples//2 num_pos_ex = self.num_examples-num_neg_ex @@ -133,7 +145,8 @@ def save_data(self): for concept in tqdm(self.train_concepts, desc="Sample examples and save data..."): pos = set(self.kb.individuals(concept)) neg = set(self.kb.individuals())-pos - if len(neg) == 0: continue + if len(neg) == 0: + continue pos = [ind.get_iri().as_str().split("/")[-1] for ind in pos] neg = [ind.get_iri().as_str().split("/")[-1] for ind in neg] positive, negative = self.sample_examples(pos, neg) @@ -143,4 +156,4 @@ def save_data(self): os.makedirs(f'{self.path[:self.path.rfind("/")]}/training_data/', exist_ok=True) with open(f'{self.path[:self.path.rfind("/")]}/training_data/Data.json', 'w') as file_train: json.dump(dict(data), file_train, indent=3, ensure_ascii=False) - print(f'Data saved at {self.path[:self.path.rfind("/")]}') \ No newline at end of file + print(f'Data saved at {self.path[:self.path.rfind("/")]}') diff --git a/ontolearn/nces_embeddings/compute_embeddings.py b/ontolearn/nces_embeddings/compute_embeddings.py index c17f14bd..c1a9a67c 100644 --- a/ontolearn/nces_embeddings/compute_embeddings.py +++ b/ontolearn/nces_embeddings/compute_embeddings.py @@ -2,18 +2,21 @@ from util.data import Data import traceback import argparse -import os, sys +import os base_path = os.path.dirname(os.path.realpath(__file__)).split("ontolearn")[0] + def start(args): - datasets = [Data(data_dir=f'{base_path}NCESData/{f}/triples/', train_plus_valid=args.train_plus_valid) for f in args.kbs] + datasets = [Data(data_dir=f'{base_path}NCESData/{f}/triples/', + train_plus_valid=args.train_plus_valid) for f in args.kbs] for i, d in enumerate(datasets): folder_name = args.kbs[i] experiment = Experiment(dataset=d, model=args.model_name, parameters=vars(args), ith_logger='_' + folder_name, - store_emb_dataframe=args.store_emb_dataframe, storage_path=f"{base_path}NCESData/{folder_name}/embeddings") + store_emb_dataframe=args.store_emb_dataframe, + storage_path=f"{base_path}NCESData/{folder_name}/embeddings") print('Storage path: ', f"{base_path}NCESData/{folder_name}/embeddings") try: experiment.train_and_eval() @@ -23,7 +26,8 @@ def start(args): traceback.print_exc() print('Exit.') exit(1) - + + def str2bool(v): if isinstance(v, bool): return v @@ -42,7 +46,8 @@ def str2bool(v): parser.add_argument('--num_of_epochs', type=int, default=100) parser.add_argument('--batch_size', type=int, default=512) parser.add_argument('--scoring_technique', default='KvsAll', - help="KvsAll technique or Negative Sampling. For Negative Sampling, use any positive integer as input parameter") + help="KvsAll technique or Negative Sampling. For Negative Sampling, use any positive integer " + "as input parameter") parser.add_argument('--label_smoothing', type=float, default=0.1) parser.add_argument('--learning_rate', type=float, default=.01) parser.add_argument('--optim', type=str, default='RMSprop', help='Choose optimizer: Adam or RMSprop') @@ -57,7 +62,8 @@ def str2bool(v): parser.add_argument('--kernel_size', type=int, default=3) parser.add_argument("--kbs", nargs='+', type=str, default=folders) parser.add_argument('--num_workers', type=int, default=4, help='Number of cpus used during batching') - parser.add_argument('--store_emb_dataframe', type=str2bool, const=True, default=True, nargs='?', help="Whether to store the embeddings") + parser.add_argument('--store_emb_dataframe', type=str2bool, const=True, default=True, nargs='?', + help="Whether to store the embeddings") args = parser.parse_args() if args.model_name in ["ConEx", "Complex"]: args.embedding_dim = args.embedding_dim // 2 diff --git a/ontolearn/nces_embeddings/util/complex_models.py b/ontolearn/nces_embeddings/util/complex_models.py index 69d6fa61..2249a381 100644 --- a/ontolearn/nces_embeddings/util/complex_models.py +++ b/ontolearn/nces_embeddings/util/complex_models.py @@ -1,9 +1,9 @@ import torch -from torch.nn import functional as F, Parameter +from torch.nn import functional as F import numpy as np from torch.nn.init import xavier_normal_ import torch.nn as nn -import torch.optim as optim + torch.backends.cudnn.deterministic = True seed = 1 @@ -105,7 +105,8 @@ def __init__(self, params=None): self.conv1 = torch.nn.Conv2d(in_channels=1, out_channels=self.num_of_output_channels, kernel_size=(self.kernel_size, self.kernel_size), stride=1, padding=1, bias=True) # Formula for convolution output shape: (input_dim + 2* padding - kernel_size) / (stride) + 1 - self.fc_num_input = ((self.embedding_dim+2-self.kernel_size)+1) * (4+2-self.kernel_size+1) * self.num_of_output_channels + self.fc_num_input = ((self.embedding_dim+2-self.kernel_size)+1) * \ + (4+2-self.kernel_size+1) * self.num_of_output_channels self.fc = torch.nn.Linear(self.fc_num_input, self.embedding_dim * 2) self.bn_conv1 = torch.nn.BatchNorm2d(self.num_of_output_channels) @@ -131,7 +132,7 @@ def residual_convolution(self, C_1, C_2): def forward_head_batch(self, *, e1_idx, rel_idx): """ Given a head entity and a relation (h,r), we compute scores for all entities. - [score(h,r,x)|x \in Entities] => [0.0,0.1,...,0.8], shape=> (1, |Entities|) + [score(h,r,x)|x \\in Entities] => [0.0,0.1,...,0.8], shape=> (1, |Entities|) Given a batch of head entities and relations => shape (size of batch,| Entities|) """ # (1) diff --git a/ontolearn/nces_embeddings/util/data.py b/ontolearn/nces_embeddings/util/data.py index 5ac728bb..f24d97d9 100644 --- a/ontolearn/nces_embeddings/util/data.py +++ b/ontolearn/nces_embeddings/util/data.py @@ -13,7 +13,7 @@ def __init__(self, data_dir=None, train_plus_valid=False, reverse=False, tail_pr Use the union of training and validation split during training phase. ****** out_of_vocab_flag=True - Remove all triples from validation and test that contain at least one entity that did not occurred during training. + Remove all triples from validation and test that contain at least one entity that did not occur during training. """ self.info = {'dataset': data_dir, @@ -34,9 +34,8 @@ def __init__(self, data_dir=None, train_plus_valid=False, reverse=False, tail_pr self.valid_relations = self.get_relations(self.valid_data) self.test_relations = self.get_relations(self.test_data) # The order of entities is important - self.relations = self.train_relations + [i for i in self.valid_relations \ - if i not in self.train_relations] + [i for i in self.test_relations \ - if i not in self.train_relations] + self.relations = self.train_relations + [i for i in self.valid_relations if i not in self.train_relations] + \ + [i for i in self.test_relations if i not in self.train_relations] # Sanity checking on the framework. assert set(self.relations) == set(self.train_relations).union( set(self.valid_relations).union(set(self.test_relations))) @@ -58,7 +57,7 @@ def load_data(data_dir, data_type, add_reciprical=True): try: with open("%s%s.txt" % (data_dir, data_type), "r") as f: data = f.read().strip().split("\n") - data = [i.split("\t") for i in data if len(i.split("\t"))==3] + data = [i.split("\t") for i in data if len(i.split("\t")) == 3] if add_reciprical: data += [[i[2], i[1] + "_reverse", i[0]] for i in data] except FileNotFoundError as e: diff --git a/ontolearn/nces_embeddings/util/ensemble.py b/ontolearn/nces_embeddings/util/ensemble.py index 9997a5cd..10caad0a 100644 --- a/ontolearn/nces_embeddings/util/ensemble.py +++ b/ontolearn/nces_embeddings/util/ensemble.py @@ -1,6 +1,6 @@ -import torch from torch import nn + class Ensemble(nn.Module): """ ensemble through model averaging. """ diff --git a/ontolearn/nces_embeddings/util/experiment.py b/ontolearn/nces_embeddings/util/experiment.py index 28948890..af61ff64 100644 --- a/ontolearn/nces_embeddings/util/experiment.py +++ b/ontolearn/nces_embeddings/util/experiment.py @@ -53,7 +53,7 @@ def __init__(self, *, dataset, model, parameters, ith_logger, store_emb_datafram self.neg_sample_ratio = None self.storage_path = storage_path - #self.logger = create_logger(name=self.model + ith_logger, p=self.storage_path) + # self.logger = create_logger(name=self.model + ith_logger, p=self.storage_path) print('Cuda available:{0}'.format(self.cuda)) if 'norm_flag' not in self.kwargs: @@ -94,7 +94,7 @@ def describe(self): print("Number of triples in testing data:{0}".format(len(self.dataset.test_data))) print("Number of entities:{0}".format(len(self.entity_idxs))) print("Number of relations:{0}".format(len(self.relation_idxs))) - #print("HyperParameter Settings:{0}".format(self.kwargs)) + # print("HyperParameter Settings:{0}".format(self.kwargs)) def evaluate_one_to_n(self, model, data, log_info='Evaluate one to N.'): """ @@ -284,11 +284,12 @@ def train(self, model): s = self.kwargs["scoring_technique"] raise ValueError(f'scoring_technique is not valid ***{s}**') # Save the trained model. - #torch.save(model.state_dict(), self.storage_path + '/model.pt') + # torch.save(model.state_dict(), self.storage_path + '/model.pt') # Save embeddings of entities and relations in csv file. if self.store_emb_dataframe: entity_emb, emb_rel = model.get_embeddings() - # pd.DataFrame(index=self.dataset.entities, data=entity_emb.numpy()).to_csv(TypeError: can't convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first. + # pd.DataFrame(index=self.dataset.entities, data=entity_emb.numpy()).to_csv(TypeError: + # can't convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first. print("Storing embeddings at ", self.storage_path) pd.DataFrame(index=self.dataset.entities, data=entity_emb.cpu().numpy()).to_csv( '{0}/{1}_entity_embeddings.csv'.format(self.storage_path, model.name)) @@ -320,9 +321,9 @@ def train_and_eval(self): else: print(self.model, ' is not valid name') raise ValueError - + self.train(model) - if not 'vicodi' in self.dataset.info['dataset'] and not 'carcinogenesis' in self.dataset.info['dataset']: + if 'vicodi'not in self.dataset.info['dataset'] and 'carcinogenesis' not in self.dataset.info['dataset']: self.eval(model) else: print('\n## No evaluation on large datasets, skipping ##\n') diff --git a/ontolearn/nces_embeddings/util/helper_classes.py b/ontolearn/nces_embeddings/util/helper_classes.py index 99350f93..3987a43f 100644 --- a/ontolearn/nces_embeddings/util/helper_classes.py +++ b/ontolearn/nces_embeddings/util/helper_classes.py @@ -6,7 +6,6 @@ from torch.optim.lr_scheduler import ExponentialLR from collections import defaultdict from torch.utils.data import DataLoader -import pandas as pd import numpy as np import torch @@ -20,6 +19,8 @@ np.random.seed(seed) torch.manual_seed(seed) # noinspection PyTypeChecker + + class DatasetTriple(torch.utils.data.Dataset): def __init__(self, data): data = torch.Tensor(data).long() @@ -58,6 +59,7 @@ def __getitem__(self, idx): y_vec[self.tail_idx[idx]] = 1 # given head and rel, set 1's for all tails. return self.head_idx[idx], self.rel_idx[idx], y_vec + class Reproduce: def __init__(self): self.dataset = None @@ -184,8 +186,10 @@ def reproduce(self, model_path, data_path, model_name, per_rel_flag_=False, tail print('Number of free parameters: ', sum([p.numel() for p in model.parameters()])) # To save if you wish. # entity_emb, emb_rel = model.get_embeddings() - # pd.DataFrame(index=self.dataset.entities, data=entity_emb.numpy()).to_csv('{0}/{1}_entity_embeddings.csv'.format(model_path, model.name)) - # pd.DataFrame(index=self.dataset.relations, data=emb_rel.numpy()).to_csv('{0}/{1}_relation_embeddings.csv'.format(model_path, model.name)) + # pd.DataFrame(index=self.dataset.entities, + # data=entity_emb.numpy()).to_csv('{0}/{1}_entity_embeddings.csv'.format(model_path, model.name)) + # pd.DataFrame(index=self.dataset.relations, + # data=emb_rel.numpy()).to_csv('{0}/{1}_relation_embeddings.csv'.format(model_path, model.name)) self.entity_idxs = {self.dataset.entities[i]: i for i in range(len(self.dataset.entities))} self.relation_idxs = {self.dataset.relations[i]: i for i in range(len(self.dataset.relations))} self.batch_size = self.kwargs['batch_size'] @@ -236,7 +240,8 @@ def reproduce_ensemble(self, model, data_path, per_rel_flag_=False, tail_pred_co out_of_vocab_flag=False): """ per_rel_flag_ reports link prediction results per relations. - flag_of_removal -> removes triples from testing split containing entities that did not occur during training at testing time. + flag_of_removal -> removes triples from testing split containing entities that did not occur during training + at testing time. lp_based_on_head_and_tail_entity_rankings-> computes rank of missing entities based on head and tail entity. """ diff --git a/ontolearn/nces_embeddings/util/real_models.py b/ontolearn/nces_embeddings/util/real_models.py index cf9827ed..98a9e42e 100644 --- a/ontolearn/nces_embeddings/util/real_models.py +++ b/ontolearn/nces_embeddings/util/real_models.py @@ -121,6 +121,7 @@ def forward_triples_and_loss(self, e1_idx, rel_idx, e2_idx, target): def forward_head_and_loss(self, *args, **kwargs): raise NotImplementedError('KvsAll is not implemented for TransE') + class Tucker(torch.nn.Module): def __init__(self, param): super(Tucker, self).__init__() @@ -173,8 +174,8 @@ def forward_head_and_loss(self, e1_idx, rel_idx, targets): def get_embeddings(self): return self.E.weight.data, self.R.weight.data - def forward_triples(self, *args,**kwargs): + def forward_triples(self, *args, **kwargs): raise NotImplementedError('Negative Sampling is not implemented for Tucker') - def forward_triples_and_loss(self, *args,**kwargs): - raise NotImplementedError('Negative Sampling is not implemented for Tucker') \ No newline at end of file + def forward_triples_and_loss(self, *args, **kwargs): + raise NotImplementedError('Negative Sampling is not implemented for Tucker') diff --git a/ontolearn/nces_modules.py b/ontolearn/nces_modules.py index 58c6926f..9598aa03 100644 --- a/ontolearn/nces_modules.py +++ b/ontolearn/nces_modules.py @@ -1,11 +1,14 @@ -## From https://github.com/juho-lee/set_transformer +"""NCES modules.""" +# From https://github.com/juho-lee/set_transformer import torch import torch.nn as nn import torch.nn.functional as F import math + class MAB(nn.Module): + """MAB module.""" def __init__(self, dim_Q, dim_K, dim_V, num_heads, ln=False): super(MAB, self).__init__() self.dim_V = dim_V @@ -27,14 +30,16 @@ def forward(self, Q, K): K_ = torch.cat(K.split(dim_split, 2), 0) V_ = torch.cat(V.split(dim_split, 2), 0) - A = torch.softmax(Q_.bmm(K_.transpose(1,2))/math.sqrt(self.dim_V), 2) + A = torch.softmax(Q_.bmm(K_.transpose(1, 2))/math.sqrt(self.dim_V), 2) O = torch.cat((Q_ + A.bmm(V_)).split(Q.size(0), 0), 2) O = O if getattr(self, 'ln0', None) is None else self.ln0(O) O = O + F.relu(self.fc_o(O)) O = O if getattr(self, 'ln1', None) is None else self.ln1(O) return O + class SAB(nn.Module): + """SAB module.""" def __init__(self, dim_in, dim_out, num_heads, ln=False): super(SAB, self).__init__() self.mab = MAB(dim_in, dim_in, dim_out, num_heads, ln=ln) @@ -42,7 +47,9 @@ def __init__(self, dim_in, dim_out, num_heads, ln=False): def forward(self, X): return self.mab(X, X) + class ISAB(nn.Module): + """ISAB module.""" def __init__(self, dim_in, dim_out, num_heads, num_inds, ln=False): super(ISAB, self).__init__() self.I = nn.Parameter(torch.Tensor(1, num_inds, dim_out)) @@ -54,7 +61,9 @@ def forward(self, X): H = self.mab0(self.I.repeat(X.size(0), 1, 1), X) return self.mab1(X, H) + class PMA(nn.Module): + """PMA module.""" def __init__(self, dim, num_heads, num_seeds, ln=False): super(PMA, self).__init__() self.S = nn.Parameter(torch.Tensor(1, num_seeds, dim)) @@ -62,4 +71,4 @@ def __init__(self, dim, num_heads, num_seeds, ln=False): self.mab = MAB(dim, dim, dim, num_heads, ln=ln) def forward(self, X): - return self.mab(self.S.repeat(X.size(0), 1, 1), X) \ No newline at end of file + return self.mab(self.S.repeat(X.size(0), 1, 1), X) diff --git a/ontolearn/nces_trainer.py b/ontolearn/nces_trainer.py index 8866e4d5..547eca4d 100644 --- a/ontolearn/nces_trainer.py +++ b/ontolearn/nces_trainer.py @@ -1,9 +1,11 @@ -import numpy as np, copy +"""NCES trainer.""" +import numpy as np +import copy import torch from tqdm import trange from collections import defaultdict -from sklearn.utils import resample -import os, json +import os +import json from ontolearn.data_struct import BaseDataLoader from torch.optim.lr_scheduler import ExponentialLR from torch.nn import functional as F @@ -21,10 +23,12 @@ def before_pad(arg): if len(set(arg_temp)) == 3 and ('⊓' in arg_temp or '⊔' in arg_temp): return arg_temp[0] return arg_temp - + + class NCESTrainer: - - def __init__(self, nces, epochs=300, learning_rate=1e-4, decay_rate=0, clip_value=5.0, num_workers=8, storage_path="./"): + """NCES trainer.""" + def __init__(self, nces, epochs=300, learning_rate=1e-4, decay_rate=0, clip_value=5.0, num_workers=8, + storage_path="./"): self.nces = nces self.epochs = epochs self.learning_rate = learning_rate @@ -32,7 +36,7 @@ def __init__(self, nces, epochs=300, learning_rate=1e-4, decay_rate=0, clip_valu self.clip_value = clip_value self.num_workers = num_workers self.storage_path = storage_path - + @staticmethod def compute_accuracy(prediction, target): def soft(arg1, arg2): @@ -59,11 +63,10 @@ def hard(arg1, arg2): arg2_ = before_pad(BaseDataLoader.decompose(arg2_)) else: arg2_ = before_pad(arg2_) - return 100*float(sum(map(lambda x,y: x==y, arg1_, arg2_)))/max(len(arg1_), len(arg2_)) + return 100*float(sum(map(lambda x, y: x == y, arg1_, arg2_)))/max(len(arg1_), len(arg2_)) soft_acc = sum(map(soft, prediction, target))/len(target) hard_acc = sum(map(hard, prediction, target))/len(target) return soft_acc, hard_acc - def get_optimizer(self, synthesizer, optimizer='Adam'): if optimizer == 'Adam': @@ -75,7 +78,7 @@ def get_optimizer(self, synthesizer, optimizer='Adam'): else: raise ValueError print('Unsupported optimizer') - + def show_num_learnable_params(self): print("*"*20+"Trainable model size"+"*"*20) size = sum([p.numel() for p in self.nces.model.parameters()]) @@ -84,7 +87,7 @@ def show_num_learnable_params(self): print("*"*20+"Trainable model size"+"*"*20) print() return size - + def collate_batch(self, batch): pos_emb_list = [] neg_emb_list = [] @@ -97,23 +100,27 @@ def collate_batch(self, batch): pos_emb_list.append(pos_emb) neg_emb_list.append(neg_emb) target_labels.append(label) - pos_emb_list[0] = F.pad(pos_emb_list[0], (0, 0, 0, self.nces.num_examples - pos_emb_list[0].shape[0]), "constant", 0) + pos_emb_list[0] = F.pad(pos_emb_list[0], (0, 0, 0, self.nces.num_examples - pos_emb_list[0].shape[0]), + "constant", 0) pos_emb_list = pad_sequence(pos_emb_list, batch_first=True, padding_value=0) - neg_emb_list[0] = F.pad(neg_emb_list[0], (0, 0, 0, self.nces.num_examples - neg_emb_list[0].shape[0]), "constant", 0) + neg_emb_list[0] = F.pad(neg_emb_list[0], (0, 0, 0, self.nces.num_examples - neg_emb_list[0].shape[0]), + "constant", 0) neg_emb_list = pad_sequence(neg_emb_list, batch_first=True, padding_value=0) target_labels = pad_sequence(target_labels, batch_first=True, padding_value=-100) - return pos_emb_list, neg_emb_list, target_labels - + return pos_emb_list, neg_emb_list, target_labels + def map_to_token(self, idx_array): return self.nces.model.inv_vocab[idx_array] - + def train(self, train_dataloader, save_model=True, optimizer='Adam', record_runtime=True): device = torch.device("cuda" if torch.cuda.is_available() else "cpu") if isinstance(self.nces.model, list): self.nces.model = copy.deepcopy(self.nces.model[0]) model_size = self.show_num_learnable_params() - if device.type == "cpu": print("Training on CPU, it may take long...") - else: print("GPU available !") + if device.type == "cpu": + print("Training on CPU, it may take long...") + else: + print("GPU available !") print() print("#"*50) print() @@ -121,15 +128,21 @@ def train(self, train_dataloader, save_model=True, optimizer='Adam', record_runt print("#"*50, "\n") synthesizer = copy.deepcopy(self.nces.model).train() desc = synthesizer.name - if device.type == "cuda": synthesizer.cuda() + if device.type == "cuda": + synthesizer.cuda() opt = self.get_optimizer(synthesizer=synthesizer, optimizer=optimizer) - if self.decay_rate: self.scheduler = ExponentialLR(opt, self.decay_rate) - Train_loss = []; Train_acc = defaultdict(list); best_score = 0. - if record_runtime: t0 = time.time() + if self.decay_rate: + self.scheduler = ExponentialLR(opt, self.decay_rate) + Train_loss = [] + Train_acc = defaultdict(list) + best_score = 0. + if record_runtime: + t0 = time.time() s_acc, h_acc = 0, 0 Epochs = trange(self.epochs, desc=f'Loss: {np.nan}, Soft Acc: {s_acc}, Hard Acc: {h_acc}', leave=True) for e in Epochs: - soft_acc, hard_acc = [], []; train_losses = [] + soft_acc, hard_acc = [], [] + train_losses = [] for x1, x2, labels in train_dataloader: target_sequence = self.map_to_token(labels) if device.type == "cuda": @@ -137,18 +150,22 @@ def train(self, train_dataloader, save_model=True, optimizer='Adam', record_runt pred_sequence, scores = synthesizer(x1, x2) loss = synthesizer.loss(scores, labels) s_acc, h_acc = self.compute_accuracy(pred_sequence, target_sequence) - soft_acc.append(s_acc); hard_acc.append(h_acc) + soft_acc.append(s_acc) + hard_acc.append(h_acc) train_losses.append(loss.item()) opt.zero_grad() loss.backward() clip_grad_value_(synthesizer.parameters(), clip_value=self.clip_value) opt.step() - if self.decay_rate: self.scheduler.step() + if self.decay_rate: + self.scheduler.step() train_soft_acc, train_hard_acc = np.mean(soft_acc), np.mean(hard_acc) Train_loss.append(np.mean(train_losses)) Train_acc['soft'].append(train_soft_acc) Train_acc['hard'].append(train_hard_acc) - Epochs.set_description('Loss: {:.4f}, Soft Acc: {:.2f}%, Hard Acc: {:.2f}%'.format(Train_loss[-1], train_soft_acc, train_hard_acc)) + Epochs.set_description('Loss: {:.4f}, Soft Acc: {:.2f}%, Hard Acc: {:.2f}%'.format(Train_loss[-1], + train_soft_acc, + train_hard_acc)) Epochs.refresh() weights = copy.deepcopy(synthesizer.state_dict()) if Train_acc['hard'] and Train_acc['hard'][-1] > best_score: @@ -158,15 +175,17 @@ def train(self, train_dataloader, save_model=True, optimizer='Adam', record_runt if record_runtime: duration = time.time()-t0 runtime_info = {"Architecture": synthesizer.name, - "Number of Epochs": self.epochs, "Runtime (s)": duration} + "Number of Epochs": self.epochs, "Runtime (s)": duration} if not os.path.exists(self.storage_path+"/runtime/"): os.mkdir(self.storage_path+"/runtime/") with open(self.storage_path+"/runtime/runtime"+"_"+desc+".json", "w") as file: json.dump(runtime_info, file, indent=3) results_dict = dict() - print("Top performance: loss: {:.4f}, soft accuracy: {:.2f}% ... hard accuracy: {:.2f}%".format(min(Train_loss), max(Train_acc['soft']), max(Train_acc['hard']))) + print("Top performance: loss: {:.4f}, soft accuracy: {:.2f}% ... " + "hard accuracy: {:.2f}%".format(min(Train_loss), max(Train_acc['soft']), max(Train_acc['hard']))) print() - results_dict.update({"Train Max Soft Acc": max(Train_acc['soft']), "Train Max Hard Acc": max(Train_acc['hard']), "Train Min Loss": min(Train_loss)}) + results_dict.update({"Train Max Soft Acc": max(Train_acc['soft']), "Train Max Hard Acc": max(Train_acc['hard']), + "Train Min Loss": min(Train_loss)}) if not os.path.exists(self.storage_path+"/results/"): os.mkdir(self.storage_path+"/results/") with open(self.storage_path+"/results/"+"results"+"_"+desc+".json", "w") as file: @@ -179,5 +198,5 @@ def train(self, train_dataloader, save_model=True, optimizer='Adam', record_runt if not os.path.exists(self.storage_path+"/metrics/"): os.mkdir(self.storage_path+"/metrics/") with open(self.storage_path+"/metrics/"+"metrics_"+desc+".json", "w") as plot_file: - json.dump({"soft acc": Train_acc['soft'], "hard acc": Train_acc['hard'], "loss": Train_loss}, plot_file, indent=3) - + json.dump({"soft acc": Train_acc['soft'], "hard acc": Train_acc['hard'], "loss": Train_loss}, plot_file, + indent=3) diff --git a/ontolearn/nces_utils.py b/ontolearn/nces_utils.py index a797c606..b234b865 100644 --- a/ontolearn/nces_utils.py +++ b/ontolearn/nces_utils.py @@ -1,3 +1,4 @@ +"""NCES utils.""" from tokenizers import Tokenizer from tokenizers.models import BPE from tokenizers.trainers import BpeTrainer @@ -8,8 +9,9 @@ os.environ["TOKENIZERS_PARALLELISM"] = "false" + class SimpleSolution: - + def __init__(self, vocab, atomic_concept_names): self.name = 'SimpleSolution' self.atomic_concept_names = atomic_concept_names @@ -19,7 +21,7 @@ def __init__(self, vocab, atomic_concept_names): tokenizer.train_from_iterator(vocab, trainer) self.tokenizer = PreTrainedTokenizerFast(tokenizer_object=tokenizer) self.tokenizer.pad_token = "[PAD]" - + def predict(self, expression: str): atomic_classes = [atm for atm in self.tokenizer.tokenize(expression) if atm in self.atomic_concept_names] if atomic_classes == []: @@ -27,4 +29,3 @@ def predict(self, expression: str): random.shuffle(self.atomic_concept_names) atomic_classes = self.atomic_concept_names[:3] return " ⊔ ".join(atomic_classes) - \ No newline at end of file diff --git a/ontolearn/owlapy/__init__.py b/ontolearn/owlapy/__init__.py index 8156d78e..5a5fd5aa 100644 --- a/ontolearn/owlapy/__init__.py +++ b/ontolearn/owlapy/__init__.py @@ -1,8 +1,6 @@ -"""OWLAPY +"""OWLAPY - loosely based on OWL API. -loosely based on OWL API - -many help texts copied from OWL API [1] +Many help texts copied from OWL API [1] OWLAPI licence: LGPL and Apache [1] https://github.com/owlcs/owlapi diff --git a/ontolearn/owlapy/_utils.py b/ontolearn/owlapy/_utils.py index ea41fb02..9bbeabf1 100644 --- a/ontolearn/owlapy/_utils.py +++ b/ontolearn/owlapy/_utils.py @@ -1,10 +1,10 @@ def MOVE(*args): - """"Move" an imported class to the current module by setting the classes __module__ attribute + """"Move" an imported class to the current module by setting the classes __module__ attribute. - This is useful for documentation purposes to hide internal packages in sphinx + This is useful for documentation purposes to hide internal packages in sphinx. Args: - args: list of classes to move + args: List of classes to move. """ from inspect import currentframe f = currentframe() diff --git a/ontolearn/owlapy/ext/__init__.py b/ontolearn/owlapy/ext/__init__.py index 48b76335..05c201ef 100644 --- a/ontolearn/owlapy/ext/__init__.py +++ b/ontolearn/owlapy/ext/__init__.py @@ -1,8 +1,10 @@ +"""Extra classes.""" import logging from abc import ABCMeta from typing import Iterable -from ontolearn.owlapy.model import OWLNamedIndividual, OWLObjectProperty, OWLReasoner, OWLDataProperty, OWLDataRange, OWLLiteral +from ontolearn.owlapy.model import OWLNamedIndividual, OWLObjectProperty, OWLReasoner, OWLDataProperty, OWLDataRange, \ + OWLLiteral logger = logging.getLogger(__name__) diff --git a/ontolearn/owlapy/fast_instance_checker.py b/ontolearn/owlapy/fast_instance_checker.py index 06c1b921..3ccfae22 100644 --- a/ontolearn/owlapy/fast_instance_checker.py +++ b/ontolearn/owlapy/fast_instance_checker.py @@ -8,10 +8,10 @@ from typing import DefaultDict, Iterable, Dict, Mapping, Set, Type, TypeVar, Optional, FrozenSet from ontolearn.owlapy.ext import OWLReasonerEx -from ontolearn.owlapy.model import OWLDataRange, OWLObjectOneOf, OWLOntology, OWLNamedIndividual, OWLClass, OWLClassExpression, \ +from ontolearn.owlapy.model import OWLDataRange, OWLObjectOneOf, OWLOntology, OWLNamedIndividual, OWLClass, \ OWLObjectProperty, OWLDataProperty, OWLObjectUnionOf, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom, \ OWLObjectPropertyExpression, OWLObjectComplementOf, OWLObjectAllValuesFrom, IRI, OWLObjectInverseOf, \ - OWLDataSomeValuesFrom, OWLDataPropertyExpression, OWLDatatypeRestriction, OWLLiteral, \ + OWLDataSomeValuesFrom, OWLDataPropertyExpression, OWLDatatypeRestriction, OWLLiteral, OWLClassExpression, \ OWLDataComplementOf, OWLDataAllValuesFrom, OWLDatatype, OWLDataHasValue, OWLDataOneOf, OWLReasoner, \ OWLDataIntersectionOf, OWLDataUnionOf, OWLObjectCardinalityRestriction, OWLObjectMinCardinality, \ OWLObjectMaxCardinality, OWLObjectExactCardinality, OWLObjectHasValue, OWLPropertyExpression, OWLFacetRestriction @@ -23,7 +23,7 @@ class OWLReasoner_FastInstanceChecker(OWLReasonerEx): - """Tries to check instances fast (but maybe incomplete)""" + """Tries to check instances fast (but maybe incomplete).""" __slots__ = '_ontology', '_base_reasoner', \ '_ind_set', '_cls_to_ind', \ '_has_prop', \ diff --git a/ontolearn/owlapy/io.py b/ontolearn/owlapy/io.py index 17f3fe40..5341eba2 100644 --- a/ontolearn/owlapy/io.py +++ b/ontolearn/owlapy/io.py @@ -1,42 +1,43 @@ +"""Abstract renderer and parser classes.""" from abc import abstractmethod, ABCMeta from ontolearn.owlapy.model import OWLObject class OWLObjectRenderer(metaclass=ABCMeta): - """Abstract class with a render method to render an OWL Object into a string""" + """Abstract class with a render method to render an OWL Object into a string.""" @abstractmethod def set_short_form_provider(self, short_form_provider) -> None: - """Configure a short form provider that shortens the OWL objects during rendering + """Configure a short form provider that shortens the OWL objects during rendering. Args: - short_form_provider: short form provider + short_form_provider: Short form provider. """ pass @abstractmethod def render(self, o: OWLObject) -> str: - """Render OWL Object to string + """Render OWL Object to string. Args: - o: OWL Object + o: OWL Object. Returns: - String rendition of OWL object + String rendition of OWL object. """ pass class OWLObjectParser(metaclass=ABCMeta): - """Abstract class with a parse method to parse a string to an OWL Object""" + """Abstract class with a parse method to parse a string to an OWL Object.""" @abstractmethod def parse_expression(self, expression_str: str) -> OWLObject: - """Parse a string to an OWL Object + """Parse a string to an OWL Object. Args: - expression_str: string + expression_str (str): Expression string. Returns: - The OWL Object which is represented by the string + The OWL Object which is represented by the string. """ pass diff --git a/ontolearn/owlapy/model/__init__.py b/ontolearn/owlapy/model/__init__.py index 43274a49..0e1405f8 100644 --- a/ontolearn/owlapy/model/__init__.py +++ b/ontolearn/owlapy/model/__init__.py @@ -1,8 +1,10 @@ -"""The OWL-APy Model class and method names should match those of OWL API [1] +"""The OWL-APy Model classes and methods. + +Their names should match those of OWL API [1]. If OWL API has streaming and getter API, it is enough to provide the streaming API only. -many help texts copied from OWL API +Many help texts copied from OWL API. [1] https://github.com/owlcs/owlapi""" @@ -38,7 +40,7 @@ class HasOperands(Generic[_T], metaclass=ABCMeta): """An interface to objects that have a collection of operands. Args: - _T: operand type + _T: Operand type. """ __slots__ = () @@ -54,15 +56,15 @@ def operands(self) -> Iterable[_T]: class OWLPropertyRange(OWLObject, metaclass=ABCMeta): - """OWL Objects that can be the ranges of properties""" + """OWL Objects that can be the ranges of properties.""" class OWLDataRange(OWLPropertyRange, metaclass=ABCMeta): - """Represents a DataRange in the OWL 2 Specification""" + """Represents a DataRange in the OWL 2 Specification.""" class OWLClassExpression(OWLPropertyRange): - """An OWL 2 Class Expression""" + """An OWL 2 Class Expression.""" __slots__ = () @abstractmethod @@ -71,7 +73,7 @@ def is_owl_thing(self) -> bool: is equivalent to owl:Thing. Returns: - :True if this expression is owl:Thing + True if this expression is owl:Thing. """ pass @@ -84,7 +86,7 @@ def is_owl_nothing(self) -> bool: @abstractmethod def get_object_complement_of(self) -> 'OWLObjectComplementOf': - """Gets the object complement of this class expression + """Gets the object complement of this class expression. Returns: A class expression that is the complement of this class expression. @@ -102,7 +104,7 @@ def get_nnf(self) -> 'OWLClassExpression': class OWLAnonymousClassExpression(OWLClassExpression, metaclass=ABCMeta): - """A Class Expression which is not a named Class""" + """A Class Expression which is not a named Class.""" def is_owl_nothing(self) -> bool: # documented in parent @@ -123,6 +125,7 @@ def get_nnf(self) -> 'OWLClassExpression': class OWLBooleanClassExpression(OWLAnonymousClassExpression, metaclass=ABCMeta): + """Represent an anonymous boolean class expression.""" __slots__ = () pass @@ -137,14 +140,14 @@ class OWLObjectComplementOf(OWLBooleanClassExpression, HasOperands[OWLClassExpre def __init__(self, op: OWLClassExpression): """ Args: - op: class expression to complement + op: Class expression to complement. """ self._operand = op def get_operand(self) -> OWLClassExpression: """ Returns: - the wrapped expression + The wrapped expression. """ return self._operand @@ -250,14 +253,14 @@ class OWLPropertyExpression(OWLObject, metaclass=ABCMeta): def is_data_property_expression(self) -> bool: """ Returns: - True if this is a data property + True if this is a data property. """ return False def is_object_property_expression(self) -> bool: """ Returns: - True if this is an object property + True if this is an object property. """ return False @@ -265,7 +268,7 @@ def is_owl_top_object_property(self) -> bool: """Determines if this is the owl:topObjectProperty. Returns: - :True if this property is the owl:topObjectProperty + True if this property is the owl:topObjectProperty. """ return False @@ -273,41 +276,42 @@ def is_owl_top_data_property(self) -> bool: """Determines if this is the owl:topDataProperty. Returns: - :True if this property is the owl:topDataProperty + True if this property is the owl:topDataProperty. """ return False class OWLRestriction(OWLAnonymousClassExpression): - """Represents a Object Property Restriction or Data Property Restriction in the OWL 2 specification.""" + """Represents an Object Property Restriction or Data Property Restriction in the OWL 2 specification.""" __slots__ = () @abstractmethod def get_property(self) -> OWLPropertyExpression: """ Returns: - property being restricted + Property being restricted. """ pass def is_data_restriction(self) -> bool: - """Determines if this is a data restriction + """Determines if this is a data restriction. Returns: - True if this is a data restriction + True if this is a data restriction. """ return False def is_object_restriction(self) -> bool: - """Determines if this is an object restriction + """Determines if this is an object restriction. Returns: - True if this is an object restriction + True if this is an object restriction. """ return False class OWLObjectPropertyExpression(OWLPropertyExpression): + """A high level interface to describe different types of object properties.""" __slots__ = () @abstractmethod @@ -419,7 +423,7 @@ def __init__(self, property: OWLObjectProperty): """Gets the inverse of an object property. Args: - property: The property of which the inverse will be returned + property: The property of which the inverse will be returned. """ self._inverse_property = property @@ -480,7 +484,7 @@ class HasFiller(Generic[_T], metaclass=ABCMeta): """An interface to objects that have a filler. Args: - _T: filler type + _T: Filler type. """ __slots__ = () @@ -500,7 +504,7 @@ class OWLHasValueRestriction(Generic[_T], OWLRestriction, HasFiller[_T], metacla """OWLHasValueRestriction. Args: - _T: the value type + _T: The value type. """ __slots__ = () @@ -523,7 +527,7 @@ def get_filler(self) -> _T: class OWLQuantifiedRestriction(Generic[_T], OWLRestriction, HasFiller[_T], metaclass=ABCMeta): - """A quantified restriction. + """Represents a quantified restriction. Args: _T: value type @@ -534,7 +538,7 @@ class OWLQuantifiedRestriction(Generic[_T], OWLRestriction, HasFiller[_T], metac class OWLQuantifiedObjectRestriction(OWLQuantifiedRestriction[OWLClassExpression], OWLObjectRestriction, metaclass=ABCMeta): - """A quantified object restriction.""" + """Represents a quantified object restriction.""" __slots__ = () _filler: OWLClassExpression @@ -553,14 +557,14 @@ class OWLObjectSomeValuesFrom(OWLQuantifiedObjectRestriction): type_index: Final = 3005 def __init__(self, property: OWLObjectPropertyExpression, filler: OWLClassExpression): - """Gets an OWLObjectSomeValuesFrom restriction + """Gets an OWLObjectSomeValuesFrom restriction. Args: property: The object property that the restriction acts along. filler: The class expression that is the filler. Returns: - An OWLObjectSomeValuesFrom restriction along the specified property with the specified filler + An OWLObjectSomeValuesFrom restriction along the specified property with the specified filler. """ super().__init__(filler) self._property = property @@ -615,7 +619,7 @@ class OWLNaryBooleanClassExpression(OWLBooleanClassExpression, HasOperands[OWLCl def __init__(self, operands: Iterable[OWLClassExpression]): """ Args: - operands: class expressions + operands: Class expressions. """ self._operands = tuple(operands) @@ -669,10 +673,10 @@ def get_cardinality(self) -> int: class OWLCardinalityRestriction(Generic[_F], OWLQuantifiedRestriction[_F], HasCardinality, metaclass=ABCMeta): - """. + """Base interface for owl min and max cardinality restriction. Args: - _F: type of filler + _F: Type of filler. """ __slots__ = () @@ -693,6 +697,7 @@ def get_filler(self) -> _F: class OWLObjectCardinalityRestriction(OWLCardinalityRestriction[OWLClassExpression], OWLQuantifiedObjectRestriction): + """Represents Object Property Cardinality Restrictions in the OWL 2 specification.""" __slots__ = () _property: OWLObjectPropertyExpression @@ -731,10 +736,10 @@ def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, fill Args: cardinality: Cannot be negative. property: The property that the restriction acts along. - filler: class expression for restriction + filler: Class expression for restriction. Returns: - an ObjectMinCardinality on the specified property + An ObjectMinCardinality on the specified property. """ super().__init__(cardinality, property, filler) @@ -749,10 +754,10 @@ def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, fill Args: cardinality: Cannot be negative. property: The property that the restriction acts along. - filler: class expression for restriction + filler: Class expression for restriction. Returns: - an ObjectMaxCardinality on the specified property + An ObjectMaxCardinality on the specified property. """ super().__init__(cardinality, property, filler) @@ -767,10 +772,10 @@ def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, fill Args: cardinality: Cannot be negative. property: The property that the restriction acts along. - filler: class expression for restriction + filler: Class expression for restriction. Returns: - an ObjectExactCardinality on the specified property + An ObjectExactCardinality on the specified property. """ super().__init__(cardinality, property, filler) @@ -778,7 +783,7 @@ def as_intersection_of_min_max(self) -> OWLObjectIntersectionOf: """Obtains an equivalent form that is a conjunction of a min cardinality and max cardinality restriction. Returns: - The semantically equivalent but structurally simpler form (= 1 R C) = >= 1 R C and <= 1 R C + The semantically equivalent but structurally simpler form (= 1 R C) = >= 1 R C and <= 1 R C. """ args = self.get_cardinality(), self.get_property(), self.get_filler() return OWLObjectIntersectionOf((OWLObjectMinCardinality(*args), OWLObjectMaxCardinality(*args))) @@ -798,7 +803,7 @@ def __init__(self, property: OWLObjectPropertyExpression): property: The property that the restriction acts along. Returns: - a ObjectHasSelf class expression on the specified property + A ObjectHasSelf class expression on the specified property. """ self._property = property @@ -836,10 +841,10 @@ def __init__(self, property: OWLObjectPropertyExpression, individual: OWLIndivid """ Args: property: The property that the restriction acts along. - individual: individual for restriction + individual: Individual for restriction. Returns: - a HasValue restriction with specified property and value + A HasValue restriction with specified property and value """ super().__init__(individual) self._property = property @@ -852,7 +857,7 @@ def as_some_values_from(self) -> OWLClassExpression: """A convenience method that obtains this restriction as an existential restriction with a nominal filler. Returns: - The existential equivalent of this value restriction. simp(HasValue(p a)) = some(p {a}) + The existential equivalent of this value restriction. simp(HasValue(p a)) = some(p {a}). """ return OWLObjectSomeValuesFrom(self.get_property(), OWLObjectOneOf(self.get_filler())) @@ -950,8 +955,8 @@ def __init__(self, ontology_iri: Optional[IRI] = None, version_iri: Optional[IRI """Constructs an ontology identifier specifying the ontology IRI and version IRI. Args: - ontology_iri: The ontology IRI (optional) - version_iri: The version IRI (must be None if no ontology_iri is provided) + ontology_iri: The ontology IRI (optional). + version_iri: The version IRI (must be None if no ontology_iri is provided). """ self._ontology_iri = ontology_iri self._version_iri = version_iri @@ -960,7 +965,7 @@ def get_ontology_iri(self) -> Optional[IRI]: """Gets the ontology IRI. Returns: - Ontology IRI. If the ontology is anonymous, it will return None + Ontology IRI. If the ontology is anonymous, it will return None. """ return self._ontology_iri @@ -968,7 +973,7 @@ def get_version_iri(self) -> Optional[IRI]: """Gets the version IRI. Returns: - Version IRI or None + Version IRI or None. """ return self._version_iri @@ -1002,7 +1007,7 @@ class OWLAxiom(OWLObject, metaclass=ABCMeta): """Represents Axioms in the OWL 2 Specification. An OWL ontology contains a set of axioms. These axioms can be annotation axioms, declaration axioms, imports axioms - or logical axioms + or logical axioms. """ __slots__ = '_annotations' @@ -1127,11 +1132,11 @@ class OWLLiteral(OWLAnnotationValue, metaclass=ABCMeta): type_index: Final = 4008 def __new__(cls, value, type_: Optional[OWLDatatype] = None): - """Convenience method that obtains a literal + """Convenience method that obtains a literal. Args: - value: The value of the literal - type_: the datatype of the literal + value: The value of the literal. + type_: The datatype of the literal. """ if type_ is not None: if type_ == BooleanOWLDatatype: @@ -1176,7 +1181,7 @@ def get_literal(self) -> str: return str(self._v) def is_boolean(self) -> bool: - """Whether this literal is typed as boolean""" + """Whether this literal is typed as boolean.""" return False def parse_boolean(self) -> bool: @@ -1189,7 +1194,7 @@ def parse_boolean(self) -> bool: raise ValueError def is_double(self) -> bool: - """Whether this literal is typed as double""" + """Whether this literal is typed as double.""" return False def parse_double(self) -> float: @@ -1202,7 +1207,7 @@ def parse_double(self) -> float: raise ValueError def is_integer(self) -> bool: - """Whether this literal is typed as integer""" + """Whether this literal is typed as integer.""" return False def parse_integer(self) -> int: @@ -1215,7 +1220,7 @@ def parse_integer(self) -> int: raise ValueError def is_string(self) -> bool: - """Whether this literal is typed as string""" + """Whether this literal is typed as string.""" return False def parse_string(self) -> str: @@ -1228,7 +1233,7 @@ def parse_string(self) -> str: raise ValueError def is_date(self) -> bool: - """Whether this literal is typed as date""" + """Whether this literal is typed as date.""" return False def parse_date(self) -> date: @@ -1241,7 +1246,7 @@ def parse_date(self) -> date: raise ValueError def is_datetime(self) -> bool: - """Whether this literal is typed as dateTime""" + """Whether this literal is typed as dateTime.""" return False def parse_datetime(self) -> datetime: @@ -1254,7 +1259,7 @@ def parse_datetime(self) -> datetime: raise ValueError def is_duration(self) -> bool: - """Whether this literal is typed as duration""" + """Whether this literal is typed as duration.""" return False def parse_duration(self) -> Timedelta: @@ -1602,7 +1607,7 @@ def __repr__(self): class OWLQuantifiedDataRestriction(OWLQuantifiedRestriction[OWLDataRange], OWLDataRestriction, metaclass=ABCMeta): - """A quantified data restriction.""" + """Represents a quantified data restriction.""" __slots__ = () _filler: OWLDataRange @@ -1618,7 +1623,7 @@ def get_filler(self) -> OWLDataRange: class OWLDataCardinalityRestriction(OWLCardinalityRestriction[OWLDataRange], OWLQuantifiedDataRestriction, OWLDataRestriction, metaclass=ABCMeta): - """Represents Data Property Cardinality Restrictions in the OWL 2 specification""" + """Represents Data Property Cardinality Restrictions in the OWL 2 specification.""" __slots__ = () _property: OWLDataPropertyExpression @@ -1656,14 +1661,14 @@ class OWLDataAllValuesFrom(OWLQuantifiedDataRestriction): _property: OWLDataPropertyExpression def __init__(self, property: OWLDataPropertyExpression, filler: OWLDataRange): - """Gets an OWLDataAllValuesFrom restriction + """Gets an OWLDataAllValuesFrom restriction. Args: property: The data property that the restriction acts along. filler: The data range that is the filler. Returns: - An OWLDataAllValuesFrom restriction along the specified property with the specified filler + An OWLDataAllValuesFrom restriction along the specified property with the specified filler. """ super().__init__(filler) self._property = property @@ -1693,14 +1698,14 @@ class OWLDataComplementOf(OWLDataRange): def __init__(self, data_range: OWLDataRange): """ Args: - data_range: data range to complement + data_range: Data range to complement. """ self._data_range = data_range def get_data_range(self) -> OWLDataRange: """ Returns: - the wrapped data range + The wrapped data range. """ return self._data_range @@ -1727,10 +1732,10 @@ def __init__(self, cardinality: int, property: OWLDataPropertyExpression, filler Args: cardinality: Cannot be negative. property: The property that the restriction acts along. - filler: data range for restriction + filler: Data range for restriction Returns: - a DataExactCardinality on the specified property + A DataExactCardinality on the specified property. """ super().__init__(cardinality, property, filler) @@ -1738,7 +1743,7 @@ def as_intersection_of_min_max(self) -> OWLObjectIntersectionOf: """Obtains an equivalent form that is a conjunction of a min cardinality and max cardinality restriction. Returns: - The semantically equivalent but structurally simpler form (= 1 R D) = >= 1 R D and <= 1 R D + The semantically equivalent but structurally simpler form (= 1 R D) = >= 1 R D and <= 1 R D. """ args = self.get_cardinality(), self.get_property(), self.get_filler() return OWLObjectIntersectionOf((OWLDataMinCardinality(*args), OWLDataMaxCardinality(*args))) @@ -1753,14 +1758,14 @@ class OWLDataHasValue(OWLHasValueRestriction[OWLLiteral], OWLDataRestriction): _property: OWLDataPropertyExpression def __init__(self, property: OWLDataPropertyExpression, value: OWLLiteral): - """Gets an OWLDataHasValue restriction + """Gets an OWLDataHasValue restriction. Args: property: The data property that the restriction acts along. - filler: The literal value + filler: The literal value. Returns: - An OWLDataHasValue restriction along the specified property with the specified literal + An OWLDataHasValue restriction along the specified property with the specified literal. """ super().__init__(value) self._property = property @@ -1780,7 +1785,7 @@ def as_some_values_from(self) -> OWLClassExpression: """A convenience method that obtains this restriction as an existential restriction with a nominal filler. Returns: - The existential equivalent of this value restriction. simp(HasValue(p a)) = some(p {a}) + The existential equivalent of this value restriction. simp(HasValue(p a)) = some(p {a}). """ return OWLDataSomeValuesFrom(self.get_property(), OWLDataOneOf(self.get_filler())) @@ -1800,10 +1805,10 @@ def __init__(self, cardinality: int, property: OWLDataPropertyExpression, filler Args: cardinality: Cannot be negative. property: The property that the restriction acts along. - filler: data range for restriction + filler: Data range for restriction. Returns: - a DataMaxCardinality on the specified property + A DataMaxCardinality on the specified property. """ super().__init__(cardinality, property, filler) @@ -1819,10 +1824,10 @@ def __init__(self, cardinality: int, property: OWLDataPropertyExpression, filler Args: cardinality: Cannot be negative. property: The property that the restriction acts along. - filler: data range for restriction + filler: Data range for restriction. Returns: - a DataMinCardinality on the specified property + A DataMinCardinality on the specified property. """ super().__init__(cardinality, property, filler) @@ -1874,14 +1879,14 @@ class OWLDataSomeValuesFrom(OWLQuantifiedDataRestriction): _property: OWLDataPropertyExpression def __init__(self, property: OWLDataPropertyExpression, filler: OWLDataRange): - """Gets an OWLDataSomeValuesFrom restriction + """Gets an OWLDataSomeValuesFrom restriction. Args: property: The data property that the restriction acts along. filler: The data range that is the filler. Returns: - An OWLDataSomeValuesFrom restriction along the specified property with the specified filler + An OWLDataSomeValuesFrom restriction along the specified property with the specified filler. """ super().__init__(filler) self._property = property @@ -1911,7 +1916,7 @@ class OWLNaryDataRange(OWLDataRange, HasOperands[OWLDataRange]): def __init__(self, operands: Iterable[OWLDataRange]): """ Args: - operands: data ranges + operands: Data ranges. """ self._operands = tuple(operands) @@ -1954,10 +1959,10 @@ class OWLImportsDeclaration(HasIRI): def __init__(self, import_iri: IRI): """ Args: - import_import_iri: imported ontology + import_import_iri: Imported ontology. Returns: - an imports declaration + An imports declaration. """ self._iri = import_iri @@ -1966,7 +1971,7 @@ def get_iri(self) -> IRI: Returns: The import IRI that points to the ontology to be imported. The imported ontology might have this IRI as - its ontology IRI but this is not mandated. For example, an ontology with a non resolvable ontology IRI + its ontology IRI but this is not mandated. For example, an ontology with a non-resolvable ontology IRI can be deployed at a resolvable URL. """ return self._iri @@ -2020,8 +2025,8 @@ def __init__(self, annotations: Optional[Iterable['OWLAnnotation']] = None): class OWLDeclarationAxiom(OWLAxiom): - '''Represents a Declaration axiom in the OWL 2 Specification. A declaration axiom declares an entity in an ontology. - It doesn't affect the logical meaning of the ontology.''' + """Represents a Declaration axiom in the OWL 2 Specification. A declaration axiom declares an entity in an ontology. + It doesn't affect the logical meaning of the ontology.""" __slots__ = '_entity' _entity: OWLEntity @@ -2046,7 +2051,7 @@ def __repr__(self): class OWLDatatypeDefinitionAxiom(OWLLogicalAxiom): - '''Represents a DatatypeDefinition axiom in the OWL 2 Specification.''' + """Represents a DatatypeDefinition axiom in the OWL 2 Specification.""" __slots__ = '_datatype', '_datarange' _datatype: OWLDatatype @@ -2079,7 +2084,7 @@ def __repr__(self): class OWLHasKeyAxiom(OWLLogicalAxiom, HasOperands[OWLPropertyExpression]): - '''Represents a HasKey axiom in the OWL 2 Specification.''' + """Represents a HasKey axiom in the OWL 2 Specification.""" __slots__ = '_class_expression', '_property_expressions' _class_expression: OWLClassExpression @@ -2120,7 +2125,7 @@ class OWLNaryAxiom(Generic[_C], OWLAxiom, metaclass=ABCMeta): axioms. Args: - _C: class of contained objects + _C: Class of contained objects. """ __slots__ = () @@ -2132,8 +2137,9 @@ def as_pairwise_axioms(self) -> Iterable['OWLNaryAxiom[_C]']: # noinspection PyUnresolvedReferences # noinspection PyDunderSlots class OWLNaryClassAxiom(OWLClassAxiom, OWLNaryAxiom[OWLClassExpression], metaclass=ABCMeta): + """Represents an axiom that contains two or more operands that could also be represented with + multiple pairwise axioms.""" __slots__ = '_class_expressions' - _class_expressions: List[OWLClassExpression] @abstractmethod @@ -2151,6 +2157,12 @@ def class_expressions(self) -> Iterable[OWLClassExpression]: yield from self._class_expressions def as_pairwise_axioms(self) -> Iterable['OWLNaryClassAxiom']: + """Gets this axiom as a set of pairwise axioms; if the axiom contains only two operands, + the axiom itself is returned unchanged, including its annotations. + + Returns: + This axiom as a set of pairwise axioms. + """ if len(self._class_expressions) < 3: yield self else: @@ -2199,6 +2211,8 @@ def __init__(self, class_expressions: List[OWLClassExpression], class OWLNaryIndividualAxiom(OWLIndividualAxiom, OWLNaryAxiom[OWLIndividual], metaclass=ABCMeta): + """Represents an axiom that contains two or more operands that could also be represented with + multiple pairwise individual axioms.""" __slots__ = '_individuals' _individuals: List[OWLIndividual] @@ -2210,6 +2224,11 @@ def __init__(self, individuals: List[OWLIndividual], super().__init__(annotations=annotations) def individuals(self) -> Iterable[OWLIndividual]: + """Get the individuals. + + Returns: + Generator containing the individuals. + """ yield from self._individuals def as_pairwise_axioms(self) -> Iterable['OWLNaryIndividualAxiom']: @@ -2249,6 +2268,8 @@ def __init__(self, individuals: List[OWLIndividual], class OWLNaryPropertyAxiom(Generic[_P], OWLPropertyAxiom, OWLNaryAxiom[_P], metaclass=ABCMeta): + """Represents an axiom that contains two or more operands that could also be represented with + multiple pairwise property axioms.""" __slots__ = '_properties' _properties: List[_P] @@ -2259,6 +2280,11 @@ def __init__(self, properties: List[_P], annotations: Optional[Iterable['OWLAnno super().__init__(annotations=annotations) def properties(self) -> Iterable[_P]: + """Get all the properties that appear in the axiom. + + Returns: + Generator containing the properties. + """ yield from self._properties def as_pairwise_axioms(self) -> Iterable['OWLNaryPropertyAxiom']: @@ -2348,12 +2374,12 @@ class OWLSubClassOfAxiom(OWLClassAxiom): def __init__(self, sub_class: OWLClassExpression, super_class: OWLClassExpression, annotations: Optional[Iterable['OWLAnnotation']] = None): - """Get an equivalent classes axiom with specified operands and no annotations + """Get an equivalent classes axiom with specified operands and no annotations. Args: - sub_class: the sub class - super_class: the super class - annotations: annotations + sub_class: The sub-class. + super_class: The super class. + annotations: Annotations. """ self._sub_class = sub_class self._super_class = super_class @@ -2380,7 +2406,7 @@ def __repr__(self): class OWLDisjointUnionAxiom(OWLClassAxiom): - '''Represents a DisjointUnion axiom in the OWL 2 Specification.''' + """Represents a DisjointUnion axiom in the OWL 2 Specification.""" __slots__ = '_cls', '_class_expressions' _cls: OWLClass @@ -2419,7 +2445,7 @@ def __repr__(self): class OWLClassAssertionAxiom(OWLIndividualAxiom): - '''Represents ClassAssertion axioms in the OWL 2 Specification.''' + """Represents ClassAssertion axioms in the OWL 2 Specification.""" __slots__ = '_individual', '_class_expression' _individual: OWLIndividual @@ -2427,11 +2453,11 @@ class OWLClassAssertionAxiom(OWLIndividualAxiom): def __init__(self, individual: OWLIndividual, class_expression: OWLClassExpression, annotations: Optional[Iterable['OWLAnnotation']] = None): - """Get a ClassAssertion axiom for the specified individual and class expression + """Get a ClassAssertion axiom for the specified individual and class expression. Args: - individual: the individual - class_expression: the class the individual belongs to - annotations: annotations + individual: The individual. + class_expression: The class the individual belongs to. + annotations: Annotations. """ self._individual = individual self._class_expression = class_expression @@ -2472,10 +2498,10 @@ class OWLAnnotationProperty(OWLProperty): _iri: IRI def __init__(self, iri: IRI): - """Get a new OWLAnnotationProperty object + """Get a new OWLAnnotationProperty object. Args: - iri: new OWLAnnotationProperty IRI + iri: New OWLAnnotationProperty IRI. """ self._iri = iri @@ -2493,7 +2519,7 @@ class OWLAnnotation(OWLObject): _value: OWLAnnotationValue def __init__(self, property: OWLAnnotationProperty, value: OWLAnnotationValue): - """Gets an annotation + """Gets an annotation. Args: property: the annotation property. @@ -2506,7 +2532,7 @@ def get_property(self) -> OWLAnnotationProperty: """Gets the property that this annotation acts along. Returns: - The annotation property + The annotation property. """ return self._property @@ -2539,11 +2565,11 @@ class OWLAnnotationAssertionAxiom(OWLAnnotationAxiom): _annotation: OWLAnnotation def __init__(self, subject: OWLAnnotationSubject, annotation: OWLAnnotation): - """Get an annotation assertion axiom - with annotations + """Get an annotation assertion axiom - with annotations. Args: - subject: subject - annotation: annotation + subject: Subject. + annotation: Annotation. """ assert isinstance(subject, OWLAnnotationSubject) assert isinstance(annotation, OWLAnnotation) @@ -2555,7 +2581,7 @@ def get_subject(self) -> OWLAnnotationSubject: """Gets the subject of this object. Returns: - The subject + The subject. """ return self._subject @@ -2588,7 +2614,7 @@ def __repr__(self): class OWLSubAnnotationPropertyOfAxiom(OWLAnnotationAxiom): - '''Represents an SubAnnotationPropertyOf axiom in the OWL 2 specification''' + """Represents an SubAnnotationPropertyOf axiom in the OWL 2 specification.""" __slots__ = '_sub_property', '_super_property' _sub_property: OWLAnnotationProperty @@ -2621,7 +2647,7 @@ def __repr__(self): class OWLAnnotationPropertyDomainAxiom(OWLAnnotationAxiom): - '''Represents an AnnotationPropertyDomain axiom in the OWL 2 specification''' + """Represents an AnnotationPropertyDomain axiom in the OWL 2 specification.""" __slots__ = '_property', '_domain' _property: OWLAnnotationProperty @@ -2654,7 +2680,7 @@ def __repr__(self): class OWLAnnotationPropertyRangeAxiom(OWLAnnotationAxiom): - '''Represents an AnnotationPropertyRange axiom in the OWL 2 specification''' + """Represents an AnnotationPropertyRange axiom in the OWL 2 specification.""" __slots__ = '_property', '_range' _property: OWLAnnotationProperty @@ -2687,6 +2713,9 @@ def __repr__(self): class OWLSubPropertyAxiom(Generic[_P], OWLPropertyAxiom): + """ + Base interface for object and data sub-property axioms. + """ __slots__ = '_sub_property', '_super_property' _sub_property: _P @@ -2720,7 +2749,7 @@ def __repr__(self): class OWLSubObjectPropertyOfAxiom(OWLSubPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom): - '''Represents a SubObjectPropertyOf axiom in the OWL 2 specification''' + """Represents a SubObjectPropertyOf axiom in the OWL 2 specification.""" __slots__ = () def __init__(self, sub_property: OWLObjectPropertyExpression, super_property: OWLObjectPropertyExpression, @@ -2729,7 +2758,7 @@ def __init__(self, sub_property: OWLObjectPropertyExpression, super_property: OW class OWLSubDataPropertyOfAxiom(OWLSubPropertyAxiom[OWLDataPropertyExpression], OWLDataPropertyAxiom): - '''Represents a SubDataPropertyOf axiom in the OWL 2 specification''' + """Represents a SubDataPropertyOf axiom in the OWL 2 specification.""" __slots__ = () def __init__(self, sub_property: OWLDataPropertyExpression, super_property: OWLDataPropertyExpression, @@ -2738,7 +2767,7 @@ def __init__(self, sub_property: OWLDataPropertyExpression, super_property: OWLD class OWLPropertyAssertionAxiom(Generic[_P, _C], OWLIndividualAxiom, metaclass=ABCMeta): - '''Represents a PropertyAssertion axiom in the OWL 2 specification''' + """Represents a PropertyAssertion axiom in the OWL 2 specification.""" __slots__ = '_subject', '_property', '_object' _subject: OWLIndividual @@ -2748,12 +2777,12 @@ class OWLPropertyAssertionAxiom(Generic[_P, _C], OWLIndividualAxiom, metaclass=A @abstractmethod def __init__(self, subject: OWLIndividual, property_: _P, object_: _C, annotations: Optional[Iterable['OWLAnnotation']] = None): - """Get a PropertyAssertion axiom for the specified subject, property, object + """Get a PropertyAssertion axiom for the specified subject, property, object. Args: - subject: the subject of the property assertion - property: the property of the property assertion - object: the object of the property assertion - annotations: annotations + subject: The subject of the property assertion. + property_: The property of the property assertion. + object_: The object of the property assertion. + annotations: Annotations. """ assert isinstance(subject, OWLIndividual) @@ -2786,7 +2815,7 @@ def __repr__(self): class OWLObjectPropertyAssertionAxiom(OWLPropertyAssertionAxiom[OWLObjectPropertyExpression, OWLIndividual]): - '''Represents an ObjectPropertyAssertion axiom in the OWL 2 specification''' + """Represents an ObjectPropertyAssertion axiom in the OWL 2 specification.""" __slots__ = () def __init__(self, subject: OWLIndividual, property_: OWLObjectPropertyExpression, object_: OWLIndividual, @@ -2795,7 +2824,7 @@ def __init__(self, subject: OWLIndividual, property_: OWLObjectPropertyExpressio class OWLNegativeObjectPropertyAssertionAxiom(OWLPropertyAssertionAxiom[OWLObjectPropertyExpression, OWLIndividual]): - '''Represents a NegativeObjectPropertyAssertion axiom in the OWL 2 specification''' + """Represents a NegativeObjectPropertyAssertion axiom in the OWL 2 specification.""" __slots__ = () def __init__(self, subject: OWLIndividual, property_: OWLObjectPropertyExpression, object_: OWLIndividual, @@ -2804,7 +2833,7 @@ def __init__(self, subject: OWLIndividual, property_: OWLObjectPropertyExpressio class OWLDataPropertyAssertionAxiom(OWLPropertyAssertionAxiom[OWLDataPropertyExpression, OWLLiteral]): - '''Represents an DataPropertyAssertion axiom in the OWL 2 specification''' + """Represents an DataPropertyAssertion axiom in the OWL 2 specification.""" __slots__ = () def __init__(self, subject: OWLIndividual, property_: OWLDataPropertyExpression, object_: OWLLiteral, @@ -2813,7 +2842,7 @@ def __init__(self, subject: OWLIndividual, property_: OWLDataPropertyExpression, class OWLNegativeDataPropertyAssertionAxiom(OWLPropertyAssertionAxiom[OWLDataPropertyExpression, OWLLiteral]): - '''Represents an NegativeDataPropertyAssertion axiom in the OWL 2 specification''' + """Represents an NegativeDataPropertyAssertion axiom in the OWL 2 specification.""" __slots__ = () def __init__(self, subject: OWLIndividual, property_: OWLDataPropertyExpression, object_: OWLLiteral, @@ -2822,6 +2851,7 @@ def __init__(self, subject: OWLIndividual, property_: OWLDataPropertyExpression, class OWLUnaryPropertyAxiom(Generic[_P], OWLPropertyAxiom, metaclass=ABCMeta): + """Unary property axiom.""" __slots__ = '_property' _property: _P @@ -2836,6 +2866,7 @@ def get_property(self) -> _P: class OWLObjectPropertyCharacteristicAxiom(OWLUnaryPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom, metaclass=ABCMeta): + """Base interface for functional object property axiom.""" __slots__ = () @abstractmethod @@ -2855,7 +2886,7 @@ def __repr__(self): class OWLFunctionalObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - '''Represents FunctionalObjectProperty axioms in the OWL 2 specification.''' + """Represents FunctionalObjectProperty axioms in the OWL 2 specification.""" __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -2863,7 +2894,7 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLAsymmetricObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - '''Represents AsymmetricObjectProperty axioms in the OWL 2 specification.''' + """Represents AsymmetricObjectProperty axioms in the OWL 2 specification.""" __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -2871,7 +2902,7 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLInverseFunctionalObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - '''Represents InverseFunctionalObjectProperty axioms in the OWL 2 specification.''' + """Represents InverseFunctionalObjectProperty axioms in the OWL 2 specification.""" __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -2879,7 +2910,7 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLIrreflexiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - '''Represents IrreflexiveObjectProperty axioms in the OWL 2 specification.''' + """Represents IrreflexiveObjectProperty axioms in the OWL 2 specification.""" __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -2887,7 +2918,7 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLReflexiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - '''Represents ReflexiveObjectProperty axioms in the OWL 2 specification.''' + """Represents ReflexiveObjectProperty axioms in the OWL 2 specification.""" __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -2895,7 +2926,7 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLSymmetricObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - '''Represents SymmetricObjectProperty axioms in the OWL 2 specification.''' + """Represents SymmetricObjectProperty axioms in the OWL 2 specification.""" __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -2903,7 +2934,7 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLTransitiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - '''Represents TransitiveObjectProperty axioms in the OWL 2 specification.''' + """Represents TransitiveObjectProperty axioms in the OWL 2 specification.""" __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -2912,6 +2943,7 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLDataPropertyCharacteristicAxiom(OWLUnaryPropertyAxiom[OWLDataPropertyExpression], OWLDataPropertyAxiom, metaclass=ABCMeta): + """Base interface for Functional data property axiom.""" __slots__ = () @abstractmethod @@ -2931,7 +2963,7 @@ def __repr__(self): class OWLFunctionalDataPropertyAxiom(OWLDataPropertyCharacteristicAxiom): - '''Represents FunctionalDataProperty axioms in the OWL 2 specification.''' + """Represents FunctionalDataProperty axioms in the OWL 2 specification.""" __slots__ = () def __init__(self, property_: OWLDataPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -3035,7 +3067,7 @@ class OWLOntology(OWLObject, metaclass=ABCMeta): An OWLOntology consists of a possibly empty set of OWLAxioms and a possibly empty set of OWLAnnotations. An ontology can have an ontology IRI which can be used to identify the ontology. If it has an ontology IRI then it may also have an ontology version IRI. Since OWL 2, an ontology need not have an ontology IRI. (See the OWL 2 - Structural Specification) + Structural Specification). An ontology cannot be modified directly. Changes must be applied via its OWLOntologyManager. """ @@ -3047,7 +3079,7 @@ def classes_in_signature(self) -> Iterable[OWLClass]: """Gets the classes in the signature of this object. Returns: - Classes in the signature of this object + Classes in the signature of this object. """ pass @@ -3056,7 +3088,7 @@ def data_properties_in_signature(self) -> Iterable[OWLDataProperty]: """Get the data properties that are in the signature of this object. Returns: - Data properties that are in the signature of this object + Data properties that are in the signature of this object. """ pass @@ -3065,7 +3097,7 @@ def object_properties_in_signature(self) -> Iterable[OWLObjectProperty]: """A convenience method that obtains the object properties that are in the signature of this object. Returns: - Object properties that are in the signature of this object + Object properties that are in the signature of this object. """ pass @@ -3108,7 +3140,7 @@ def data_property_domain_axioms(self, property: OWLDataProperty) -> Iterable[OWL property: The property which is equal to the property of the retrieved axioms. Returns: - the axioms matching the search. + The axioms matching the search. """ pass @@ -3120,7 +3152,7 @@ def data_property_range_axioms(self, property: OWLDataProperty) -> Iterable[OWLD property: The property which is equal to the property of the retrieved axioms. Returns: - the axioms matching the search. + The axioms matching the search. """ pass @@ -3132,7 +3164,7 @@ def object_property_domain_axioms(self, property: OWLObjectProperty) -> Iterable property: The property which is equal to the property of the retrieved axioms. Returns: - the axioms matching the search. + The axioms matching the search. """ pass @@ -3144,13 +3176,13 @@ def object_property_range_axioms(self, property: OWLObjectProperty) -> Iterable[ property: The property which is equal to the property of the retrieved axioms. Returns: - the axioms matching the search. + The axioms matching the search. """ pass @abstractmethod def get_owl_ontology_manager(self) -> _M: - """Gets the manager that manages this ontology""" + """Gets the manager that manages this ontology.""" pass @abstractmethod @@ -3158,17 +3190,19 @@ def get_ontology_id(self) -> OWLOntologyID: """Gets the OWLOntologyID belonging to this object. Returns: - The OWLOntologyID + The OWLOntologyID. """ pass def is_anonymous(self) -> bool: + """Check whether this ontology does contain an IRI or not.""" return self.get_ontology_id().is_anonymous() # noinspection PyUnresolvedReferences # noinspection PyDunderSlots class OWLOntologyChange(metaclass=ABCMeta): + """Represents an ontology change.""" __slots__ = () _ont: OWLOntology @@ -3181,7 +3215,7 @@ def get_ontology(self) -> OWLOntology: """Gets the ontology that the change is/was applied to. Returns: - The ontology that the change is applicable to + The ontology that the change is applicable to. """ return self._ont @@ -3193,8 +3227,8 @@ class AddImport(OWLOntologyChange): def __init__(self, ontology: OWLOntology, import_declaration: OWLImportsDeclaration): """ Args: - ontology: the ontology to which the change is to be applied - import_declaration: the import declaration + ontology: The ontology to which the change is to be applied. + import_declaration: The import declaration. """ super().__init__(ontology) self._declaration = import_declaration @@ -3203,7 +3237,7 @@ def get_import_declaration(self) -> OWLImportsDeclaration: """Gets the import declaration that the change pertains to. Returns: - The import declaration + The import declaration. """ return self._declaration @@ -3232,7 +3266,7 @@ def load_ontology(self, iri: IRI) -> OWLOntology: Args: iri: The IRI that identifies the ontology. It is expected that the ontology will also have this IRI - (although the OWL API should tolerated situations where this is not the case). + (although the OWL API should tolerate situations where this is not the case). Returns: The OWLOntology representation of the ontology that was loaded. @@ -3246,7 +3280,7 @@ def apply_change(self, change: OWLOntologyChange): get_owl_ontology_manager() call. Args: - change: The change to be applied + change: The change to be applied. Raises: ChangeApplied.UNSUCCESSFULLY: if the change was not applied successfully. @@ -3259,7 +3293,7 @@ def add_axiom(self, ontology: OWLOntology, axiom: OWLAxiom): Args: ontology: The ontology to add the axiom to. - axiom: The axiom to be added + axiom: The axiom to be added. """ pass @@ -3269,7 +3303,7 @@ def remove_axiom(self, ontology: OWLOntology, axiom: OWLAxiom): Args: ontology: The ontology to remove the axiom from. - axiom: The axiom to be removed + axiom: The axiom to be removed. """ pass @@ -3280,7 +3314,7 @@ def save_ontology(self, ontology: OWLOntology, document_iri: IRI): Args: ontology: The ontology to be saved. - document_iri: The document IRI where the ontology should be saved to + document_iri: The document IRI where the ontology should be saved to. """ pass @@ -3444,8 +3478,8 @@ def data_property_values(self, ind: OWLNamedIndividual, pe: OWLDataProperty, dir """Gets the data property values for the specified individual and data property expression. Args: - ind: The individual that is the subject of the data property values - pe: The data property expression whose values are to be retrieved for the specified individual + ind: The individual that is the subject of the data property values. + pe: The data property expression whose values are to be retrieved for the specified individual. direct: Specifies if the direct values should be retrieved (True), or if all values should be retrieved (False), so that sub properties are taken into account. @@ -3461,8 +3495,8 @@ def object_property_values(self, ind: OWLNamedIndividual, pe: OWLObjectPropertyE """Gets the object property values for the specified individual and object property expression. Args: - ind: The individual that is the subject of the object property values - pe: The object property expression whose values are to be retrieved for the specified individual + ind: The individual that is the subject of the object property values. + pe: The object property expression whose values are to be retrieved for the specified individual. direct: Specifies if the direct values should be retrieved (True), or if all values should be retrieved (False), so that sub properties are taken into account. @@ -3475,7 +3509,7 @@ def object_property_values(self, ind: OWLNamedIndividual, pe: OWLObjectPropertyE @abstractmethod def flush(self) -> None: """Flushes any changes stored in the buffer, which causes the reasoner to take into consideration the changes - the current root ontology specified by the changes""" + the current root ontology specified by the changes.""" pass @abstractmethod @@ -3505,7 +3539,7 @@ def sub_classes(self, ce: OWLClassExpression, direct: bool = False, only_named: ce: The class expression whose strict (direct) subclasses are to be retrieved. direct: Specifies if the direct subclasses should be retrieved (True) or if the all subclasses (descendant) classes should be retrieved (False). - only_named: Whether to only retrieve named sub classes or also complex class expressions. + only_named: Whether to only retrieve named sub-classes or also complex class expressions. Returns: If direct is True, each class C where reasoner axioms entails DirectSubClassOf(C, ce). If direct is False, @@ -3602,7 +3636,7 @@ def types(self, ind: OWLNamedIndividual, direct: bool = False) -> Iterable[OWLCl @abstractmethod def get_root_ontology(self) -> OWLOntology: """Gets the "root" ontology that is loaded into this reasoner. The reasoner takes into account the axioms in - this ontology and its imports closure.""" + this ontology and its import's closure.""" pass @abstractmethod diff --git a/ontolearn/owlapy/model/_iri.py b/ontolearn/owlapy/model/_iri.py index fcaf084f..d09aeb1c 100644 --- a/ontolearn/owlapy/model/_iri.py +++ b/ontolearn/owlapy/model/_iri.py @@ -9,6 +9,7 @@ class HasIRI(metaclass=ABCMeta): + """Simple class to access the IRI.""" __slots__ = () @abstractmethod @@ -16,7 +17,7 @@ def get_iri(self) -> 'IRI': """Gets the IRI of this object. Returns: - The IRI of this object + The IRI of this object. """ pass @@ -44,7 +45,7 @@ class _meta_IRI(ABCMeta, _WeakCached): class IRI(OWLAnnotationSubject, OWLAnnotationValue, metaclass=_meta_IRI): - """An IRI, consisting of a namespace and a remainder""" + """An IRI, consisting of a namespace and a remainder.""" __slots__ = '_namespace', '_remainder', '__weakref__' type_index: Final = 0 @@ -72,8 +73,8 @@ def create(namespace: str, remainder: str) -> 'IRI': namespace + remainder. Args: - namespace: The first string - remainder: The second string + namespace: The first string. + remainder: The second string. Returns: An IRI whose characters consist of prefix + suffix. @@ -86,7 +87,7 @@ def create(string: str) -> 'IRI': """Creates an IRI from the specified String. Args: - string: The String that specifies the IRI + string: The String that specifies the IRI. Returns: The IRI that has the specified string representation. @@ -115,7 +116,7 @@ def is_nothing(self): """Determines if this IRI is equal to the IRI that owl:Nothing is named with. Returns: - :True if this IRI is equal to and otherwise False + :True if this IRI is equal to and otherwise False. """ from ontolearn.owlapy.vocab import OWLRDFVocabulary return self == OWLRDFVocabulary.OWL_NOTHING.get_iri() @@ -124,7 +125,7 @@ def is_thing(self): """Determines if this IRI is equal to the IRI that owl:Thing is named with. Returns: - :True if this IRI is equal to and otherwise False + :True if this IRI is equal to and otherwise False. """ from ontolearn.owlapy.vocab import OWLRDFVocabulary return self == OWLRDFVocabulary.OWL_THING.get_iri() @@ -132,7 +133,7 @@ def is_thing(self): def is_reserved_vocabulary(self) -> bool: """Determines if this IRI is in the reserved vocabulary. An IRI is in the reserved vocabulary if it starts with or or - or + or . Returns: True if the IRI is in the reserved vocabulary, otherwise False. @@ -147,7 +148,7 @@ def as_iri(self) -> 'IRI': def as_str(self) -> str: """ Returns: - the string that specifies the IRI + The string that specifies the IRI. """ return self._namespace + self._remainder @@ -162,13 +163,13 @@ def get_short_form(self) -> str: def get_namespace(self) -> str: """ Returns: - the namespace as string + The namespace as string. """ return self._namespace def get_remainder(self) -> str: """ Returns: - the remainder (coincident with NCName usually) for this IRI. + The remainder (coincident with NCName usually) for this IRI. """ return self._remainder diff --git a/ontolearn/owlapy/model/providers.py b/ontolearn/owlapy/model/providers.py index 59cf64ba..5f4ccdaa 100644 --- a/ontolearn/owlapy/model/providers.py +++ b/ontolearn/owlapy/model/providers.py @@ -1,3 +1,4 @@ +"""OWL Datatype restriction constructors.""" from typing import Union from datetime import datetime, date from ontolearn.owlapy.model import OWLDatatypeRestriction, OWLFacet, OWLFacetRestriction, OWLLiteral @@ -7,27 +8,32 @@ def OWLDatatypeMaxExclusiveRestriction(max_: Restriction_Literals) -> OWLDatatypeRestriction: + """Create a max exclusive restriction.""" r = OWLFacetRestriction(OWLFacet.MAX_EXCLUSIVE, max_) return OWLDatatypeRestriction(r.get_facet_value().get_datatype(), r) def OWLDatatypeMinExclusiveRestriction(min_: Restriction_Literals) -> OWLDatatypeRestriction: + """Create a min exclusive restriction.""" r = OWLFacetRestriction(OWLFacet.MIN_EXCLUSIVE, min_) return OWLDatatypeRestriction(r.get_facet_value().get_datatype(), r) def OWLDatatypeMaxInclusiveRestriction(max_: Restriction_Literals) -> OWLDatatypeRestriction: + """Create a max inclusive restriction.""" r = OWLFacetRestriction(OWLFacet.MAX_INCLUSIVE, max_) return OWLDatatypeRestriction(r.get_facet_value().get_datatype(), r) def OWLDatatypeMinInclusiveRestriction(min_: Restriction_Literals) -> OWLDatatypeRestriction: + """Create a min inclusive restriction.""" r = OWLFacetRestriction(OWLFacet.MIN_INCLUSIVE, min_) return OWLDatatypeRestriction(r.get_facet_value().get_datatype(), r) def OWLDatatypeMinMaxExclusiveRestriction(min_: Restriction_Literals, max_: Restriction_Literals) -> OWLDatatypeRestriction: + """Create a min-max exclusive restriction.""" if isinstance(min_, float) and isinstance(max_, int): max_ = float(max_) if isinstance(max_, float) and isinstance(min_, int): @@ -42,6 +48,7 @@ def OWLDatatypeMinMaxExclusiveRestriction(min_: Restriction_Literals, def OWLDatatypeMinMaxInclusiveRestriction(min_: Restriction_Literals, max_: Restriction_Literals) -> OWLDatatypeRestriction: + """Create a min-max inclusive restriction.""" if isinstance(min_, float) and isinstance(max_, int): max_ = float(max_) if isinstance(max_, float) and isinstance(min_, int): diff --git a/ontolearn/owlapy/namespaces.py b/ontolearn/owlapy/namespaces.py index 80162332..23217fa1 100644 --- a/ontolearn/owlapy/namespaces.py +++ b/ontolearn/owlapy/namespaces.py @@ -1,19 +1,20 @@ +"""Namespaces.""" from typing import Final class Namespaces: - """A Namespace and its prefix""" + """A Namespace and its prefix.""" __slots__ = '_prefix', '_ns' _prefix: str _ns: str def __init__(self, prefix: str, ns: str): - """Create a new namespace + """Create a new namespace. Args: - prefix: typical prefix associated with this namespace - ns: namespace IRI as string + prefix: Typical prefix associated with this namespace. + ns: Namespace IRI as string. """ assert ns[-1] in ("/", ":", "#") self._prefix = prefix diff --git a/ontolearn/owlapy/owl2sparql/__init__.py b/ontolearn/owlapy/owl2sparql/__init__.py index e69de29b..509cdf1e 100644 --- a/ontolearn/owlapy/owl2sparql/__init__.py +++ b/ontolearn/owlapy/owl2sparql/__init__.py @@ -0,0 +1 @@ +"""OWL-to-SPARQL converter.""" diff --git a/ontolearn/owlapy/owl2sparql/converter.py b/ontolearn/owlapy/owl2sparql/converter.py index 917a9992..f78e1102 100644 --- a/ontolearn/owlapy/owl2sparql/converter.py +++ b/ontolearn/owlapy/owl2sparql/converter.py @@ -1,3 +1,4 @@ +"""Format converter.""" from collections import defaultdict from contextlib import contextmanager from functools import singledispatchmethod @@ -6,12 +7,12 @@ from rdflib.plugins.sparql.parser import parseQuery -from ontolearn.owlapy.model import OWLClassExpression, OWLClass, OWLEntity, OWLObjectProperty, OWLObjectIntersectionOf, \ +from ontolearn.owlapy.model import OWLClassExpression, OWLClass, OWLEntity, OWLObjectProperty, \ OWLObjectUnionOf, OWLObjectComplementOf, OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom, OWLObjectHasValue, \ OWLNamedIndividual, OWLObjectCardinalityRestriction, OWLObjectMinCardinality, OWLObjectExactCardinality, \ OWLObjectMaxCardinality, OWLDataCardinalityRestriction, OWLDataProperty, OWLObjectHasSelf, OWLObjectOneOf, \ OWLDataSomeValuesFrom, OWLDataAllValuesFrom, OWLDataHasValue, OWLDatatype, TopOWLDatatype, OWLDataOneOf, \ - OWLLiteral, OWLDatatypeRestriction + OWLLiteral, OWLDatatypeRestriction, OWLObjectIntersectionOf from ontolearn.owlapy.vocab import OWLFacet, OWLRDFVocabulary _Variable_facet_comp = MappingProxyType({ @@ -23,10 +24,17 @@ def peek(x): + """Peek the last element of an array. + + Returns: + The last element arr[-1]. + + """ return x[-1] class VariablesMapping: + """Helper class for owl-to-sparql conversion.""" __slots__ = 'class_cnt', 'prop_cnt', 'ind_cnt', 'dict' def __init__(self): @@ -70,6 +78,7 @@ def __getitem__(self, item: OWLEntity) -> str: class Owl2SparqlConverter: + """Convert owl (owlapy model class expressions) to SPARQL.""" __slots__ = 'ce', 'sparql', 'variables', 'parent', 'parent_var', 'properties', 'variable_entities', 'cnt', \ 'mapping', 'grouping_vars', 'having_conditions', '_intersection' @@ -87,6 +96,16 @@ class Owl2SparqlConverter: cnt: int def convert(self, root_variable: str, ce: OWLClassExpression, named_individuals: bool = False): + """Used to convert owl class expression to SPARQL syntax. + + Args: + root_variable (str): Root variable name that will be used in SPARQL query. + ce (OWLClassExpression): The owl class expression to convert. + named_individuals (bool): If 'True' return only entities that are instances of owl:NamedIndividual. + + Returns: + list[str]: The SPARQL query. + """ self.ce = ce self.sparql = [] self.variables = [] @@ -361,7 +380,7 @@ def _(self, ce: OWLObjectHasValue): self.append_triple(self.current_variable, property_expression.get_named_property(), value) # an overload of process function - # this overload is responsible for handling the exists operator combined with an individual (e.g., >=3 hasChild.Male) + # this overload is responsible for handling the exists operator combined with an individual(e.g., >=3 hasChild.Male) # general case: \theta n r.C @process.register def _(self, ce: OWLObjectCardinalityRestriction): @@ -380,7 +399,8 @@ def _(self, ce: OWLObjectCardinalityRestriction): raise ValueError(ce) # if the comparator is ≤ or the cardinality is 0, we need an additional group graph pattern - # the additional group graph pattern will take care the cases where an individual is not associated with the property expression + # the additional group graph pattern will take care the cases where an individual is not associated with the + # property expression if comparator == "<=" or cardinality == 0: self.append("{") @@ -401,7 +421,8 @@ def _(self, ce: OWLObjectCardinalityRestriction): # here, the second group graph pattern starts if comparator == "<=" or cardinality == 0: self.append("} UNION {") - self.append_triple(subject_variable, self.mapping.new_individual_variable(), self.mapping.new_individual_variable()) + self.append_triple(subject_variable, self.mapping.new_individual_variable(), + self.mapping.new_individual_variable()) self.append("FILTER NOT EXISTS { ") object_variable = self.mapping.new_individual_variable() if property_expression.is_anonymous(): @@ -469,7 +490,6 @@ def _(self, ce: OWLObjectOneOf): self.append(f"<{ind.to_string_id()}>") self.append(f" )") - @process.register def _(self, ce: OWLDataSomeValuesFrom): object_variable = self.mapping.new_individual_variable() @@ -563,7 +583,7 @@ def triple(self, subject, predicate, object_): def as_query(self, root_variable: str, ce: OWLClassExpression, - count: bool=False, + count: bool = False, values: Optional[Iterable[OWLNamedIndividual]] = None, named_individuals: bool = False): # root variable: the variable that will be projected @@ -599,4 +619,3 @@ def as_query(self, query = "\n".join(qs) parseQuery(query) return query - diff --git a/ontolearn/owlapy/owlready2/__init__.py b/ontolearn/owlapy/owlready2/__init__.py index 45e325f3..6e567c6c 100644 --- a/ontolearn/owlapy/owlready2/__init__.py +++ b/ontolearn/owlapy/owlready2/__init__.py @@ -1,5 +1,6 @@ +"""Implementations based on owlready2.""" from ontolearn.owlapy._utils import MOVE -from ontolearn.owlapy.owlready2._base import OWLOntologyManager_Owlready2, OWLReasoner_Owlready2, OWLOntology_Owlready2,\ - BaseReasoner_Owlready2 +from ontolearn.owlapy.owlready2._base import OWLOntologyManager_Owlready2, OWLReasoner_Owlready2, \ + OWLOntology_Owlready2, BaseReasoner_Owlready2 MOVE(OWLOntologyManager_Owlready2, OWLReasoner_Owlready2, OWLOntology_Owlready2, BaseReasoner_Owlready2) __all__ = 'OWLOntologyManager_Owlready2', 'OWLReasoner_Owlready2', 'OWLOntology_Owlready2', 'BaseReasoner_Owlready2' diff --git a/ontolearn/owlapy/owlready2/_base.py b/ontolearn/owlapy/owlready2/_base.py index d682a3e3..fbca8b13 100644 --- a/ontolearn/owlapy/owlready2/_base.py +++ b/ontolearn/owlapy/owlready2/_base.py @@ -12,12 +12,12 @@ from ontolearn.owlapy.owlready2 import axioms from ontolearn.owlapy import namespaces from ontolearn.owlapy.ext import OWLReasonerEx -from ontolearn.owlapy.model import OWLObjectPropertyRangeAxiom, OWLOntologyManager, OWLDataProperty, OWLObjectProperty, \ +from ontolearn.owlapy.model import OWLObjectPropertyRangeAxiom, OWLOntologyManager, OWLDataProperty, \ OWLNamedIndividual, OWLClassExpression, OWLObjectPropertyExpression, OWLOntologyID, OWLAxiom, OWLOntology, \ OWLOntologyChange, AddImport, OWLThing, DoubleOWLDatatype, OWLObjectPropertyDomainAxiom, OWLLiteral, \ OWLObjectInverseOf, BooleanOWLDatatype, IntegerOWLDatatype, DateOWLDatatype, DateTimeOWLDatatype, OWLClass, \ DurationOWLDatatype, StringOWLDatatype, IRI, OWLDataPropertyRangeAxiom, OWLDataPropertyDomainAxiom, OWLClassAxiom, \ - OWLSubClassOfAxiom, OWLEquivalentClassesAxiom, OWLObjectSomeValuesFrom + OWLSubClassOfAxiom, OWLEquivalentClassesAxiom, OWLObjectSomeValuesFrom, OWLObjectProperty from ontolearn.owlapy.owlready2.utils import FromOwlready2 logger = logging.getLogger(__name__) @@ -51,6 +51,12 @@ def _unparse_duration_datatype(literal: Timedelta): class BaseReasoner_Owlready2(Enum): + """Enumeration class for base reasoner when calling sync_reasoner. + + Attributes: + PELLET: Pellet base reasoner. + HERMIT: HermiT base reasoner. + """ PELLET = auto() HERMIT = auto() @@ -61,6 +67,13 @@ class OWLOntologyManager_Owlready2(OWLOntologyManager): _world: owlready2.namespace.World def __init__(self, world_store=None): + """Ontology manager in Ontolearn. + Creates a world where ontology is loaded. + Used to make changes in the ontology. + + Args: + world_store: The file name of the world store. Leave to default value to create a new world. + """ if world_store is None: self._world = owlready2.World() else: @@ -100,7 +113,7 @@ def save_ontology(self, ontology: OWLOntology, document_iri: IRI): raise NotImplementedError def save_world(self): - """saves the actual state of the quadstore in the SQLite3 file + """Saves the actual state of the quadstore in the SQLite3 file. """ self._world.save() @@ -113,6 +126,13 @@ class OWLOntology_Owlready2(OWLOntology): _world: owlready2.World def __init__(self, manager: OWLOntologyManager_Owlready2, ontology_iri: IRI, load: bool): + """Represents an Ontology in Ontolearn. + + Args: + manager: Ontology manager. + ontology_iri: IRI of the ontology. + load: Whether to load the ontology or not. + """ self._manager = manager self._iri = ontology_iri self._world = manager._world @@ -221,6 +241,7 @@ def object_property_range_axioms(self, pe: OWLObjectProperty) -> Iterable[OWLObj pass # XXX TODO def get_original_iri(self): + """Get the IRI argument that was used to create this ontology.""" return self._iri def __eq__(self, other): @@ -246,7 +267,7 @@ def __init__(self, ontology: OWLOntology_Owlready2, isolate: bool = False): Base reasoner in Ontolearn, used to reason in the given ontology. Args: - ontology: the ontology that should be used by the reasoner + ontology: The ontology that should be used by the reasoner. isolate: Whether to isolate the reasoner in a new world + copy of the original ontology. Useful if you create multiple reasoner instances in the same script. """ @@ -269,15 +290,16 @@ def __init__(self, ontology: OWLOntology_Owlready2, isolate: bool = False): def update_isolated_ontology(self, axioms_to_add: List[OWLAxiom] = None, axioms_to_remove: List[OWLAxiom] = None): """ - Make changes to the isolated ontology that the reasoner is using. + Add or remove axioms to the isolated ontology that the reasoner is using. Args: - axioms_to_add: Axioms to add to the isolated ontology - axioms_to_remove: Axioms to remove from the isolated ontology + axioms_to_add (List[OWLAxiom]): Axioms to add to the isolated ontology. + axioms_to_remove (List[OWLAxiom]): Axioms to remove from the isolated ontology. """ if self._isolated: if axioms_to_add is None and axioms_to_remove is None: - raise ValueError("At least one argument should be specified.") + raise ValueError(f"At least one argument should be specified in method: " + f"{self.update_isolated_ontology.__name__}") manager = self._ontology.get_owl_ontology_manager() if axioms_to_add is not None: for axiom in axioms_to_add: @@ -286,7 +308,8 @@ def update_isolated_ontology(self, axioms_to_add: List[OWLAxiom] = None, for axiom in axioms_to_remove: manager.remove_axiom(self._ontology, axiom) else: - raise AssertionError("The reasoner is not using an isolated ontology.") + raise AssertionError(f"Misuse of method '{self.update_isolated_ontology.__name__}'. The reasoner is not " + f"using an isolated ontology.") def data_property_domains(self, pe: OWLDataProperty, direct: bool = False) -> Iterable[OWLClassExpression]: domains = {d.get_domain() for d in self.get_root_ontology().data_property_domain_axioms(pe)} @@ -671,7 +694,7 @@ def disjoint_data_properties(self, dp: OWLDataProperty) -> Iterable[OWLDataPrope if d != OWLDataProperty(IRI('http://www.w3.org/2002/07/owl#', 'DatatypeProperty')): yield from self._find_disjoint_data_properties(d, seen_set=seen_set) - def _sup_or_sup_data_properties_recursive(self, dp: OWLDataProperty, seen_set: Set, super_or_sub="") \ + def _sup_or_sub_data_properties_recursive(self, dp: OWLDataProperty, seen_set: Set, super_or_sub="") \ -> Iterable[OWLDataProperty]: for d in self.equivalent_data_properties(dp): if d not in seen_set: @@ -689,9 +712,9 @@ def _sup_or_sup_data_properties_recursive(self, dp: OWLDataProperty, seen_set: S if sp not in seen_set: seen_set.add(sp) yield sp - yield from self._sup_or_sup_data_properties_recursive(sp, seen_set, super_or_sub) + yield from self._sup_or_sub_data_properties_recursive(sp, seen_set, super_or_sub) - def _sup_or_sup_data_properties(self, dp: OWLDataProperty, direct: bool = False, super_or_sub=""): + def _sup_or_sub_data_properties(self, dp: OWLDataProperty, direct: bool = False, super_or_sub=""): assert isinstance(dp, OWLDataProperty) if direct: p_x: owlready2.DataPropertyClass = self._world[dp.get_iri().as_str()] @@ -704,13 +727,24 @@ def _sup_or_sup_data_properties(self, dp: OWLDataProperty, direct: bool = False, yield OWLDataProperty(IRI.create(sp.iri)) else: seen_set = set() - yield from self._sup_or_sup_data_properties_recursive(dp, seen_set, super_or_sub) + yield from self._sup_or_sub_data_properties_recursive(dp, seen_set, super_or_sub) def super_data_properties(self, dp: OWLDataProperty, direct: bool = False) -> Iterable[OWLDataProperty]: - yield from self._sup_or_sup_data_properties(dp, direct, "super") + """Gets the stream of data properties that are the strict (potentially direct) super properties of the + specified data property with respect to the imports closure of the root ontology. + + Args: + dp (OWLDataProperty): The data property whose super properties are to be retrieved. + direct (bool): Specifies if the direct super properties should be retrieved (True) or if the all + super properties (ancestors) should be retrieved (False). + + Returns: + Iterable of super properties. + """ + yield from self._sup_or_sub_data_properties(dp, direct, "super") def sub_data_properties(self, dp: OWLDataProperty, direct: bool = False) -> Iterable[OWLDataProperty]: - yield from self._sup_or_sup_data_properties(dp, direct, "sub") + yield from self._sup_or_sub_data_properties(dp, direct, "sub") def _sup_or_sub_object_properties_recursive(self, op: OWLObjectProperty, seen_set: Set, super_or_sub=""): for o in self.equivalent_object_properties(op): @@ -761,6 +795,18 @@ def _sup_or_sub_object_properties(self, op: OWLObjectPropertyExpression, direct: def super_object_properties(self, op: OWLObjectPropertyExpression, direct: bool = False) \ -> Iterable[OWLObjectPropertyExpression]: + """Gets the stream of object properties that are the strict (potentially direct) super properties of the + specified object property with respect to the imports closure of the root ontology. + + Args: + op (OWLObjectPropertyExpression): The object property expression whose super properties are to be + retrieved. + direct (bool): Specifies if the direct super properties should be retrieved (True) or if the all + super properties (ancestors) should be retrieved (False). + + Returns: + Iterable of super properties. + """ yield from self._sup_or_sub_object_properties(op, direct, "super") def sub_object_properties(self, op: OWLObjectPropertyExpression, direct: bool = False) \ @@ -783,12 +829,12 @@ def types(self, ind: OWLNamedIndividual, direct: bool = False) -> Iterable[OWLCl def _sync_reasoner(self, other_reasoner: BaseReasoner_Owlready2 = None, infer_property_values: bool = True, infer_data_property_values: bool = True, debug: bool = False) -> None: - """Call Owlready2's sync_reasoner method, which spawns a Java process on a temp file to infer more + """Call Owlready2's sync_reasoner method, which spawns a Java process on a temp file to infer more. Args: - other_reasoner: set to BaseReasoner.PELLET (default) or BaseReasoner.HERMIT - infer_property_values: whether to infer property values - infer_data_property_values: whether to infer data property values (only for PELLET) + other_reasoner: Set to BaseReasoner.PELLET (default) or BaseReasoner.HERMIT. + infer_property_values: Whether to infer property values. + infer_data_property_values: Whether to infer data property values (only for PELLET). """ assert other_reasoner is None or isinstance(other_reasoner, BaseReasoner_Owlready2) with self.get_root_ontology()._onto: @@ -804,4 +850,5 @@ def get_root_ontology(self) -> OWLOntology: return self._ontology def is_isolated(self): + """Return True if this reasoner is using an isolated ontology.""" return self._isolated diff --git a/ontolearn/owlapy/owlready2/axioms.py b/ontolearn/owlapy/owlready2/axioms.py index 8341f8c5..e2757134 100644 --- a/ontolearn/owlapy/owlready2/axioms.py +++ b/ontolearn/owlapy/owlready2/axioms.py @@ -1,3 +1,4 @@ +"""Logic behind adding and removing axioms.""" from functools import singledispatch from itertools import islice, combinations import types @@ -6,7 +7,7 @@ import owlready2 from owlready2 import destroy_entity, AllDisjoint, AllDifferent, GeneralClassAxiom -from ontolearn.owlapy.model import OWLDisjointUnionAxiom, OWLQuantifiedDataRestriction, OWLQuantifiedObjectRestriction, \ +from ontolearn.owlapy.model import OWLDisjointUnionAxiom, OWLQuantifiedDataRestriction, \ OWLAnnotationAssertionAxiom, OWLClass, OWLClassAssertionAxiom, OWLEquivalentClassesAxiom, OWLObject, \ OWLAnnotationProperty, OWLDataHasValue, OWLDataProperty, OWLDeclarationAxiom, OWLIndividual, \ OWLNamedIndividual, OWLNaryBooleanClassExpression, OWLObjectComplementOf, OWLObjectHasValue, \ @@ -18,7 +19,8 @@ OWLInverseFunctionalObjectPropertyAxiom, OWLIrreflexiveObjectPropertyAxiom, OWLObjectPropertyCharacteristicAxiom, \ OWLDisjointDataPropertiesAxiom, OWLDisjointObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom, \ OWLEquivalentObjectPropertiesAxiom, OWLInverseObjectPropertiesAxiom, OWLNaryPropertyAxiom, OWLNaryIndividualAxiom, \ - OWLDifferentIndividualsAxiom, OWLDisjointClassesAxiom, OWLSameIndividualAxiom, OWLProperty + OWLDifferentIndividualsAxiom, OWLDisjointClassesAxiom, OWLSameIndividualAxiom, OWLProperty, \ + OWLQuantifiedObjectRestriction from ontolearn.owlapy.owlready2.utils import ToOwlready2 diff --git a/ontolearn/owlapy/owlready2/complex_ce_instances.py b/ontolearn/owlapy/owlready2/complex_ce_instances.py index f7d468e9..8294ef6d 100644 --- a/ontolearn/owlapy/owlready2/complex_ce_instances.py +++ b/ontolearn/owlapy/owlready2/complex_ce_instances.py @@ -1,3 +1,4 @@ +"""OWL Reasoner - Complex Class Expression Instances (CCEI).""" import logging import types from logging import warning @@ -22,11 +23,13 @@ class OWLReasoner_Owlready2_ComplexCEInstances(OWLReasoner_Owlready2): def __init__(self, ontology: OWLOntology_Owlready2, base_reasoner: Optional[BaseReasoner_Owlready2] = None, infer_property_values: bool = True, infer_data_property_values: bool = True, isolate: bool = False): """ + OWL Reasoner with support for Complex Class Expression Instances + sync_reasoner. + Args: - ontology: the ontology that should be used by the reasoner - base_reasoner: set to BaseReasoner.PELLET (default) or BaseReasoner.HERMIT - infer_property_values: whether to infer property values - infer_data_property_values: whether to infer data property values (only for PELLET) + ontology: The ontology that should be used by the reasoner. + base_reasoner: Set to BaseReasoner.PELLET (default) or BaseReasoner.HERMIT. + infer_property_values: Whether to infer property values. + infer_data_property_values: Whether to infer data property values (only for PELLET). isolate: Whether to isolate the reasoner in a new world + copy of the original ontology. Useful if you create multiple reasoner instances in the same script. """ @@ -47,6 +50,9 @@ def __init__(self, ontology: OWLOntology_Owlready2, base_reasoner: Optional[Base def update_isolated_ontology(self, axioms_to_add: List[OWLAxiom] = None, axioms_to_remove: List[OWLAxiom] = None): if self._isolated: + if axioms_to_add is None and axioms_to_remove is None: + raise ValueError(f"At least one argument should be specified in method: " + f"{self.update_isolated_ontology.__name__}") self._ontology = self.reference_ontology super().update_isolated_ontology(axioms_to_add, axioms_to_remove) self.reference_ontology.get_owl_ontology_manager().save_ontology(self._ontology, self.reference_iri) @@ -56,7 +62,8 @@ def update_isolated_ontology(self, axioms_to_add: List[OWLAxiom] = None, self._world = new_manager._world self._sync_reasoner(self._base_reasoner, self.infer_property_values, self.infer_data_property_values) else: - raise AssertionError("The reasoner is not using an isolated ontology.") + raise AssertionError(f"Misuse of method '{self.update_isolated_ontology.__name__}'. The reasoner is not " + f"using an isolated ontology.") def instances(self, ce: OWLClassExpression, direct: bool = False) -> Iterable[OWLNamedIndividual]: if isinstance(ce, OWLClass): @@ -89,4 +96,4 @@ def __del__(self): try: os.remove(file_path) except OSError as e: - logger.warning(f"Error deleting {file_path}") + logger.warning(f"Error deleting {file_path}: {e}") diff --git a/ontolearn/owlapy/owlready2/plus.py b/ontolearn/owlapy/owlready2/plus.py index 2c8a31e0..f1b9f6c0 100644 --- a/ontolearn/owlapy/owlready2/plus.py +++ b/ontolearn/owlapy/owlready2/plus.py @@ -1,16 +1,18 @@ +"""OWL Reasoner Plus.""" from typing import Iterable, Set import owlready2 from ontolearn.owlapy import namespaces -from ontolearn.owlapy.model import OWLObjectPropertyExpression, OWLObjectProperty, OWLClassExpression, OWLClass, OWLThing, IRI +from ontolearn.owlapy.model import OWLObjectPropertyExpression, OWLObjectProperty, OWLClassExpression, OWLClass, \ + OWLThing, IRI from ontolearn.owlapy.owlready2 import OWLReasoner_Owlready2 class OWLReasoner_Owlready2_Plus(OWLReasoner_Owlready2): - """OWL Reasoner based on owlready2 + """OWL Reasoner based on owlready2. - contains some behavioural fixes""" + Contains some behavioural fixes.""" def sub_classes(self, ce: OWLClassExpression, direct: bool = False) -> Iterable[OWLClass]: if isinstance(ce, OWLClass): if direct: diff --git a/ontolearn/owlapy/owlready2/utils.py b/ontolearn/owlapy/owlready2/utils.py index 94cfaad6..02c7a807 100644 --- a/ontolearn/owlapy/owlready2/utils.py +++ b/ontolearn/owlapy/owlready2/utils.py @@ -1,3 +1,4 @@ +"""Utils for mapping to and from owlready2.""" from datetime import date, datetime from functools import singledispatchmethod from types import MappingProxyType @@ -6,7 +7,7 @@ import owlready2 from pandas import Timedelta -from ontolearn.owlapy.model import OWLObjectMinCardinality, OWLObjectOneOf, OWLObjectRestriction, OWLPropertyExpression, \ +from ontolearn.owlapy.model import OWLObjectMinCardinality, OWLObjectOneOf, OWLObjectRestriction, \ OWLObjectComplementOf, OWLObjectUnionOf, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom, \ OWLObjectPropertyExpression, OWLObject, OWLOntology, OWLAnnotationProperty, IRI, OWLObjectInverseOf, \ DoubleOWLDatatype, IntegerOWLDatatype, OWLClassExpression, OWLDataAllValuesFrom, OWLDataComplementOf, \ @@ -15,7 +16,7 @@ OWLDataPropertyExpression, OWLDatatypeRestriction, OWLFacetRestriction, OWLLiteral, OWLObjectHasValue, \ OWLNamedIndividual, OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectProperty, OWLClass, \ DateOWLDatatype, DateTimeOWLDatatype, DurationOWLDatatype, OWLRestriction, OWLDataOneOf, OWLDataRestriction, \ - OWLIndividual, StringOWLDatatype + OWLIndividual, StringOWLDatatype, OWLPropertyExpression from ontolearn.owlapy.vocab import OWLFacet @@ -35,15 +36,22 @@ class ToOwlready2: + __slots__ = '_world' _world: owlready2.World def __init__(self, world: owlready2.World): + """Map owlapy model classes to owlready2. + + Args: + world: Owlready2 World to use for mapping. + """ self._world = world @singledispatchmethod def map_object(self, o: OWLObject): + """Map owlapy object classes.""" raise NotImplementedError(f'don\'t know how to map {o}') @map_object.register @@ -64,6 +72,7 @@ def _(self, ap: OWLAnnotationProperty) -> owlready2.annotation.AnnotationPropert @singledispatchmethod def map_concept(self, o: OWLClassExpression) \ -> Union[owlready2.ClassConstruct, owlready2.ThingClass]: + """Map owlapy concept classes.""" raise NotImplementedError(o) @singledispatchmethod @@ -173,6 +182,7 @@ def _(self, ce: OWLDataHasValue) -> owlready2.class_construct.Restriction: @singledispatchmethod def map_datarange(self, p: OWLDataRange) -> Union[owlready2.ClassConstruct, type]: + """Map owlapy data range classes.""" raise NotImplementedError(p) @map_datarange.register @@ -221,10 +231,12 @@ def _(self, type_: OWLDatatype) -> type: class FromOwlready2: + """Map owlready2 classes to owlapy model classes.""" __slots__ = () @singledispatchmethod def map_concept(self, c: Union[owlready2.ClassConstruct, owlready2.ThingClass]) -> OWLClassExpression: + """Map concept classes.""" raise NotImplementedError(c) @singledispatchmethod @@ -317,6 +329,7 @@ def _to_data_property(self, c: owlready2.Restriction) -> OWLDataRestriction: @singledispatchmethod def map_datarange(self, p: owlready2.ClassConstruct) -> OWLDataRange: + """Map data range classes.""" raise NotImplementedError(p) @map_datarange.register diff --git a/ontolearn/owlapy/parser.py b/ontolearn/owlapy/parser.py index 76302055..97cb50f6 100644 --- a/ontolearn/owlapy/parser.py +++ b/ontolearn/owlapy/parser.py @@ -1,3 +1,4 @@ +"""String to OWL parsers.""" from types import MappingProxyType from typing import Final, List, Optional, Union from parsimonious.grammar import Grammar @@ -176,8 +177,8 @@ class _ManchesterOWLSyntaxParserMeta(type(NodeVisitor), type(OWLObjectParser)): class ManchesterOWLSyntaxParser(NodeVisitor, OWLObjectParser, metaclass=_ManchesterOWLSyntaxParserMeta): - """Manchester Syntax parser to parse strings to OWLClassExpressions - Following: https://www.w3.org/TR/owl2-manchester-syntax""" + """Manchester Syntax parser to parse strings to OWLClassExpressions. + Following: https://www.w3.org/TR/owl2-manchester-syntax.""" slots = 'ns', 'grammar' @@ -191,8 +192,8 @@ def __init__(self, namespace: Optional[Union[str, Namespaces]] = None, grammar=N Prefixes are currently not supported, except for datatypes. Args: - namespace: Namespace to resolve names that were given without one - grammar: Grammar (defaults to MANCHESTERGRAMMAR) + namespace: Namespace to resolve names that were given without one. + grammar: Grammar (defaults to MANCHESTERGRAMMAR). """ self.ns = namespace self.grammar = grammar @@ -520,7 +521,7 @@ class _DLSyntaxParserMeta(type(NodeVisitor), type(OWLObjectParser)): class DLSyntaxParser(NodeVisitor, OWLObjectParser, metaclass=_DLSyntaxParserMeta): - """Description Logic Syntax parser to parse strings to OWLClassExpressions""" + """Description Logic Syntax parser to parse strings to OWLClassExpressions.""" slots = 'ns', 'grammar' @@ -532,8 +533,8 @@ def __init__(self, namespace: Optional[Union[str, Namespaces]] = None, grammar=N Prefixes are currently not supported, except for datatypes. Args: - namespace: Namespace to resolve names that were given without one - grammar: Grammar (defaults to DL_GRAMMAR) + namespace: Namespace to resolve names that were given without one. + grammar: Grammar (defaults to DL_GRAMMAR). """ self.ns = namespace self.grammar = grammar diff --git a/ontolearn/owlapy/render.py b/ontolearn/owlapy/render.py index f357cc8f..1a207438 100644 --- a/ontolearn/owlapy/render.py +++ b/ontolearn/owlapy/render.py @@ -1,3 +1,4 @@ +"""Renderers for different syntax.""" # -*- coding: utf-8 -*- import types @@ -53,16 +54,16 @@ def _simple_short_form_provider(e: OWLEntity) -> str: class DLSyntaxObjectRenderer(OWLObjectRenderer): - """DL Syntax renderer for OWL Objects""" + """DL Syntax renderer for OWL Objects.""" __slots__ = '_sfp' _sfp: Callable[[OWLEntity], str] def __init__(self, short_form_provider: Callable[[OWLEntity], str] = _simple_short_form_provider): - """Create a new DL Syntax renderer + """Create a new DL Syntax renderer. Args: - short_form_provider: custom short form provider + short_form_provider: Custom short form provider. """ self._sfp = short_form_provider diff --git a/ontolearn/owlapy/util.py b/ontolearn/owlapy/util.py index 93a0cf29..970358ac 100644 --- a/ontolearn/owlapy/util.py +++ b/ontolearn/owlapy/util.py @@ -1,3 +1,4 @@ +"""Owlapy utils.""" from functools import singledispatchmethod, total_ordering from typing import Iterable, List, Type, TypeVar, Generic, Tuple, cast, Optional, Union, overload @@ -23,10 +24,13 @@ @total_ordering class OrderedOWLObject: - """Holder of OWL Objects that can be used for Python sorted + """Holder of OWL Objects that can be used for Python sorted. The Ordering is dependent on the type_index of the impl. classes recursively followed by all components of the OWL Object. + + Attributes: + o: OWL object. """ __slots__ = 'o', '_chain' @@ -35,10 +39,10 @@ class OrderedOWLObject: # we are limited by https://github.com/python/typing/issues/213 # o: Intersection[OWLObject, HasIndex] def __init__(self, o: _HasIndex): - """OWL Object holder with a defined sort order + """OWL Object holder with a defined sort order. Args: - o: OWL Object + o: OWL Object. """ self.o = o self._chain = None @@ -92,17 +96,17 @@ def _sort_by_ordered_owl_object(i: Iterable[_O]) -> Iterable[_O]: class NNF: - """This class contains functions to transform a Class Expression into Negation Normal Form""" + """This class contains functions to transform a Class Expression into Negation Normal Form.""" @singledispatchmethod def get_class_nnf(self, ce: OWLClassExpression, negated: bool = False) -> OWLClassExpression: """Convert a Class Expression to Negation Normal Form. Operands will be sorted. Args: - ce: Class Expression - negated: whether the result should be negated + ce: Class Expression. + negated: Whether the result should be negated. Returns: - Class Expression in Negation Normal Form + Class Expression in Negation Normal Form. """ raise NotImplementedError @@ -280,32 +284,32 @@ def _(self, ce: OWLDataMaxCardinality, negated: bool = False): # OWL-APy custom util start class TopLevelCNF: - """This class contains functions to transform a class expression into Top-Level Conjunctive Normal Form""" + """This class contains functions to transform a class expression into Top-Level Conjunctive Normal Form.""" def get_top_level_cnf(self, ce: OWLClassExpression) -> OWLClassExpression: """Convert a class expression into Top-Level Conjunctive Normal Form. Operands will be sorted. Args: - ce: Class Expression + ce: Class Expression. Returns: - Class Expression in Top-Level Conjunctive Normal Form + Class Expression in Top-Level Conjunctive Normal Form. """ c = _get_top_level_form(ce.get_nnf(), OWLObjectUnionOf, OWLObjectIntersectionOf) return combine_nary_expressions(c) class TopLevelDNF: - """This class contains functions to transform a class expression into Top-Level Disjunctive Normal Form""" + """This class contains functions to transform a class expression into Top-Level Disjunctive Normal Form.""" def get_top_level_dnf(self, ce: OWLClassExpression) -> OWLClassExpression: """Convert a class expression into Top-Level Disjunctive Normal Form. Operands will be sorted. Args: - ce: Class Expression + ce: Class Expression. Returns: - Class Expression in Top-Level Disjunctive Normal Form + Class Expression in Top-Level Disjunctive Normal Form. """ c = _get_top_level_form(ce.get_nnf(), OWLObjectIntersectionOf, OWLObjectUnionOf) return combine_nary_expressions(c) @@ -367,11 +371,11 @@ def combine_nary_expressions(ce: OWLDataRange) -> OWLDataRange: def combine_nary_expressions(ce: OWLPropertyRange) -> OWLPropertyRange: - ''' Shortens an OWLClassExpression or OWLDataRange by combining all nested nary expressions of the same type. + """ Shortens an OWLClassExpression or OWLDataRange by combining all nested nary expressions of the same type. Operands will be sorted. - E.g. OWLObjectUnionOf(A, OWLObjectUnionOf(C, B)) -> OWLObjectUnionOf(A, B, C) - ''' + E.g. OWLObjectUnionOf(A, OWLObjectUnionOf(C, B)) -> OWLObjectUnionOf(A, B, C). + """ if isinstance(ce, (OWLNaryBooleanClassExpression, OWLNaryDataRange)): expressions: List[OWLPropertyRange] = [] for op in ce.operands(): @@ -405,21 +409,31 @@ def combine_nary_expressions(ce: OWLPropertyRange) -> OWLPropertyRange: def iter_count(i: Iterable) -> int: - """Count the number of elements in an iterable""" + """Count the number of elements in an iterable.""" return sum(1 for _ in i) def as_index(o: OWLObject) -> HasIndex: - """Cast OWL Object to HasIndex""" + """Cast OWL Object to HasIndex.""" i = cast(HasIndex, o) assert type(i).type_index return i -# adapted from functools.lru_cache class LRUCache(Generic[_K, _V]): - # Constants shared by all lru cache instances: - sentinel = object() # unique object used to signal cache misses + """Constants shares by all lru cache instances. + + Adapted from functools.lru_cache. + + Attributes: + sentinel: Unique object used to signal cache misses. + PREV: Name for the link field 0. + NEXT: Name for the link field 1. + KEY: Name for the link field 2. + RESULT: Name for the link field 3. + """ + + sentinel = object() PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields def __init__(self, maxsize: Optional[int] = None): @@ -498,14 +512,14 @@ def __setitem__(self, key: _K, value: _V): self.full = (self.cache_len() >= self.maxsize) def cache_info(self): - """Report cache statistics""" + """Report cache statistics.""" with self.lock: from collections import namedtuple return namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])( self.hits, self.misses, self.maxsize, self.cache_len()) def cache_clear(self): - """Clear the cache and cache statistics""" + """Clear the cache and cache statistics.""" with self.lock: self.cache.clear() self.root[:] = [self.root, self.root, None, None] diff --git a/ontolearn/owlapy/vocab.py b/ontolearn/owlapy/vocab.py index 90614804..1bf4ab8e 100644 --- a/ontolearn/owlapy/vocab.py +++ b/ontolearn/owlapy/vocab.py @@ -1,3 +1,4 @@ +"""Enumerations.""" from abc import ABCMeta from enum import Enum, EnumMeta from typing import Final, Callable, TypeVar @@ -37,6 +38,7 @@ class _meta_Enum(ABCMeta, EnumMeta): class OWLRDFVocabulary(_Vocabulary, Enum, metaclass=_meta_Enum): + """Enumerations for OWL/RDF vocabulary.""" def __new__(cls, namespace: Namespaces, remainder: str, *args): obj = object.__new__(cls) obj._value_ = f"{namespace.prefix}:{remainder}" @@ -53,6 +55,7 @@ def __new__(cls, namespace: Namespaces, remainder: str, *args): class XSDVocabulary(_Vocabulary, Enum, metaclass=_meta_Enum): + """Enumerations for XSD vocabulary.""" def __new__(cls, remainder: str, *args): obj = object.__new__(cls) obj._value_ = f"{namespaces.XSD.prefix}:{remainder}" @@ -78,6 +81,7 @@ def __init__(self, remainder: str): # TODO: Add langRange facet class OWLFacet(_Vocabulary, Enum, metaclass=_meta_Enum): + """Enumerations for OWL facets.""" def __new__(cls, remainder: str, *args): obj = object.__new__(cls) obj._value_ = f"{namespaces.XSD.prefix}:{remainder}" diff --git a/ontolearn/owlready2/__init__.py b/ontolearn/owlready2/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ontolearn/owlready2/utils.py b/ontolearn/owlready2/utils.py deleted file mode 100644 index 52f88f91..00000000 --- a/ontolearn/owlready2/utils.py +++ /dev/null @@ -1,2 +0,0 @@ -def get_full_iri(x): - return x.namespace.base_iri + x.name diff --git a/ontolearn/refinement_operators.py b/ontolearn/refinement_operators.py index 2297f178..98e1d1ff 100644 --- a/ontolearn/refinement_operators.py +++ b/ontolearn/refinement_operators.py @@ -1,3 +1,4 @@ +"""Refinement Operators for refinement-based concept learners.""" from collections import defaultdict from itertools import chain import random @@ -20,7 +21,7 @@ # TODO: 23 Warnings need to be fixed here to avoid runtime errors class LengthBasedRefinement(BaseRefinement): - """ A top down refinement operator refinement operator in ALC.""" + """ A top-down refinement operator in ALC.""" def __init__(self, knowledge_base: KnowledgeBase): super().__init__(knowledge_base) @@ -48,17 +49,19 @@ def refine_top(self) -> Iterable: """ (3) Add Nothing """ iterable_container.append([self.kb.generator.nothing]) """ (4) Get all most general restrictions and store them forall r. T, \\exist r. T """ - iterable_container.append(self.kb.most_general_universal_restrictions(domain=self.kb.generator.thing, filler=None)) - iterable_container.append(self.kb.most_general_existential_restrictions(domain=self.kb.generator.thing, filler=None)) + iterable_container.append(self.kb.most_general_universal_restrictions(domain=self.kb.generator.thing, + filler=None)) + iterable_container.append(self.kb.most_general_existential_restrictions(domain=self.kb.generator.thing, + filler=None)) """ (5) Generate all refinements of given concept that have length less or equal to the maximum refinement length constraint """ yield from self.apply_union_and_intersection_from_iterable(iterable_container) def apply_union_and_intersection_from_iterable(self, cont: Iterable[Generator]) -> Iterable: - """ Create Union and Intersection OWL Class Expressions - 1. Create OWLObjectIntersectionOf via logical conjunction of cartesian product of input owl class expressions + """ Create Union and Intersection OWL Class Expressions. + 1. Create OWLObjectIntersectionOf via logical conjunction of cartesian product of input owl class expressions. 2. Create OWLObjectUnionOf class expression via logical disjunction pf cartesian product of input owl class - expressions + expressions. Repeat 1 and 2 until all concepts having max_len_refinement_top reached. """ cumulative_refinements = dict() @@ -116,7 +119,7 @@ def apply_union_and_intersection_from_iterable(self, cont: Iterable[Generator]) def refine_atomic_concept(self, class_expression: OWLClassExpression) -> Iterable[OWLClassExpression]: """ - Refine an atomic class expressions, i.e,. length 1 + Refine an atomic class expressions, i.e,. length 1. """ assert isinstance(class_expression, OWLClassExpression) for i in self.top_refinements: @@ -129,12 +132,13 @@ def refine_atomic_concept(self, class_expression: OWLClassExpression) -> Iterabl def refine_complement_of(self, class_expression: OWLObjectComplementOf) -> Iterable[OWLClassExpression]: """ Refine OWLObjectComplementOf - 1- Get All direct parents - 2- Negate (1) - 3- Intersection with T + 1- Get All direct parents, + 2- Negate (1), + 3- Intersection with T. """ assert isinstance(class_expression, OWLObjectComplementOf) - yield from self.kb.generator.negation_from_iterables(self.kb.get_direct_parents(self.kb.negation(class_expression))) + yield from self.kb.generator.negation_from_iterables(self.kb.get_direct_parents( + self.kb.negation(class_expression))) yield self.kb.generator.intersection((class_expression, self.kb.generator.thing)) def refine_object_some_values_from(self, class_expression: OWLObjectSomeValuesFrom) -> Iterable[OWLClassExpression]: @@ -155,7 +159,7 @@ def refine_object_all_values_from(self, class_expression: OWLObjectAllValuesFrom def refine_object_union_of(self, class_expression: OWLObjectUnionOf) -> Iterable[OWLClassExpression]: """ - Refine C =A AND B + Refine C =A AND B. """ assert isinstance(class_expression, OWLObjectUnionOf) operands: List[OWLClassExpression] = list(class_expression.operands()) @@ -168,7 +172,7 @@ def refine_object_union_of(self, class_expression: OWLObjectUnionOf) -> Iterable def refine_object_intersection_of(self, class_expression: OWLClassExpression) -> Iterable[OWLClassExpression]: """ - Refine C =A AND B + Refine C =A AND B. """ assert isinstance(class_expression, OWLObjectIntersectionOf) operands: List[OWLClassExpression] = list(class_expression.operands()) @@ -204,7 +208,7 @@ def refine(self, class_expression) -> Iterable[OWLClassExpression]: class ModifiedCELOERefinement(BaseRefinement[OENode]): """ - A top down/downward refinement operator refinement operator in SHIQ(D). + A top down/downward refinement operator in SHIQ(D). """ __slots__ = 'max_child_length', 'use_negation', 'use_all_constructor', 'use_inverse', 'use_card_restrictions', \ 'max_nr_fillers', 'card_limit', 'use_numeric_datatypes', 'use_boolean_datatype', 'dp_splits', \ @@ -287,14 +291,14 @@ def _setup(self): def _operands_len(self, _Type: Type[OWLNaryBooleanClassExpression], ops: List[OWLClassExpression]) -> int: - """Calculate the length of a OWL Union or Intersection with operands ops + """Calculate the length of a OWL Union or Intersection with operands ops. Args: - _Type: type of class expression (OWLObjectUnionOf or OWLObjectIntersectionOf) - ops: list of operands + _Type: Type of class expression (OWLObjectUnionOf or OWLObjectIntersectionOf) + ops: list of operands. Returns: - length of expression + Length of expression. """ length = 0 if len(ops) == 1: @@ -325,23 +329,23 @@ def refine_atomic_concept(self, ce: OWLClass, max_length: int, distinguishes the refinement of atomic concepts and start concept(they called Top concept). [1] Concept learning, Lehmann et. al - (1) Generate all subconcepts given C, Denoted by (SH_down(C)) - (2) Generate {A AND C | A \\in SH_down(C)} - (2) Generate {A OR C | A \\in SH_down(C)} - (3) Generate {\\not A | A \\in SH_down(C) AND_logical \\not \\exist B in T : B \\sqsubset A} - (4) Generate restrictions. - (5) Intersect and union (1),(2),(3),(4) - (6) Create negation of all leaf_concepts + (1) Generate all subconcepts given C, Denoted by (SH_down(C)), + (2) Generate {A AND C | A \\in SH_down(C)}, + (2) Generate {A OR C | A \\in SH_down(C)}, + (3) Generate {\\not A | A \\in SH_down(C) AND_logical \\not \\exist B in T : B \\sqsubset A}, + (4) Generate restrictions, + (5) Intersect and union (1),(2),(3),(4), + (6) Create negation of all leaf_concepts. (***) The most general relation is not available. Args: - ce: - max_length: - current_domain: + ce: Atomic concept to refine. + max_length: Refine up to this concept length. + current_domain: Domain. Returns: - ? + Iterable of refined concepts. """ assert isinstance(ce, OWLClass) @@ -389,7 +393,8 @@ def refine_atomic_concept(self, ce: OWLClass, max_length: int, bool_res = [] for bool_dp in self.kb.most_general_boolean_data_properties(domain=current_domain): bool_res.append(self.generator.data_has_value_restriction(value=OWLLiteral(True), property=bool_dp)) - bool_res.append(self.generator.data_has_value_restriction(value=OWLLiteral(False), property=bool_dp)) + bool_res.append(self.generator.data_has_value_restriction(value=OWLLiteral(False), + property=bool_dp)) iter_container.append(bool_res) # yield self.kb.intersection((ce, ce)) # yield self.kb.union((ce, ce)) @@ -445,6 +450,14 @@ def refine_atomic_concept(self, ce: OWLClass, max_length: int, # if self.kb.individuals_count(temp_intersection) > 0: def refine_complement_of(self, ce: OWLObjectComplementOf) -> Iterable[OWLClassExpression]: + """ Refine owl:complementOf. + + Args: + ce (OWLObjectComplementOf): owl:complementOf - class expression. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectComplementOf) if self.use_negation: @@ -455,6 +468,15 @@ def refine_complement_of(self, ce: OWLObjectComplementOf) -> Iterable[OWLClassEx def refine_object_some_values_from(self, ce: OWLObjectSomeValuesFrom, max_length: int) \ -> Iterable[OWLClassExpression]: + """ Refine owl:someValuesFrom. + + Args: + ce (OWLObjectSomeValuesFrom): owl:someValuesFrom class expression. + max_length (int): Refine up to this concept length. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectSomeValuesFrom) assert isinstance(ce.get_filler(), OWLClassExpression) @@ -478,6 +500,15 @@ def refine_object_some_values_from(self, ce: OWLObjectSomeValuesFrom, max_length def refine_object_all_values_from(self, ce: OWLObjectAllValuesFrom, max_length: int) \ -> Iterable[OWLObjectAllValuesFrom]: + """Refine owl:allValuesFrom. + + Args: + ce (OWLObjectAllValuesFrom): owl:allValuesFrom - class expression. + max_length (int): Refine up to this concept length. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectAllValuesFrom) if self.use_all_constructor: @@ -497,6 +528,15 @@ def refine_object_all_values_from(self, ce: OWLObjectAllValuesFrom, max_length: def refine_object_min_card_restriction(self, ce: OWLObjectMinCardinality, max_length: int) \ -> Iterable[OWLObjectMinCardinality]: + """Refine owl:minCardinality. + + Args: + ce (OWLObjectMinCardinality): owl:minCardinality - class expression. + max_length (int): Refine up to this concept length. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectMinCardinality) assert ce.get_cardinality() >= 0 @@ -506,10 +546,20 @@ def refine_object_min_card_restriction(self, ce: OWLObjectMinCardinality, max_le yield self.generator.min_cardinality_restriction(i, ce.get_property(), ce.get_cardinality()) if ce.get_cardinality() < self.max_nr_fillers[ce.get_property()]: - yield self.generator.min_cardinality_restriction(ce.get_filler(), ce.get_property(), ce.get_cardinality() + 1) + yield self.generator.min_cardinality_restriction(ce.get_filler(), ce.get_property(), + ce.get_cardinality() + 1) def refine_object_max_card_restriction(self, ce: OWLObjectMaxCardinality, max_length: int) \ -> Iterable[OWLObjectMaxCardinality]: + """Refine owl:maxCardinality. + + Args: + ce (OWLObjectMaxCardinality): owl:maxCardinality - class expression. + max_length (int): Refine up to this concept length. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectMaxCardinality) assert ce.get_cardinality() >= 0 @@ -519,22 +569,25 @@ def refine_object_max_card_restriction(self, ce: OWLObjectMaxCardinality, max_le yield self.generator.max_cardinality_restriction(i, ce.get_property(), ce.get_cardinality()) if ce.get_cardinality() > 1 or (self.use_negation and ce.get_cardinality() > 0): - yield self.generator.max_cardinality_restriction(ce.get_filler(), ce.get_property(), ce.get_cardinality() - 1) + yield self.generator.max_cardinality_restriction(ce.get_filler(), ce.get_property(), + ce.get_cardinality() - 1) def refine_object_union_of(self, ce: OWLObjectUnionOf, max_length: int, current_domain: Optional[OWLClassExpression]) -> Iterable[OWLObjectUnionOf]: - """Given a node corresponding a concepts that comprises union operation. - 1) Obtain two concepts A, B - 2) Refine A and union refiements with B. + """Refine owl:unionOf. + + Given a node corresponding a concepts that comprises union operation: + 1) Obtain two concepts A, B, + 2) Refine A and union refinements with B, 3) Repeat (2) for B. Args: - current_domain: - node: - max_length: + ce (OWLObjectUnionOf): owl:unionOf - class expression. + current_domain (OWLClassExpression): Domain. + max_length (int): Refine up to this concept length. Returns: - ? + Iterable of refined concepts. """ assert isinstance(ce, OWLObjectUnionOf) @@ -553,6 +606,15 @@ def refine_object_union_of(self, ce: OWLObjectUnionOf, max_length: int, def refine_object_intersection_of(self, ce: OWLObjectIntersectionOf, max_length: int, current_domain: Optional[OWLClassExpression]) \ -> Iterable[OWLObjectIntersectionOf]: + """Refine owl:intersectionOf. + + Args: + ce (OWLObjectIntersectionOf): owl:intersectionOf - class expression. + current_domain (int): Domain. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectIntersectionOf) # TODO: Add sanity check method for intersections as in DL-Learner? @@ -571,8 +633,15 @@ def refine_object_intersection_of(self, ce: OWLObjectIntersectionOf, max_length: yield intersection def refine_data_some_values_from(self, ce: OWLDataSomeValuesFrom) -> Iterable[OWLDataSomeValuesFrom]: - assert isinstance(ce, OWLDataSomeValuesFrom) + """Refine owl:someValuesFrom for data properties. + Args: + ce (OWLDataSomeValuesFrom): owl:someValuesFrom - class expression. + + Returns: + Iterable of refined concepts. + """ + assert isinstance(ce, OWLDataSomeValuesFrom) datarange = ce.get_filler() if isinstance(datarange, OWLDatatypeRestriction) and ce.get_property() in self.dp_splits: splits = self.dp_splits[ce.get_property()] @@ -582,13 +651,21 @@ def refine_data_some_values_from(self, ce: OWLDataSomeValuesFrom) -> Iterable[OW idx = splits.index(val) if facet_res.get_facet() == OWLFacet.MIN_INCLUSIVE and (next_idx := idx + 1) < len(splits): - yield self.generator.data_existential_restriction(OWLDatatypeMinInclusiveRestriction(splits[next_idx]), - ce.get_property()) + yield self.generator.data_existential_restriction( + OWLDatatypeMinInclusiveRestriction(splits[next_idx]), ce.get_property()) elif facet_res.get_facet() == OWLFacet.MAX_INCLUSIVE and (next_idx := idx - 1) >= 0: - yield self.generator.data_existential_restriction(OWLDatatypeMaxInclusiveRestriction(splits[next_idx]), - ce.get_property()) + yield self.generator.data_existential_restriction( + OWLDatatypeMaxInclusiveRestriction(splits[next_idx]), ce.get_property()) def refine_data_has_value(self, ce: OWLDataHasValue) -> Iterable[OWLDataHasValue]: + """ Refine owl:hasValue. + + Args: + ce (OWLDataHasValue): owl:hasValue - class expression. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLDataHasValue) for more_special_dp in self.kb.data_property_hierarchy().more_special_roles(ce.get_property()): @@ -596,15 +673,15 @@ def refine_data_has_value(self, ce: OWLDataHasValue) -> Iterable[OWLDataHasValue def refine(self, ce: OWLClassExpression, max_length: int, current_domain: Optional[OWLClassExpression] = None) \ -> Iterable[OWLClassExpression]: - """Refine a given concept + """Refine a given concept. Args: - ce: concept to refine - max_length: refine up to this concept length - current_domain: + ce: Concept to refine. + max_length: Refine up to this concept length. + current_domain: Domain. Returns: - iterable of refined concepts + Iterable of refined concepts. """ assert isinstance(ce, OWLClassExpression) if isinstance(ce, OWLClass): @@ -632,7 +709,7 @@ def refine(self, ce: OWLClassExpression, max_length: int, current_domain: Option class ExpressRefinement(ModifiedCELOERefinement): - """ A top down refinement operator refinement operator in ALCHIQ(D).""" + """ A top-down refinement operator in ALCHIQ(D).""" __slots__ = 'expressivity', 'downsample', 'sample_fillers_count', 'generator' @@ -669,6 +746,13 @@ def __init__(self, knowledge_base, self._setup() def refine_atomic_concept(self, ce: OWLClass) -> Iterable[OWLClassExpression]: + """Refine atomic concept. + Args: + ce: Atomic concept to refine. + + Returns: + Iterable of refined concepts. + """ if ce.is_owl_nothing(): yield OWLNothing else: @@ -707,7 +791,8 @@ def refine_atomic_concept(self, ce: OWLClass) -> Iterable[OWLClassExpression]: bool_res = [] for bool_dp in self.kb.most_general_boolean_data_properties(domain=ce): bool_res.append(self.generator.data_has_value_restriction(value=OWLLiteral(True), property=bool_dp)) - bool_res.append(self.generator.data_has_value_restriction(value=OWLLiteral(False), property=bool_dp)) + bool_res.append(self.generator.data_has_value_restriction(value=OWLLiteral(False), + property=bool_dp)) iter_container_restrict.append(set(bool_res)) if self.use_card_restrictions and (self.max_child_length >= self.len(ce) + 3): @@ -715,7 +800,8 @@ def refine_atomic_concept(self, ce: OWLClass) -> Iterable[OWLClassExpression]: for prop in self.kb.most_general_object_properties(domain=ce): max_ = self.max_nr_fillers[prop] if max_ > 1: - card_res.append(self.generator.max_cardinality_restriction(self.generator.thing, prop, max_ - 1)) + card_res.append(self.generator.max_cardinality_restriction(self.generator.thing, + prop, max_ - 1)) iter_container_restrict.append(set(card_res)) iter_container_restrict = list(set(chain.from_iterable(iter_container_restrict))) @@ -756,6 +842,14 @@ def refine_atomic_concept(self, ce: OWLClass) -> Iterable[OWLClassExpression]: yield ce def refine_complement_of(self, ce: OWLObjectComplementOf) -> Iterable[OWLClassExpression]: + """ Refine owl:complementOf. + + Args: + ce (OWLObjectComplementOf): owl:complementOf - class expression. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectComplementOf) any_refinement = False parents = self.kb.get_direct_parents(self.generator.negation(ce)) @@ -767,6 +861,14 @@ def refine_complement_of(self, ce: OWLObjectComplementOf) -> Iterable[OWLClassEx yield ce def refine_object_some_values_from(self, ce: OWLObjectSomeValuesFrom) -> Iterable[OWLClassExpression]: + """ Refine owl:someValuesFrom. + + Args: + ce (OWLObjectSomeValuesFrom): owl:someValuesFrom class expression. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectSomeValuesFrom) assert isinstance(ce.get_filler(), OWLClassExpression) any_refinement = False @@ -786,13 +888,22 @@ def refine_object_some_values_from(self, ce: OWLObjectSomeValuesFrom) -> Iterabl yield self.generator.existential_restriction(ce.get_filler(), more_special_op) any_refinement = True - if self.use_card_restrictions and self.len(ce) <= self.max_child_length and self.max_nr_fillers[ce.get_property()] > 1: + if self.use_card_restrictions and self.len(ce) <= self.max_child_length and \ + self.max_nr_fillers[ce.get_property()] > 1: yield self.generator.min_cardinality_restriction(ce.get_filler(), ce.get_property(), 2) any_refinement = True if not any_refinement: yield ce def refine_object_all_values_from(self, ce: OWLObjectAllValuesFrom) -> Iterable[OWLClassExpression]: + """Refine owl:allValuesFrom. + + Args: + ce (OWLObjectAllValuesFrom): owl:allValuesFrom - class expression. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectAllValuesFrom) assert isinstance(ce.get_filler(), OWLClassExpression) any_refinement = False @@ -813,6 +924,14 @@ def refine_object_all_values_from(self, ce: OWLObjectAllValuesFrom) -> Iterable[ def refine_object_min_card_restriction(self, ce: OWLObjectMinCardinality) \ -> Iterable[OWLObjectMinCardinality]: + """Refine owl:allValuesFrom. + + Args: + ce (OWLObjectAllValuesFrom): owl:allValuesFrom - class expression. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectMinCardinality) assert ce.get_cardinality() >= 0 @@ -821,10 +940,19 @@ def refine_object_min_card_restriction(self, ce: OWLObjectMinCardinality) \ yield self.generator.min_cardinality_restriction(ref, ce.get_property(), ce.get_cardinality()) if self.use_card_restrictions and ce.get_cardinality() < self.max_nr_fillers[ce.get_property()]: - yield self.generator.min_cardinality_restriction(ce.get_filler(), ce.get_property(), ce.get_cardinality() + 1) + yield self.generator.min_cardinality_restriction(ce.get_filler(), ce.get_property(), + ce.get_cardinality() + 1) def refine_object_max_card_restriction(self, ce: OWLObjectMaxCardinality) \ -> Iterable[OWLObjectMaxCardinality]: + """Refine owl:maxCardinality. + + Args: + ce (OWLObjectMaxCardinality): owl:maxCardinality - class expression. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectMaxCardinality) assert ce.get_cardinality() >= 0 @@ -833,9 +961,18 @@ def refine_object_max_card_restriction(self, ce: OWLObjectMaxCardinality) \ yield self.generator.max_cardinality_restriction(ref, ce.get_property(), ce.get_cardinality()) if ce.get_cardinality() > 1: - yield self.generator.max_cardinality_restriction(ce.get_filler(), ce.get_property(), ce.get_cardinality() - 1) + yield self.generator.max_cardinality_restriction(ce.get_filler(), ce.get_property(), + ce.get_cardinality() - 1) def refine_object_union_of(self, ce: OWLObjectUnionOf) -> Iterable[OWLClassExpression]: + """Refine owl:unionOf. + + Args: + ce (OWLObjectUnionOf): owl:unionOf - class expression. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectUnionOf) any_refinement = False for op in ce.operands(): @@ -854,6 +991,14 @@ def refine_object_union_of(self, ce: OWLObjectUnionOf) -> Iterable[OWLClassExpre yield ce def refine_object_intersection_of(self, ce: OWLObjectIntersectionOf) -> Iterable[OWLClassExpression]: + """Refine owl:intersectionOf. + + Args: + ce (OWLObjectIntersectionOf): owl:intersectionOf - class expression. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLObjectIntersectionOf) any_refinement = False operands = list(ce.operands()) @@ -868,6 +1013,14 @@ def refine_object_intersection_of(self, ce: OWLObjectIntersectionOf) -> Iterable yield ce def refine_data_some_values_from(self, ce: OWLDataSomeValuesFrom) -> Iterable[OWLDataSomeValuesFrom]: + """Refine owl:someValuesFrom for data properties. + + Args: + ce (OWLDataSomeValuesFrom): owl:someValuesFrom - class expression. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLDataSomeValuesFrom) any_refinement = False datarange = ce.get_filler() @@ -879,17 +1032,25 @@ def refine_data_some_values_from(self, ce: OWLDataSomeValuesFrom) -> Iterable[OW idx = splits.index(val) if facet_res.get_facet() == OWLFacet.MIN_INCLUSIVE and (next_idx := idx + 1) < len(splits): - yield self.generator.data_existential_restriction(OWLDatatypeMinInclusiveRestriction(splits[next_idx]), - ce.get_property()) + yield self.generator.data_existential_restriction( + OWLDatatypeMinInclusiveRestriction(splits[next_idx]), ce.get_property()) any_refinement = True elif facet_res.get_facet() == OWLFacet.MAX_INCLUSIVE and (next_idx := idx - 1) >= 0: - yield self.generator.data_existential_restriction(OWLDatatypeMaxInclusiveRestriction(splits[next_idx]), - ce.get_property()) + yield self.generator.data_existential_restriction( + OWLDatatypeMaxInclusiveRestriction(splits[next_idx]), ce.get_property()) any_refinement = True if not any_refinement: yield ce def refine_data_has_value(self, ce: OWLDataHasValue) -> Iterable[OWLDataHasValue]: + """ Refine owl:hasValue. + + Args: + ce (OWLDataHasValue): owl:hasValue - class expression. + + Returns: + Iterable of refined concepts. + """ assert isinstance(ce, OWLDataHasValue) any_refinement = False for more_special_dp in self.kb.data_property_hierarchy().more_special_roles(ce.get_property()): @@ -900,13 +1061,13 @@ def refine_data_has_value(self, ce: OWLDataHasValue) -> Iterable[OWLDataHasValue yield ce def refine(self, ce, **kwargs) -> Iterable[OWLClassExpression]: - """Refine a given concept + """Refine a given concept. Args: - ce: concept to refine + ce: Concept to refine Returns: - iterable of refined concepts + Iterable of refined concepts. """ # we ignore additional arguments like "max_length" or "current_domain" that might be supplied by the learning # algorithm by using **kwargs diff --git a/ontolearn/search.py b/ontolearn/search.py index 28964fb8..431df902 100644 --- a/ontolearn/search.py +++ b/ontolearn/search.py @@ -1,3 +1,4 @@ +"""Node representation.""" import weakref from _weakref import ReferenceType from abc import abstractmethod, ABCMeta @@ -172,6 +173,8 @@ def __str__(self): class Node(_NodeConcept, _NodeLen, _NodeIndividualsCount, AbstractNode): + """ Simple node. + """ __slots__ = '_concept', '_len', '_individuals_count' def __init__(self, concept: OWLClassExpression, length: int): @@ -190,6 +193,7 @@ def __str__(self): class OENode(_NodeConcept, _NodeLen, _NodeIndividualsCount, _NodeQuality, _NodeHeuristic, _NodeParentRef['OENode'], AbstractNode, AbstractConceptNode, AbstractOEHeuristicNode): + """OENode search tree node.""" __slots__ = '_concept', '_len', '_individuals_count', '_quality', '_heuristic', \ '_parent_ref', '_horizontal_expansion', \ '_refinement_count', '__weakref__' @@ -242,6 +246,9 @@ def __str__(self): class EvoLearnerNode(_NodeConcept, _NodeLen, _NodeIndividualsCount, _NodeQuality, AbstractNode, AbstractConceptNode): + """ + EvoLearner search tree node. + """ __slots__ = '_concept', '_len', '_individuals_count', '_quality', '_tree_length', '_tree_depth' _tree_length: int @@ -284,6 +291,7 @@ def __str__(self): class RL_State(_NodeConcept, _NodeQuality, _NodeHeuristic, AbstractNode, _NodeParentRef['RL_State']): renderer: ClassVar[OWLObjectRenderer] = DLSyntaxObjectRenderer() + """RL_State node.""" __slots__ = '_concept', '_quality', '_heuristic', \ 'embeddings', 'individuals', \ 'instances_bitset', 'length', 'instances', 'parent_node', 'is_root', '_parent_ref', '__weakref__' @@ -356,6 +364,7 @@ def individuals_count(self) -> Optional[int]: class LBLNode(_NodeIndividuals, OENode): + """ LBL search tree node.""" __slots__ = '_children', '_individuals' def __init__(self, concept: OWLClassExpression, length: int, individuals, parent_node: Optional['LBLNode'] = None, @@ -438,6 +447,7 @@ def __eq__(self: _N, other: _N): @total_ordering class QualityOrderedNode: + """QualityOrderedNode search tree node.""" __slots__ = 'node' node: Final[OENode] @@ -632,6 +642,7 @@ def print_partial_tree_recursive(node: LBLNode, depth: int = 0): class TreeNode(Generic[_N]): + """ Simple search tree node.""" __slots__ = 'children', 'node' node: Final[_N] diff --git a/ontolearn/sparqlkb.py b/ontolearn/sparqlkb.py index d6dc1909..757898c1 100644 --- a/ontolearn/sparqlkb.py +++ b/ontolearn/sparqlkb.py @@ -1,3 +1,4 @@ +"""SPARQL representations.""" import logging from functools import singledispatchmethod from typing import Optional, Iterable, FrozenSet @@ -12,9 +13,9 @@ from ontolearn.learning_problem import PosNegLPStandard from ontolearn.utils import oplogging from ontolearn.owlapy.ext import OWLReasonerEx -from ontolearn.owlapy.model import OWLClassAxiom, OWLClassExpression, OWLEntity, OWLOntology, OWLClass, OWLNamedIndividual, \ +from ontolearn.owlapy.model import OWLClassAxiom, OWLClassExpression, OWLEntity, OWLOntology, OWLClass, \ OWLObjectPropertyExpression, OWLDataProperty, OWLObjectProperty, OWLOntologyID, _M, OWLDataPropertyRangeAxiom, \ - IRI, OWLLiteral, OWLDatatype, OWLDataPropertyDomainAxiom, OWLObjectPropertyDomainAxiom, \ + IRI, OWLLiteral, OWLDatatype, OWLDataPropertyDomainAxiom, OWLObjectPropertyDomainAxiom, OWLNamedIndividual, \ OWLObjectPropertyRangeAxiom from ontolearn.owlapy.owl2sparql.converter import Owl2SparqlConverter from ontolearn.owlapy.owlready2 import OWLOntologyManager_Owlready2, OWLReasoner_Owlready2 diff --git a/ontolearn/tentris.py b/ontolearn/tentris.py index 0f5d22ec..67afda9f 100644 --- a/ontolearn/tentris.py +++ b/ontolearn/tentris.py @@ -1,3 +1,4 @@ +"""Tentris representations.""" import logging from functools import singledispatchmethod from types import MappingProxyType diff --git a/ontolearn/utils/__init__.py b/ontolearn/utils/__init__.py index 8abc9455..083acfc1 100644 --- a/ontolearn/utils/__init__.py +++ b/ontolearn/utils/__init__.py @@ -1,3 +1,4 @@ +"""Ontolearn utils.""" import datetime import os import pickle diff --git a/ontolearn/utils/log_config.py b/ontolearn/utils/log_config.py index 2be9451a..b63a58e5 100644 --- a/ontolearn/utils/log_config.py +++ b/ontolearn/utils/log_config.py @@ -1,3 +1,4 @@ +"""Logger configuration.""" import os import sys from datetime import datetime @@ -30,6 +31,11 @@ def _log_file(fn): def setup_logging(config_file="ontolearn/logging.conf"): + """Setup logging. + + Args: + config_file (str): Filepath for logs. + """ logging.x = SimpleNamespace(log_file=_log_file) logging.TRACE = oplogging.TRACE diff --git a/ontolearn/utils/oplogging.py b/ontolearn/utils/oplogging.py index 127487b9..e3ef9ee4 100644 --- a/ontolearn/utils/oplogging.py +++ b/ontolearn/utils/oplogging.py @@ -1,3 +1,4 @@ +"""Logging shortcuts.""" import logging CRITICAL = logging.CRITICAL diff --git a/ontolearn/value_splitter.py b/ontolearn/value_splitter.py index ffaac196..046a70ba 100644 --- a/ontolearn/value_splitter.py +++ b/ontolearn/value_splitter.py @@ -1,3 +1,4 @@ +"""Value splitters.""" from abc import ABCMeta, abstractmethod from copy import deepcopy from dataclasses import dataclass diff --git a/tests/test_core_utils_length.py b/tests/test_core_utils_length.py index ebe8f60c..bec1432f 100644 --- a/tests/test_core_utils_length.py +++ b/tests/test_core_utils_length.py @@ -3,9 +3,9 @@ from ontolearn.core.owl.utils import OWLClassExpressionLengthMetric from ontolearn.utils import setup_logging from ontolearn.owlapy.model.providers import OWLDatatypeMinMaxInclusiveRestriction -from ontolearn.owlapy.model import OWLDataUnionOf, OWLLiteral, OWLObjectProperty, OWLObjectUnionOf, OWLObjectSomeValuesFrom, \ +from ontolearn.owlapy.model import OWLDataUnionOf, OWLLiteral, OWLObjectProperty, OWLObjectUnionOf, \ OWLObjectComplementOf, OWLObjectIntersectionOf, OWLThing, OWLNamedIndividual, OWLObjectOneOf, OWLObjectHasValue, \ - OWLObjectMinCardinality, IRI, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, \ + OWLObjectMinCardinality, IRI, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, OWLObjectSomeValuesFrom, \ OWLDataAllValuesFrom, OWLDataComplementOf, OWLDataExactCardinality, OWLDataHasValue, OWLDataIntersectionOf, \ OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataOneOf, OWLDataProperty, OWLDataSomeValuesFrom diff --git a/tests/test_owlapy_fastinstancechecker.py b/tests/test_owlapy_fastinstancechecker.py index 334e1ff3..c50f9df2 100644 --- a/tests/test_owlapy_fastinstancechecker.py +++ b/tests/test_owlapy_fastinstancechecker.py @@ -13,8 +13,9 @@ OWLObjectIntersectionOf, OWLSubDataPropertyOfAxiom, OWLSubObjectPropertyOfAxiom, OWLInverseObjectPropertiesAxiom, \ DurationOWLDatatype -from ontolearn.owlapy.model.providers import OWLDatatypeMinExclusiveRestriction, OWLDatatypeMinMaxInclusiveRestriction, \ - OWLDatatypeMinMaxExclusiveRestriction, OWLDatatypeMaxExclusiveRestriction, OWLDatatypeMaxInclusiveRestriction +from ontolearn.owlapy.model.providers import OWLDatatypeMinExclusiveRestriction, \ + OWLDatatypeMinMaxInclusiveRestriction, OWLDatatypeMinMaxExclusiveRestriction, OWLDatatypeMaxExclusiveRestriction, \ + OWLDatatypeMaxInclusiveRestriction from ontolearn.owlapy.owlready2 import OWLOntologyManager_Owlready2, OWLReasoner_Owlready2 diff --git a/tests/test_owlapy_owl2sparql_converter.py b/tests/test_owlapy_owl2sparql_converter.py index e606dade..0d9d24cc 100644 --- a/tests/test_owlapy_owl2sparql_converter.py +++ b/tests/test_owlapy_owl2sparql_converter.py @@ -307,12 +307,13 @@ def test_ExistsForAllDeMorgan(self): actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False, values=None, named_individuals=True) ce_str_neg = "¬∃hasChild.¬Male" - ce_parsed_neg = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str_neg) - actual_query_neg = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed_neg, count=False, - values=None, named_individuals=True) + ce_parsed_neg = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression( + expression_str=ce_str_neg) + # actual_query_neg = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed_neg, + # count=False, values=None, named_individuals=True) sparql_results = family_rdf_graph.query(actual_query) - sparql_results_neg = family_rdf_graph.query(actual_query_neg) + # sparql_results_neg = family_rdf_graph.query(actual_query_neg) reasoner_results = set(family_kb_reasoner.instances(ce_parsed)) reasoner_results_neg = set(family_kb_reasoner.instances(ce_parsed_neg)) @@ -346,9 +347,10 @@ def test_LengthyConcepts(self): ] for ce_str in concepts: - ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str) + ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression( + expression_str=ce_str) actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False, - values=None, named_individuals=True) + values=None, named_individuals=True) sparql_results_actual = family_rdf_graph.query(actual_query) reasoner_results = set(family_kb_reasoner.instances(ce_parsed)) @@ -356,7 +358,6 @@ def test_LengthyConcepts(self): self.assertEqual(len(sparql_results_actual), len(reasoner_results), ce_str) self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results), ce_str) - def test_QualifiedCardinalityRestriction(self): # rdf graph - using rdflib family_rdf_graph = Graph() @@ -374,9 +375,10 @@ def test_QualifiedCardinalityRestriction(self): ] for ce_str in concepts: - ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str) + ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression( + expression_str=ce_str) actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False, - values=None, named_individuals=True) + values=None, named_individuals=True) sparql_results_actual = family_rdf_graph.query(actual_query) reasoner_results = set(family_kb_reasoner.instances(ce_parsed)) @@ -386,7 +388,8 @@ def test_QualifiedCardinalityRestriction(self): # need to further investigate the case for 0 # ce_str = "≥ 0 hasChild.Male" - # ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str) + # ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str= + # ce_str) # actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False, # values=None, named_individuals=True) # diff --git a/tests/test_owlapy_owlready2.py b/tests/test_owlapy_owlready2.py index 6ffa9a32..cb117b60 100644 --- a/tests/test_owlapy_owlready2.py +++ b/tests/test_owlapy_owlready2.py @@ -18,7 +18,8 @@ OWLDifferentIndividualsAxiom, OWLDisjointClassesAxiom, OWLDisjointDataPropertiesAxiom, OWLObjectUnionOf, \ OWLDisjointObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom, OWLEquivalentObjectPropertiesAxiom, \ OWLDataPropertyAssertionAxiom, OWLObjectProperty, OWLDataPropertyDomainAxiom, OWLDataPropertyRangeAxiom, \ - OWLObjectPropertyAssertionAxiom, OWLObjectPropertyDomainAxiom, OWLInverseObjectPropertiesAxiom, OWLSubClassOfAxiom + OWLObjectPropertyAssertionAxiom, OWLObjectPropertyDomainAxiom, OWLInverseObjectPropertiesAxiom, OWLSubClassOfAxiom, \ + OWLDeclarationAxiom from ontolearn.owlapy.owlready2 import OWLOntologyManager_Owlready2, OWLReasoner_Owlready2 from ontolearn.owlapy.owlready2.complex_ce_instances import OWLReasoner_Owlready2_ComplexCEInstances @@ -794,7 +795,7 @@ def test_mapping_rev_data_properties(self): self.assertEqual(owl_ce, from_owlready.map_concept(ce)) -class Owlapy_Owlready2_TempClasses_Test(unittest.TestCase): +class Owlapy_Owlready2_ComplexCEInstances_Test(unittest.TestCase): # noinspection DuplicatedCode def test_instances(self): ns = "http://example.com/father#" @@ -823,6 +824,34 @@ def test_instances(self): target_inst = frozenset({OWLNamedIndividual(IRI(ns, 'anna'))}) self.assertEqual(inst, target_inst) + def test_isolated_ontology(self): + + ns = "http://example.com/father#" + mgr = OWLOntologyManager_Owlready2() + onto = mgr.load_ontology(IRI.create("file://KGs/father.owl")) + + reasoner1 = OWLReasoner_Owlready2(onto) + ccei_reasoner = OWLReasoner_Owlready2_ComplexCEInstances(onto, isolate=True) + + new_individual = OWLNamedIndividual(IRI(ns, 'bob')) + male_ce = OWLClass(IRI(ns, "male")) + axiom1 = OWLDeclarationAxiom(new_individual) + axiom2 = OWLClassAssertionAxiom(new_individual, male_ce) + mgr.add_axiom(onto, axiom1) + mgr.add_axiom(onto, axiom2) + + self.assertIn(new_individual, reasoner1.instances(male_ce)) + self.assertNotIn(new_individual, ccei_reasoner.instances(male_ce)) + + ccei_reasoner.update_isolated_ontology(axioms_to_add=[axiom1, axiom2]) + + self.assertIn(new_individual, ccei_reasoner.instances(male_ce)) + + ccei_reasoner.update_isolated_ontology(axioms_to_remove=[axiom2, axiom1]) + + self.assertIn(new_individual, reasoner1.instances(male_ce)) + self.assertNotIn(new_individual, ccei_reasoner.instances(male_ce)) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_owlapy_parser.py b/tests/test_owlapy_parser.py index ca729e91..f3e5a8c5 100644 --- a/tests/test_owlapy_parser.py +++ b/tests/test_owlapy_parser.py @@ -2,16 +2,16 @@ from datetime import date, datetime, timedelta, timezone from pandas import Timedelta -from ontolearn.owlapy.model import OWLObjectInverseOf, OWLObjectMinCardinality, OWLObjectSomeValuesFrom, OWLObjectUnionOf, \ - DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, IRI, OWLDataAllValuesFrom, OWLDataIntersectionOf, \ - OWLDataOneOf, OWLDataProperty, OWLDataSomeValuesFrom, OWLDatatypeRestriction, OWLFacetRestriction, \ +from ontolearn.owlapy.model import OWLObjectInverseOf, OWLObjectMinCardinality, OWLObjectSomeValuesFrom, \ + OWLObjectUnionOf, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, IRI, OWLDataAllValuesFrom, \ + OWLDataIntersectionOf, OWLDataOneOf, OWLDataProperty, OWLDataSomeValuesFrom, OWLDatatypeRestriction, \ OWLLiteral, OWLNamedIndividual, OWLObjectAllValuesFrom, OWLObjectComplementOf, OWLObjectExactCardinality, \ OWLObjectHasSelf, OWLObjectHasValue, OWLObjectIntersectionOf, OWLObjectMaxCardinality, OWLObjectOneOf, \ OWLObjectProperty, OWLDataComplementOf, OWLDataExactCardinality, OWLDataMaxCardinality, OWLDataUnionOf, \ - OWLDataMinCardinality, OWLDataHasValue, OWLThing, OWLNothing + OWLDataMinCardinality, OWLDataHasValue, OWLThing, OWLNothing, OWLFacetRestriction -from ontolearn.owlapy.model.providers import OWLDatatypeMinExclusiveRestriction, OWLDatatypeMinMaxExclusiveRestriction, \ - OWLDatatypeMaxExclusiveRestriction +from ontolearn.owlapy.model.providers import OWLDatatypeMinExclusiveRestriction,\ + OWLDatatypeMinMaxExclusiveRestriction, OWLDatatypeMaxExclusiveRestriction from ontolearn.owlapy.parser import DLSyntaxParser, ManchesterOWLSyntaxParser from ontolearn.owlapy.vocab import OWLFacet diff --git a/tests/test_refinement_operators.py b/tests/test_refinement_operators.py index 8403693d..820cadce 100644 --- a/tests/test_refinement_operators.py +++ b/tests/test_refinement_operators.py @@ -11,9 +11,10 @@ from ontolearn.utils import setup_logging from ontolearn.owlapy.model.providers import OWLDatatypeMaxInclusiveRestriction, OWLDatatypeMinInclusiveRestriction from ontolearn.owlapy.render import DLSyntaxObjectRenderer -from ontolearn.owlapy.model import OWLObjectMinCardinality, OWLObjectProperty, OWLObjectSomeValuesFrom, OWLObjectUnionOf, \ +from ontolearn.owlapy.model import OWLObjectMinCardinality, OWLObjectProperty, OWLObjectSomeValuesFrom, \ OWLClass, IRI, OWLDataHasValue, OWLDataProperty, OWLDataSomeValuesFrom, OWLLiteral, OWLObjectAllValuesFrom, \ - OWLObjectCardinalityRestriction, OWLObjectComplementOf, OWLObjectIntersectionOf, OWLObjectMaxCardinality + OWLObjectCardinalityRestriction, OWLObjectComplementOf, OWLObjectIntersectionOf, OWLObjectMaxCardinality, \ + OWLObjectUnionOf from ontolearn.refinement_operators import ModifiedCELOERefinement, LengthBasedRefinement, \ ExpressRefinement @@ -188,10 +189,12 @@ def test_atomic_use_flags(self): def test_complement_of_refinements(self): rho = ModifiedCELOERefinement(self.kb, use_negation=True) - bond_refs = set(rho.refine(OWLObjectComplementOf(self.bond1), max_length=3, current_domain=self.generator.thing)) + bond_refs = set(rho.refine(OWLObjectComplementOf(self.bond1), max_length=3, + current_domain=self.generator.thing)) self.assertEqual({OWLObjectComplementOf(self.bond)}, bond_refs) - ball3_refs = set(rho.refine(OWLObjectComplementOf(self.ball3), max_length=3, current_domain=self.generator.thing)) + ball3_refs = set(rho.refine(OWLObjectComplementOf(self.ball3), max_length=3, + current_domain=self.generator.thing)) self.assertEqual({OWLObjectComplementOf(self.ring_structure)}, ball3_refs) def test_object_some_values_from_refinements(self): @@ -223,7 +226,8 @@ def test_intersection_refinements(self): def test_union_refinements(self): rho = ModifiedCELOERefinement(self.kb) true_refs = set(map(OWLObjectUnionOf, zip(self.all_bond_classes, repeat(self.ball3)))) - refs = set(rho.refine(OWLObjectUnionOf([self.bond, self.ball3]), max_length=3, current_domain=self.generator.thing)) + refs = set(rho.refine(OWLObjectUnionOf([self.bond, self.ball3]), max_length=3, + current_domain=self.generator.thing)) self.assertEqual(refs, true_refs) def test_data_some_values_from_refinements(self):