diff --git a/docs/examples/mitochondrion-full.owl b/docs/examples/mitochondrion-full.owl
index 5acf4e0ff..2f940dbfb 100644
--- a/docs/examples/mitochondrion-full.owl
+++ b/docs/examples/mitochondrion-full.owl
@@ -29,9 +29,15 @@
-
+
-
+
+
+
+
+
+
+
@@ -137,7 +143,6 @@
A location, relative to cellular compartments and structures, occupied by a macromolecular machine when it carries out a molecular function. There are two ways in which the gene ontology describes locations of gene products: (1) relative to cellular structures (e.g., cytoplasmic side of plasma membrane) or compartments (e.g., mitochondrion), and (2) the stable macromolecular complexes of which they are parts (e.g., the ribosome).
GO:0008372
- NIF_Subcellular:sao-1337158144
NIF_Subcellular:sao1337158144
cell or subcellular entity
cellular component
@@ -160,7 +165,7 @@
A location, relative to cellular compartments and structures, occupied by a macromolecular machine when it carries out a molecular function. There are two ways in which the gene ontology describes locations of gene products: (1) relative to cellular structures (e.g., cytoplasmic side of plasma membrane) or compartments (e.g., mitochondrion), and (2) the stable macromolecular complexes of which they are parts (e.g., the ribosome).
GOC:pdt
- NIF_Subcellular:sao-1337158144
+ NIF_Subcellular:sao1337158144
@@ -174,7 +179,7 @@
-
+
The living contents of a cell; the matter contained within (but not including) the plasma membrane, usually taken to exclude large vacuoles and masses of secretory or ingested material. In eukaryotes it includes the nucleus and cytoplasm.
Wikipedia:Intracellular
internal to cell
@@ -211,34 +216,16 @@
-
-
-
-
- The basic structural and functional unit of all organisms. Includes the plasma membrane and any external encapsulating structures such as the cell wall and cell envelope.
- cell and encapsulating structures
- NIF_Subcellular:sao1813327414
- Wikipedia:Cell_(biology)
- cellular_component
- GO:0005623
-
-
-
- cell
-
-
-
-
- The basic structural and functional unit of all organisms. Includes the plasma membrane and any external encapsulating structures such as the cell wall and cell envelope.
- GOC:go_curators
-
-
-
-
-
+
+
+
+
+
+
+
All of the contents of a cell excluding the plasma membrane and nucleus, but including other subcellular structures.
MIPS_funcat:70.03
Wikipedia:Cytoplasm
@@ -266,7 +253,12 @@
-
+
+
+
+
+
+
A semiautonomous, self replicating organelle that occurs in varying numbers, shapes, and sizes in the cytoplasm of virtually all eukaryotic cells. It is notably the site of tissue respiration.
MIPS_funcat:70.16
NIF_Subcellular:sao1860313010
@@ -300,7 +292,7 @@
-
+
Organized structure of distinctive morphology and function. Includes the nucleus, mitochondria, plastids, vacuoles, vesicles, ribosomes and the cytoskeleton, and prokaryotic structures such as anammoxosomes and pirellulosomes. Excludes the plasma membrane.
NIF_Subcellular:sao1539965131
Wikipedia:Organelle
@@ -355,7 +347,12 @@
-
+
+
+
+
+
+
Organized structure of distinctive morphology and function, occurring within the cell. Includes the nucleus, mitochondria, plastids, vacuoles, vesicles, ribosomes and the cytoskeleton. Excludes the plasma membrane.
cellular_component
GO:0043229
@@ -392,134 +389,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Any constituent part of an organelle, an organized structure of distinctive morphology and function. Includes constituent parts of the nucleus, mitochondria, plastids, vacuoles, vesicles, ribosomes and the cytoskeleton, but excludes the plasma membrane.
- cellular_component
- GO:0044422
-
- Note that this term is in the subset of terms that should not be used for direct gene product annotation. Instead, select a child term or, if no appropriate child term exists, please request a new term. Direct annotations to this term may be amended during annotation QC.
- organelle part
-
-
-
-
- Any constituent part of an organelle, an organized structure of distinctive morphology and function. Includes constituent parts of the nucleus, mitochondria, plastids, vacuoles, vesicles, ribosomes and the cytoskeleton, but excludes the plasma membrane.
- GOC:jl
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Any constituent part of the living contents of a cell; the matter contained within (but not including) the plasma membrane, usually taken to exclude large vacuoles and masses of secretory or ingested material. In eukaryotes it includes the nucleus and cytoplasm.
- cellular_component
- GO:0044424
-
- Note that this term is in the subset of terms that should not be used for direct gene product annotation. Instead, select a child term or, if no appropriate child term exists, please request a new term. Direct annotations to this term may be amended during annotation QC.
- intracellular part
-
-
-
-
- Any constituent part of the living contents of a cell; the matter contained within (but not including) the plasma membrane, usually taken to exclude large vacuoles and masses of secretory or ingested material. In eukaryotes it includes the nucleus and cytoplasm.
- GOC:jl
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Any constituent part of a mitochondrion, a semiautonomous, self replicating organelle that occurs in varying numbers, shapes, and sizes in the cytoplasm of virtually all eukaryotic cells. It is notably the site of tissue respiration.
- NIF_Subcellular:sao666410040
- mitochondrial subcomponent
- mitochondrion component
- cellular_component
- GO:0044429
-
- Note that this term is in the subset of terms that should not be used for direct gene product annotation. Instead, select a child term or, if no appropriate child term exists, please request a new term. Direct annotations to this term may be amended during annotation QC.
- mitochondrial part
-
-
-
-
- Any constituent part of a mitochondrion, a semiautonomous, self replicating organelle that occurs in varying numbers, shapes, and sizes in the cytoplasm of virtually all eukaryotic cells. It is notably the site of tissue respiration.
- GOC:jl
-
-
-
-
- mitochondrial subcomponent
- NIF_Subcellular:sao666410040
-
-
-
-
-
+
-
+
-
+
@@ -527,136 +403,43 @@
-
+
- Any constituent part of the cytoplasm, all of the contents of a cell excluding the plasma membrane and nucleus, but including other subcellular structures.
- cytoplasm component
- cellular_component
- GO:0044444
-
- Note that this term is in the subset of terms that should not be used for direct gene product annotation. Instead, select a child term or, if no appropriate child term exists, please request a new term. Direct annotations to this term may be amended during annotation QC.
- cytoplasmic part
-
-
-
-
- Any constituent part of the cytoplasm, all of the contents of a cell excluding the plasma membrane and nucleus, but including other subcellular structures.
- GOC:jl
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- A constituent part of an intracellular organelle, an organized structure of distinctive morphology and function, occurring within the cell. Includes constituent parts of the nucleus, mitochondria, plastids, vacuoles, vesicles, ribosomes and the cytoskeleton but excludes the plasma membrane.
+ Any (proper) part of the cytoplasm of a single cell of sufficient size to still be considered cytoplasm"
cellular_component
- GO:0044446
-
- Note that this term is in the subset of terms that should not be used for direct gene product annotation. Instead, select a child term or, if no appropriate child term exists, please request a new term. Direct annotations to this term may be amended during annotation QC.
- intracellular organelle part
+ GO:0099568
+ cytoplasmic region
-
+
- A constituent part of an intracellular organelle, an organized structure of distinctive morphology and function, occurring within the cell. Includes constituent parts of the nucleus, mitochondria, plastids, vacuoles, vesicles, ribosomes and the cytoskeleton but excludes the plasma membrane.
- GOC:jl
+ Any (proper) part of the cytoplasm of a single cell of sufficient size to still be considered cytoplasm"
+ GOC:dos
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
- Any constituent part of a cell, the basic structural and functional unit of all organisms.
- NIF_Subcellular:sao628508602
- cellular subcomponent
- cellular_component
- protoplast
- GO:0044464
-
-
- Note that this term is in the subset of terms that should not be used for direct gene product annotation. Instead, select a child term or, if no appropriate child term exists, please request a new term. Direct annotations to this term may be amended during annotation QC.
- cell part
-
-
-
-
- Any constituent part of a cell, the basic structural and functional unit of all organisms.
- GOC:jl
-
-
-
-
- cellular subcomponent
- NIF_Subcellular:sao628508602
-
-
-
-
- protoplast
- GOC:mah
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Any (proper) part of the cytoplasm of a single cell of sufficient size to still be considered cytoplasm"
+ A part of a cellular organism that is either an immaterial entity or a material entity with granularity above the level of a protein complex but below that of an anatomical system. Or, a substance produced by a cellular organism with granularity above the level of a protein complex.
+ kmv
+ 2019-08-12T18:01:37Z
cellular_component
- GO:0099568
- cytoplasmic region
+ GO:0110165
+ cellular anatomical entity
-
+
- Any (proper) part of the cytoplasm of a single cell of sufficient size to still be considered cytoplasm"
- GOC:dos
+ A part of a cellular organism that is either an immaterial entity or a material entity with granularity above the level of a protein complex but below that of an anatomical system. Or, a substance produced by a cellular organism with granularity above the level of a protein complex.
+ GOC:kmv
diff --git a/docs/examples/no-tautologies.owl b/docs/examples/no-tautologies.owl
new file mode 100644
index 000000000..81bd9262e
--- /dev/null
+++ b/docs/examples/no-tautologies.owl
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+
+
+
+
+
+
+
+
+ B
+
+
+
+
+
+
+
+ C
+
+
+
+
+
+
+
diff --git a/docs/examples/tautologies.owl b/docs/examples/tautologies.owl
new file mode 100644
index 000000000..ddd3ff57f
--- /dev/null
+++ b/docs/examples/tautologies.owl
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+
+
+
+
+
+
+
+
+ B
+
+
+
+
+
+
+
+
+ C
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/examples/template-base.owl b/docs/examples/template-base.owl
new file mode 100644
index 000000000..a961903d0
--- /dev/null
+++ b/docs/examples/template-base.owl
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Weight of a mouse or rat in kilograms (kg).
+ Rebecca C Jackson
+ weight in kilograms
+
+
+
+
+ Weight of a mouse or rat in kilograms (kg).
+ Rebecca C Jackson
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ An inbred strain of mouse used in many scientific investigations.
+ James A. Overton
+ B6C3F1
+
+
+
+
+
+ An inbred strain of mouse used in many scientific investigations.
+ James A. Overton
+
+
+
+
+
+
+
+
+ An inbred strain of rat used in many scientific investigations.
+ James A. Overton
+ F 344/N
+
+
+
+
+
+ An inbred strain of rat used in many scientific investigations.
+ James A. Overton
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0.2
+ rat 1234
+
+
+
+
+
+
+
diff --git a/docs/examples/uberon_annotated.owl b/docs/examples/uberon_annotated.owl
index fdc4d13b1..4c6fbd754 100644
--- a/docs/examples/uberon_annotated.owl
+++ b/docs/examples/uberon_annotated.owl
@@ -6,7 +6,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
- xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:oboInOwl="http://www.geneontology.org/formats/oboInOwl#">
@@ -30,66 +29,24 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -102,12 +59,6 @@
-
-
-
-
-
-
@@ -120,30 +71,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- BFO:0000050
- uberon
- part_of
- part_of
- part_of
-
+
@@ -248,288 +175,31 @@
- Anatomical structure which has as its direct parts two or more types of tissue and is continuous with one or more anatomical structures likewise constituted by two or more portions of tissues distinct from those of their complement. Examples: osteon, cortical bone, neck of femur, bronchopulmonary segment, left lobe of liver, anterior right side of heart, interventricular branch of left coronary artery, right atrium, mitral valve, head of pancreas[FMA].
-
-
-
- AAO:0011124
- EFO:0000635
- FMA:82472
- cardinal organ part
- uberon
- regional part of organ
- UBERON:0000064
-
-
-
- organ part
-
-
-
- Anatomical structure which has as its direct parts two or more types of tissue and is continuous with one or more anatomical structures likewise constituted by two or more portions of tissues distinct from those of their complement. Examples: osteon, cortical bone, neck of femur, bronchopulmonary segment, left lobe of liver, anterior right side of heart, interventricular branch of left coronary artery, right atrium, mitral valve, head of pancreas[FMA].
- FMA:82472
-
-
-
-
- regional part of organ
- NIFSTD:birnlex_16
-
-
- Anatomical group that is has as its parts distinct anatomical structures interconnected by anatomical structures at a lower level of granularity[CARO]. A group of organs that work together to perform a certain task [Wikipedia].
- system
-
-
-
-
-
- AAO:0000007
- AEO:0000011
- BILA:0000011
- BSA:0000049
- CALOHA:TS-2088
- CARO:0000011
- EHDAA2:0003011
- EHDAA:392
- EMAPA:16103
- EV:0100000
- FBbt:00004856
- FMA:7149
- HAO:0000011
- MA:0000003
- OpenCyc:Mx4rCWM0QCtDEdyAAADggVbxzQ
- TAO:0001439
- TGMA:0001831
- UMLS:C0460002
- VHOG:0001725
- WBbt:0005746
- WBbt:0005763
- XAO:0003002
- ZFA:0001439
- galen:AnatomicalSystem
- body system
- organ system
- uberon
- UBERON:0000467
-
-
- anatomical system
-
-
-
-
-
- system
- GO:0048731
-
-
-
-
- UMLS:C0460002
- ncithesaurus:Organ_System
-
-
-
-
- body system
- NIFSTD:birnlex_14
-
-
-
-
- Anatomical group that is has as its parts distinct anatomical structures interconnected by anatomical structures at a lower level of granularity[CARO]. A group of organs that work together to perform a certain task [Wikipedia].
-
- CARO:0000011
- CARO:MAH
-
+
-
- The subdivision of the vertebrate body between the thorax and pelvis. The ventral part of the abdomen contains the abdominal cavity and visceral organs. The dorsal part includes the abdominal section of the vertebral column.
- Vertebrate specific. In arthropods 'abdomen' is the most distal section of the body which lies behind the thorax or cephalothorax. If need be we can introduce some grouping class
- abdominal
- celiac
-
-
- BTO:0000020
- CALOHA:TS-0001
- EFO:0000968
- EMAPA:35102
- EV:0100011
- FMA:9577
- GAID:16
- MA:0000029
- MAT:0000298
- MESH:A01.047
- MIAA:0000298
- OpenCyc:Mx4rvVjgyZwpEbGdrcN5Y29ycA
- galen:Abdomen
- abdominopelvic region
- abdominopelvis
- uberon
- adult abdomen
- belly
- celiac region
- UBERON:0000916
-
-
- abdomen
-
-
-
-
- The subdivision of the vertebrate body between the thorax and pelvis. The ventral part of the abdomen contains the abdominal cavity and visceral organs. The dorsal part includes the abdominal section of the vertebral column.
- UBERON:cjm
-
-
-
-
- abdominopelvic region
- FMA:9577
-
-
-
-
- abdominopelvis
- FMA:9577
-
+
-
- Organism subdivision which is the part of the body posterior to the cervical region (or head, when cervical region not present) and anterior to the caudal region. Includes the sacrum when present.
- Organism subdivision that is the part of the body posterior to the head and anterior to the tail.[AAO]
- Organism subdivision which is the part of the body posterior to the head and anterior to the tail.[TAO]
-
-
-
-
- AAO:0010339
- BILA:0000116
- BTO:0001493
- CALOHA:TS-1071
- EFO:0000966
- EMAPA:31857
- FMA:7181
- MA:0000004
- MAT:0000296
- MIAA:0000296
- OpenCyc:Mx4rvVkJjpwpEbGdrcN5Y29ycA
- TAO:0001115
- UMLS:C0460005
- XAO:0000054
- XAO:0003025
- ZFA:0001115
- galen:Trunk
- thoracolumbar region
- torso
- trunk region
- uberon
- Rumpf
- UBERON:0002100
-
-
-
- trunk
-
-
-
-
- Organism subdivision which is the part of the body posterior to the cervical region (or head, when cervical region not present) and anterior to the caudal region. Includes the sacrum when present.
-
- TAO:0001115
- UBERONREF:0000006
-
-
-
-
- Organism subdivision that is the part of the body posterior to the head and anterior to the tail.[AAO]
- 2012-06-20
- AAO:0010339
- AAO
- AAO:BJB
-
-
-
-
- Organism subdivision which is the part of the body posterior to the head and anterior to the tail.[TAO]
- 2012-08-14
- TAO:0001115
- TAO
- ZFIN:curator
-
-
-
-
- UMLS:C0460005
- ncithesaurus:Trunk
-
-
-
-
- trunk region
- XAO:0000054
-
-
-
-
- Rumpf
- BTO:0001493
-
+
-
- The abdominal segment of the torso.
-
-
- EMAPA:35104
- FMA:259211
- MA:0000021
- uberon
- abdomen/pelvis/perineum
- lower body
- lumbar region
- UBERON:0002417
- abdominal segment of trunk
-
-
-
-
- The abdominal segment of the torso.
-
-
-
-
-
- abdomen/pelvis/perineum
- MA:0000021
-
-
-
-
- lower body
- MA:0000021
-
-
-
-
- lumbar region
-
-
+
@@ -537,72 +207,7 @@
- an organ that functions as a secretory or excretory organ
- glandular
- UBERON:MIAA_0000021
-
-
-
-
- AAO:0000212
- AEO:0000096
- BTO:0000522
- EFO:0000797
- EHDAA2:0003096
- EHDAA:2161
- EHDAA:4475
- EHDAA:6522
- EMAPA:18425
- FBbt:00100317
- FMA:86294
- HAO:0000375
- MA:0003038
- MAT:0000021
- MIAA:0000021
- OpenCyc:Mx4rwP3vyJwpEbGdrcN5Y29ycA
- UMLS:C1285092
- WikipediaCategory:Glands
- galen:Gland
- uberon
- Druese
- glandula
- UBERON:0002530
-
-
- gland
-
-
-
-
- an organ that functions as a secretory or excretory organ
- MP:0002163,MGI:csmith
-
-
-
-
- UMLS:C1285092
- ncithesaurus:Gland
-
-
-
-
- Druese
- BTO:0000522
-
-
-
-
- glandula
-
-
-
-
-
-
- glandula
- BTO:0000522
-
@@ -620,27 +225,7 @@
- An organ or element that is in the abdomen. Examples: spleen, intestine, kidney, abdominal mammary gland.
-
- MA:0000522
- abdomen organ
- uberon
- UBERON:0005172
-
- abdomen element
-
-
-
- An organ or element that is in the abdomen. Examples: spleen, intestine, kidney, abdominal mammary gland.
-
-
-
-
-
- abdomen organ
- MA:0000522
-
@@ -658,26 +243,7 @@
- An organ or element that is part of the adbominal segment of the organism. This region can be further subdivided into the abdominal cavity and the pelvic region.
- MA:0000529
- abdominal segment organ
- uberon
- UBERON:0005173
-
- abdominal segment element
-
-
-
- An organ or element that is part of the adbominal segment of the organism. This region can be further subdivided into the abdominal cavity and the pelvic region.
-
-
-
-
-
- abdominal segment organ
- MA:0000529
-
@@ -696,27 +262,7 @@
- An organ or element that part of the trunk region. The trunk region can be further subdividied into thoracic (including chest and thoracic cavity) and abdominal (including abdomen and pelbis) regions.
- MA:0000516
- trunk organ
- uberon
- UBERON:0005177
-
-
- trunk region element
-
-
-
- An organ or element that part of the trunk region. The trunk region can be further subdividied into thoracic (including chest and thoracic cavity) and abdominal (including abdomen and pelbis) regions.
-
-
-
-
-
- trunk organ
- MA:0000516
-
diff --git a/docs/extract.md b/docs/extract.md
index 9bc2e150d..1db05624b 100644
--- a/docs/extract.md
+++ b/docs/extract.md
@@ -136,7 +136,7 @@ By default, `extract` will include imported ontologies. To exclude imported onto
--input imports-nucleus.owl \
--term GO:0005739 \
--imports exclude \
- --output mitochondrion.owl
+ --output results/mitochondrion.owl
This only includes what is asserted in `imports-nucleus.owl`, which imports `nucleus.owl`. `imports-nucleus.owl` only includes the term 'mitochondrion' (`GO:0005739`) and links it to its parent class, 'intracellular membrane-bounded organelle' (`GO:0043231`). `nucleus.owl` contains the full hierarchy down to 'intracellular membrane-bounded organelle'. The output module, `mitochondrion.owl`, only includes the term 'mitochondrion' and this subClassOf statement.
@@ -146,7 +146,7 @@ By contrast, including imports returns the full hierarchy down to 'mitochondrion
--input imports-nucleus.owl \
--term GO:0005739 \
--imports include \
- --output mitochondrion-full.owl
+ --output results/mitochondrion-full.owl
## Extracting Ontology Annotations
diff --git a/docs/filter.md b/docs/filter.md
index 98ba3f4af..01a98bbce 100644
--- a/docs/filter.md
+++ b/docs/filter.md
@@ -2,6 +2,10 @@
The `filter` command allows you to create a new ontology from a source ontology by copying only the selected axioms. The `remove` command is the opposite of `filter`, allowing you to remove selected axioms. `filter` accepts the same options as `remove` and processes them in the same order, with just a few differences. See [`remove`](/remove) for details on configuring the options.
+Including and excluding terms is the opposite of `remove`:
+* If you wish to *exclude* a term or set of terms that would be filtered for otherwise, you can do so with `--exclude-term ` or `--exclude-terms `. These terms will **never** be in the output.
+* If you wish to *include* a term or set of terms that would not be filtered for otherwise, you can do so with `--include-term ` or `--include-terms `. These terms will **always** be in the output.
+
The key difference between `remove` and `filter` comes in the fourth processing step:
4. The final step is to take each axiom of the specified types, and compare it to the target set. The `--signature` option works the same as `remove`, but `--trim` differs. When using `filter --trim true` (the default), if *all* objects for the axiom are in the target set then that axiom is copied to the new ontology. When using `filter --trim false`, if *any* object for the axiom are in the target set, then that axiom is copied.
@@ -71,12 +75,23 @@ Copy a subset of classes based on an annotation property (maintains hierarchy):
--signature true \
--output results/uberon_slim.owl
-Copy a class, all axioms that a class appears in, annotations on all classes used, and the ontology annotations:
+Copy a class, all axioms that a class appears in and annotations on all the classes (only `UBERON:0000062` here) in the filter set:
robot filter --input uberon_module.owl \
--term UBERON:0000062 \
- --select "ontology annotations" \
+ --select annotations \
--trim false \
--signature true \
--output results/uberon_annotated.owl
+Create a "base" subset that only includes internal axioms (alternatively, use `remove --axioms external`):
+
+ robot filter --input template.owl \
+ --base-iri http://example.com/ \
+ --select "annotations" \
+ --axioms internal \
+ --include-term IAO:0000117 \
+ --include-term IAO:0000119 \
+ --preserve-structure false \
+ --output results/template-base.owl
+
diff --git a/docs/remove.md b/docs/remove.md
index 2fab6ce6c..e445ede3f 100644
--- a/docs/remove.md
+++ b/docs/remove.md
@@ -23,6 +23,9 @@ Here is how each step works in more detail:
1. The `--term` and `--term-file` options let you specify the initial target set. You can specify zero or more `--term` options (one term each), and zero or more `--term-file` options (with one term per line). You can specify terms by IRI or CURIE. If no terms are specified, then the initial target set consists of all the objects in the ontology.
+ * If you wish to exclude a term or set of terms that would be removed otherwise, you can do so with `--exclude-term ` or `--exclude-terms `. These terms will **never** be removed.
+ * If you wish to *include* a term or set of terms that would be kept otherwise, you can do so with `--include-term ` or `--include-terms `. These terms will **always** be removed.
+
2. The `--select` option lets you specify "selectors" that broaden or narrow the target set of objects. Some selectors such as `classes` take the target set and return a subset, i.e. all the classes in the target set. Other selectors such as `parents` return a new target set of related objects. The `parents` selector gets the parents of each object in the target set. Note that the `parents` set does not include the original target set, just the parents. Use the `self` selector to return the same target set. You can use multiple selectors together to get their union, so `--select "self parents"` will return the target set (`self`) and all the parents. You can use `--select` multiple times to modify the target set in several stages, so `--select parents --select children` will get the parents and then all their children, effectively returning the target set objects and all their siblings.
3. The `--axioms` option lets you specify which axiom types to consider. By default, all axioms are considered, but this can be restricted to annotation axioms, logical axioms, more specific subtypes, or any combination.
@@ -104,27 +107,48 @@ It is also possible to select terms based on parts of their IRI. You may include
- ``, e.g. ``
+If an IRI uses a literal `*` or a `?` character, these must be escaped (e.g., `http://example.com?[WILDCARD]` would become `http://example.com\?[WILDCARD]`).
+
If you wish to match a more complicated pattern, you may also use a regex pattern here by preceding the pattern with a tilde (`~`):
- `<~IRI-regex>`, e.g. `<~^.+EX_[0-9]{7}$>`
+If you do not want to type the full IRI out, you can also pattern match with `*` and `?` by CURIE for any [loaded prefixes](/global#prefixes). For example, to select everything in both the OBI and IAO namespaces:
+
+- `--select "OBI:* IAO:*"`
+
+For regex pattern matching with CURIEs, simply prefix the CURIE pattern with `~`, as we do for IRIs:
+
+- `--select "~EX:[0-9]{7}$`
+
+For CURIEs, the pattern must always come after the prefix and colon.
+
## Axioms
-The `--axioms` option allows you to specify the type of OWLAxiom to remove. More than one type can be provided and the order is not significant. For each axiom in the ontology (not including its imports closure), if the axiom implements one of the specified axiom types AND *any* of the selected terms are in the axiom's signature, then the axiom is removed from the ontology.
+The `--axioms` option allows you to specify the type of OWLAxiom to remove. More than one type can be provided and these will be processed **in order**. For each axiom in the ontology (not including its imports closure), if the axiom implements one of the specified axiom types AND *any* of the selected terms are in the axiom's signature, then the axiom is removed from the ontology.
+Basic axiom selectors select the axiom(s) based on the OWLAPI AxiomType. We have included some special shortcuts to group related axiom types together.
- `all` (default)
- `logical`
- `annotation`
- `subclass`
- `subproperty`
-- `equivalent` (classes and properties)
-- `disjoint` (classes and properties)
-- `type` (class assertions)
-- `tbox` (classes and class axioms)
-- `abox` (instances and instance-level axioms)
-- `rbox` (object properties, aka relations)
+- `equivalent`: classes and properties
+- `disjoint`: classes and properties
+- `type`: class assertions
+- `tbox`: classes and class axioms
+- `abox`: instances and instance-level axioms
+- `rbox`: object properties, i.e., relations
- [OWLAPI AxiomType](http://owlcs.github.io/owlapi/apidocs_4/org/semanticweb/owlapi/model/AxiomType.html) name (e.g., `ObjectPropertyRange`)
+There are also some special axiom selectors that use additional processing to find certain axioms:
+- `internal`: all entities that are in one of the `--base-iri` namespaces
+- `external`: all entities that are not in one of the `--base-iri` namespaces
+- `tautologies`: all axioms that are *always* true; these would be entailed in an empty ontology. WARNING: this may remove more axioms than desired.
+- `structural-tautologies`: all axioms that match a set of tautological patterns (e.g., `X SubClassOf owl:Thing`, `owl:Nothing SubClassOf X`, `X SubClassOf X`)
+
+The `--base-iri ` is a special option for use with `internal` and `external` axioms. It allows you to specify one or more "base namespaces" (e.g., `--base-iri http://purl.obolibrary.org/obo/OBI_`). You can also use any defined prefix (e.g., `--base-iri OBI`) An axiom is considered internal if the subject is in one of the base namespaces.
+
## Examples
Remove a class ('organ'), all its descendants, and any axioms using these classes:
@@ -162,6 +186,23 @@ robot remove --input obi.owl \
--select "owl:deprecated='true'^^xsd:boolean"
```
+Remove structural tautologies (e.g., `owl:Nothing`):
+
+ robot remove --input tautologies.owl \
+ --axioms structural-tautologies \
+ --output results/no-tautologies.owl
+
+Create a "base" subset by removing external axioms (alternatively, use `filter --axioms internal`):
+
+ robot remove --input template.owl \
+ --base-iri http://example.com \
+ --axioms external \
+ --exclude-term IAO:0000117 \
+ --exclude-term IAO:0000119 \
+ --preserve-structure false \
+ --trim false \
+ --output results/template-base.owl
+
*Filter* for only desired annotation properties (in this case, label and ID). This works by actually *removing* the opposite set of annotation properties (complement annotation-properties) from the ontology:
robot remove --input uberon_module.owl \
diff --git a/robot-command/src/main/java/org/obolibrary/robot/CommandLineHelper.java b/robot-command/src/main/java/org/obolibrary/robot/CommandLineHelper.java
index e2be92c00..df0ba96c0 100644
--- a/robot-command/src/main/java/org/obolibrary/robot/CommandLineHelper.java
+++ b/robot-command/src/main/java/org/obolibrary/robot/CommandLineHelper.java
@@ -10,7 +10,6 @@
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
@@ -38,9 +37,6 @@ public class CommandLineHelper {
/** Namespace for general input error messages. */
private static final String NS = "errors#";
- /** Error message when --axioms is not a valid AxiomType. Expects: input string. */
- private static final String axiomTypeError = NS + "AXIOM TYPE ERROR %s is not a valid axiom type";
-
/** Error message when a boolean value is not "true" or "false". Expects option name. */
private static final String booleanValueError =
NS + "BOOLEAN VALUE ERROR arg for %s must be true or false";
@@ -224,6 +220,64 @@ public static boolean hasFlagOrCommand(CommandLine line, String name) {
return command != null && command.equals(name);
}
+ /**
+ * Given a command line, get the 'axioms' option(s) and make sure all are properly split and
+ * return one axiom selector per list entry.
+ *
+ * @param line the command line to use
+ * @return cleaned list of input axiom type strings
+ */
+ public static List cleanAxiomStrings(CommandLine line) {
+ List axiomTypeStrings = getOptionalValues(line, "axioms");
+
+ if (axiomTypeStrings.isEmpty()) {
+ axiomTypeStrings.add("all");
+ }
+
+ // Split if it's one arg with spaces
+ List axiomTypeFixedStrings = new ArrayList<>();
+ for (String axiom : axiomTypeStrings) {
+ if (axiom.contains(" ")) {
+ axiomTypeFixedStrings.addAll(Arrays.asList(axiom.split(" ")));
+ } else {
+ axiomTypeFixedStrings.add(axiom);
+ }
+ }
+
+ return axiomTypeFixedStrings;
+ }
+
+ /**
+ * Given a command line and an IOHelper, return a list of base namespaces from the '--base-iri'
+ * option.
+ *
+ * @param line the command line to use
+ * @param ioHelper the IOHelper to resolve prefixes
+ * @return list of full base namespaces
+ */
+ public static List getBaseNamespaces(CommandLine line, IOHelper ioHelper) {
+ List bases = new ArrayList<>();
+ if (!line.hasOption("base-iri")) {
+ return bases;
+ }
+
+ Map prefixMap = ioHelper.getPrefixes();
+ for (String base : line.getOptionValues("base-iri")) {
+ if (!base.contains(":")) {
+ String expanded = prefixMap.getOrDefault(base, null);
+ if (expanded != null) {
+ bases.add(expanded);
+ } else {
+ logger.error(String.format("Unknown prefix: '%s'", base));
+ }
+ } else {
+ bases.add(base);
+ }
+ }
+
+ return bases;
+ }
+
/**
* Given a command line, an argument name, the boolean default value, and boolean if the arg is
* optional, return the value of the command-line option 'name'.
@@ -250,74 +304,20 @@ public static boolean getBooleanValue(
/**
* Given a command line, return the value of --axioms as a set of classes that extend OWLAxiom.
*
+ * @deprecated split into methods {@link #cleanAxiomStrings(CommandLine)} and others in {@link
+ * org.obolibrary.robot.RelatedObjectsHelper}
* @param line the command line to use
* @return set of OWLAxiom types
*/
+ @Deprecated
public static Set> getAxiomValues(CommandLine line) {
Set> axiomTypes = new HashSet<>();
- List axiomTypeStrings = getOptionValues(line, "axioms");
- if (axiomTypeStrings.isEmpty()) {
- axiomTypeStrings.add("all");
- }
- // Split if it's one arg with spaces
- List axiomTypeFixedStrings = new ArrayList<>();
- for (String axiom : axiomTypeStrings) {
- if (axiom.contains(" ")) {
- axiomTypeFixedStrings.addAll(Arrays.asList(axiom.split(" ")));
- } else {
- axiomTypeFixedStrings.add(axiom);
- }
- }
+ List axiomTypeStrings = cleanAxiomStrings(line);
// Then get the actual types
- for (String axiom : axiomTypeFixedStrings) {
- if (axiom.equalsIgnoreCase("all")) {
- axiomTypes.add(OWLAxiom.class);
- } else if (axiom.equalsIgnoreCase("logical")) {
- axiomTypes.add(OWLLogicalAxiom.class);
- } else if (axiom.equalsIgnoreCase("annotation")) {
- axiomTypes.add(OWLAnnotationAxiom.class);
- } else if (axiom.equalsIgnoreCase("subclass")) {
- axiomTypes.add(OWLSubClassOfAxiom.class);
- } else if (axiom.equalsIgnoreCase("subproperty")) {
- axiomTypes.add(OWLSubObjectPropertyOfAxiom.class);
- axiomTypes.add(OWLSubDataPropertyOfAxiom.class);
- axiomTypes.add(OWLSubAnnotationPropertyOfAxiom.class);
- } else if (axiom.equalsIgnoreCase("equivalent")) {
- axiomTypes.add(OWLEquivalentClassesAxiom.class);
- axiomTypes.add(OWLEquivalentObjectPropertiesAxiom.class);
- axiomTypes.add(OWLEquivalentDataPropertiesAxiom.class);
- } else if (axiom.equalsIgnoreCase("disjoint")) {
- axiomTypes.add(OWLDisjointClassesAxiom.class);
- axiomTypes.add(OWLDisjointObjectPropertiesAxiom.class);
- axiomTypes.add(OWLDisjointDataPropertiesAxiom.class);
- axiomTypes.add(OWLDisjointUnionAxiom.class);
- } else if (axiom.equalsIgnoreCase("type")) {
- axiomTypes.add(OWLClassAssertionAxiom.class);
- } else if (axiom.equalsIgnoreCase("abox")) {
- axiomTypes.addAll(
- AxiomType.ABoxAxiomTypes.stream()
- .map(AxiomType::getActualClass)
- .collect(Collectors.toSet()));
- } else if (axiom.equalsIgnoreCase("tbox")) {
- axiomTypes.addAll(
- AxiomType.TBoxAxiomTypes.stream()
- .map(AxiomType::getActualClass)
- .collect(Collectors.toSet()));
- } else if (axiom.equalsIgnoreCase("rbox")) {
- axiomTypes.addAll(
- AxiomType.RBoxAxiomTypes.stream()
- .map(AxiomType::getActualClass)
- .collect(Collectors.toSet()));
- } else if (axiom.equalsIgnoreCase("declaration")) {
- axiomTypes.add(OWLDeclarationAxiom.class);
- } else {
- AxiomType> at = AxiomType.getAxiomType(axiom);
- if (at != null) {
- // Attempt to get the axiom type based on AxiomType names
- axiomTypes.add(at.getActualClass());
- } else {
- throw new IllegalArgumentException(String.format(axiomTypeError, axiom));
- }
+ for (String axiom : axiomTypeStrings) {
+ Set> addTypes = RelatedObjectsHelper.getAxiomValues(axiom);
+ if (addTypes != null) {
+ axiomTypes.addAll(addTypes);
}
}
return axiomTypes;
@@ -407,7 +407,7 @@ public static String getRequiredValue(CommandLine line, String name, String mess
/**
* Given a command line, return an initialized IOHelper. The --prefix, --add-prefix, --prefixes,
- * --add-prefixes, --noprefixes and --xml-entities options are handled.
+ * --add-prefixes, --noprefixes, --xml-entities, and --base options are handled.
*
* @param line the command line to use
* @return an initialized IOHelper
diff --git a/robot-command/src/main/java/org/obolibrary/robot/FilterCommand.java b/robot-command/src/main/java/org/obolibrary/robot/FilterCommand.java
index f665dbfb7..2ebbfa477 100644
--- a/robot-command/src/main/java/org/obolibrary/robot/FilterCommand.java
+++ b/robot-command/src/main/java/org/obolibrary/robot/FilterCommand.java
@@ -1,7 +1,6 @@
package org.obolibrary.robot;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.cli.CommandLine;
@@ -30,8 +29,13 @@ public FilterCommand() {
o.addOption("I", "input-iri", true, "load ontology from an IRI");
o.addOption("o", "output", true, "save ontology to a file");
o.addOption("O", "ontology-iri", true, "set OntologyIRI for output");
+ o.addOption(null, "base-iri", true, "specify a base namespace");
o.addOption("t", "term", true, "term to filter");
o.addOption("T", "term-file", true, "load terms from a file");
+ o.addOption("e", "exclude-term", true, "term to force exclude");
+ o.addOption("E", "exclude-terms", true, "set of terms in text file to force exclude");
+ o.addOption("n", "include-term", true, "term to force include");
+ o.addOption("N", "include-terms", true, "set of terms in file to force include");
o.addOption("s", "select", true, "select a set of terms based on relations");
o.addOption(
"p", "preserve-structure", true, "if false, do not preserve hierarchical relationships");
@@ -111,20 +115,11 @@ public CommandState execute(CommandState state, String[] args) throws Exception
OWLOntology inputOntology = state.getOntology();
OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
- // Get a set of entities to start with
- Set objects = new HashSet<>();
- // track if a set of input IRIs were provided
- boolean hasInputIRIs = false;
- if (line.hasOption("term") || line.hasOption("term-file")) {
- Set entityIRIs = CommandLineHelper.getTerms(ioHelper, line, "term", "term-file");
- if (!entityIRIs.isEmpty()) {
- objects.addAll(OntologyHelper.getEntities(inputOntology, entityIRIs));
- hasInputIRIs = true;
- }
- }
+ // Create a new output ontology
+ OWLOntology outputOntology = getOutputOntology(line, inputOntology);
- // Get a set of axiom types
- Set> axiomTypes = CommandLineHelper.getAxiomValues(line);
+ // Selects should be processed in order, allowing unions in one --select
+ List> selectGroups = new ArrayList<>();
// Get a set of relation types, or annotations to select
List selects = CommandLineHelper.getOptionalValues(line, "select");
@@ -134,35 +129,9 @@ public CommandState execute(CommandState state, String[] args) throws Exception
selects.add("self");
}
- // Get the output IRI for the new ontology
- IRI outputIRI;
- String outputIRIString = CommandLineHelper.getOptionalValue(line, "ontology-iri");
- if (outputIRIString != null) {
- outputIRI = IRI.create(outputIRIString);
- } else {
- // If it is not provided, copy the input IRI
- outputIRI = inputOntology.getOntologyID().getOntologyIRI().orNull();
- }
-
- // Create the output ontology
- OWLOntology outputOntology;
- if (outputIRI != null) {
- outputOntology = manager.createOntology(outputIRI);
- } else {
- outputOntology = manager.createOntology();
- }
-
- // Selects should be processed in order, allowing unions in one --select
- List> selectGroups = new ArrayList<>();
-
// Track if 'annotations' selection is included
boolean includeAnnotations = false;
- // Track if selection was 'imports' or 'ontology'
- // These get processed separately and then removed
- // If no other select options are provided, we save and quit after that
- boolean hadSelection = false;
-
for (String select : selects) {
// The single group is a split of the one --select
List selectGroup = CommandLineHelper.splitSelects(select);
@@ -172,18 +141,17 @@ public CommandState execute(CommandState state, String[] args) throws Exception
selectGroup.remove("annotations");
}
if (selectGroup.contains("imports")) {
- // The imports keyword copies the import delcarations to the output ontology
+ // The imports keyword copies the import declarations to the output ontology
for (OWLImportsDeclaration imp : inputOntology.getImportsDeclarations()) {
manager.applyChange(new AddImport(outputOntology, imp));
}
- hadSelection = true;
selectGroup.remove("imports");
- } else if (selectGroup.contains("ontology")) {
+ }
+ if (selectGroup.contains("ontology")) {
// The ontology keyword retrieves the ontology annotations
for (OWLAnnotation annotation : inputOntology.getAnnotations()) {
OntologyHelper.addOntologyAnnotation(outputOntology, annotation);
}
- hadSelection = true;
selectGroup.remove("ontology");
}
if (!selectGroup.isEmpty()) {
@@ -191,60 +159,80 @@ public CommandState execute(CommandState state, String[] args) throws Exception
}
}
- // If filtering imports or ontology annotations,
- // and there are no other selects, save and return
- if (hadSelection && selectGroups.isEmpty() && objects.isEmpty()) {
- CommandLineHelper.maybeSaveOutput(line, outputOntology);
- state.setOntology(outputOntology);
- return state;
- } else if (objects.isEmpty() && hasInputIRIs) {
- // if objects is empty AND there WERE input IRIs
- // there is nothing to filter because the IRIs do not exist in the ontology
- // save and exit with empty ontology
+ // Use the select statements to get a set of objects to filter
+ Set relatedObjects =
+ RemoveCommand.getObjects(line, ioHelper, inputOntology, selectGroups);
+ if (relatedObjects.isEmpty()) {
+ // nothing to filter - save and exit
CommandLineHelper.maybeSaveOutput(line, outputOntology);
state.setOntology(outputOntology);
return state;
- } else if (objects.isEmpty()) {
- // if objects is empty AND there were NO input IRIs add all
- // this means that we are adding everything to the set to start
- objects.addAll(OntologyHelper.getObjects(inputOntology));
}
- // Use the select statements to get a set of objects to remove
- Set relatedObjects =
- RelatedObjectsHelper.selectGroups(inputOntology, ioHelper, objects, selectGroups);
-
- // Use these two options to determine which axioms to remove
+ // Add the additional axioms to the output ontology
+ List axiomSelectors = CommandLineHelper.cleanAxiomStrings(line);
+ List baseNamespaces = CommandLineHelper.getBaseNamespaces(line, ioHelper);
boolean trim = CommandLineHelper.getBooleanValue(line, "trim", true);
boolean signature = CommandLineHelper.getBooleanValue(line, "signature", false);
-
- // Get the axioms
- // Use !trim for the 'partial' option in getAxioms
- Set axiomsToAdd =
- RelatedObjectsHelper.getAxioms(inputOntology, relatedObjects, axiomTypes, !trim, signature);
+ manager.addAxioms(
+ outputOntology,
+ RelatedObjectsHelper.filterAxioms(
+ inputOntology.getAxioms(),
+ relatedObjects,
+ axiomSelectors,
+ baseNamespaces,
+ !trim,
+ signature));
// Handle gaps
boolean preserveStructure = CommandLineHelper.getBooleanValue(line, "preserve-structure", true);
if (preserveStructure) {
- axiomsToAdd.addAll(RelatedObjectsHelper.spanGaps(inputOntology, relatedObjects));
+ manager.addAxioms(
+ outputOntology, RelatedObjectsHelper.spanGaps(inputOntology, relatedObjects));
}
- // Handle annotations for any referenced object
+ // Maybe add annotations on the selected objects
if (includeAnnotations) {
- Set referencedObjects = new HashSet<>();
- for (OWLAxiom axiom : axiomsToAdd) {
- referencedObjects.addAll(OntologyHelper.getObjects(axiom));
- }
- axiomsToAdd.addAll(
- RelatedObjectsHelper.getAnnotationAxioms(inputOntology, referencedObjects));
+ manager.addAxioms(
+ outputOntology, RelatedObjectsHelper.getAnnotationAxioms(inputOntology, relatedObjects));
}
- // Add the additional axioms to the output ontology
- manager.addAxioms(outputOntology, axiomsToAdd);
-
// Save the changed ontology and return the state
CommandLineHelper.maybeSaveOutput(line, outputOntology);
state.setOntology(outputOntology);
return state;
}
+
+ /**
+ * Given a command line and an input ontology, create a new output ontology to put filtered axioms
+ * in.
+ *
+ * @param line command line to use
+ * @param inputOntology input ontology to maybe copy IRI
+ * @return OWLOntology output ontology
+ * @throws OWLOntologyCreationException on problem creating a new ontology
+ */
+ private static OWLOntology getOutputOntology(CommandLine line, OWLOntology inputOntology)
+ throws OWLOntologyCreationException {
+ OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
+ // Get the output IRI for the new ontology
+ IRI outputIRI;
+ String outputIRIString = CommandLineHelper.getOptionalValue(line, "ontology-iri");
+ if (outputIRIString != null) {
+ outputIRI = IRI.create(outputIRIString);
+ } else {
+ // If it is not provided, copy the input IRI
+ outputIRI = inputOntology.getOntologyID().getOntologyIRI().orNull();
+ }
+
+ // Create the output ontology
+ OWLOntology outputOntology;
+ if (outputIRI != null) {
+ outputOntology = manager.createOntology(outputIRI);
+ } else {
+ outputOntology = manager.createOntology();
+ }
+
+ return outputOntology;
+ }
}
diff --git a/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java b/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java
index 3a5bc2628..d03beb706 100644
--- a/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java
+++ b/robot-command/src/main/java/org/obolibrary/robot/QueryCommand.java
@@ -33,7 +33,8 @@ public class QueryCommand implements Command {
private static final String missingFileError = NS + "MISSING FILE ERROR file '%s' does not exist";
/** Error message when --query does not have two arguments. */
- private static final String missingOutputError = NS + "MISSING OUTPUT ERROR --%s requires two arguments: query and output";
+ private static final String missingOutputError =
+ NS + "MISSING OUTPUT ERROR --%s requires two arguments: query and output";
/** Error message when a query is not provided */
private static final String missingQueryError =
diff --git a/robot-command/src/main/java/org/obolibrary/robot/RemoveCommand.java b/robot-command/src/main/java/org/obolibrary/robot/RemoveCommand.java
index f84be5eb7..45a2ecc3e 100644
--- a/robot-command/src/main/java/org/obolibrary/robot/RemoveCommand.java
+++ b/robot-command/src/main/java/org/obolibrary/robot/RemoveCommand.java
@@ -28,8 +28,13 @@ public RemoveCommand() {
o.addOption("i", "input", true, "load ontology from a file");
o.addOption("I", "input-iri", true, "load ontology from an IRI");
o.addOption("o", "output", true, "save ontology to a file");
+ o.addOption(null, "base-iri", true, "specify a base namespace");
o.addOption("t", "term", true, "term to remove");
o.addOption("T", "term-file", true, "load terms from a file");
+ o.addOption("e", "exclude-term", true, "term to exclude from removal");
+ o.addOption("E", "exclude-terms", true, "set of terms in text file to exclude from removal");
+ o.addOption("n", "include-term", true, "term to force include");
+ o.addOption("N", "include-terms", true, "set of terms in file to force include");
o.addOption("s", "select", true, "select a set of terms based on relations");
o.addOption("a", "axioms", true, "filter only for given axiom types");
o.addOption(null, "include-term", true, "include term");
@@ -113,21 +118,6 @@ public CommandState execute(CommandState state, String[] args) throws Exception
OWLOntology ontology = state.getOntology();
OWLOntologyManager manager = ontology.getOWLOntologyManager();
- // Get a set of entities to start with
- Set objects = new HashSet<>();
- // track if a set of input IRIs were provided
- boolean hasInputIRIs = false;
- if (line.hasOption("term") || line.hasOption("term-file")) {
- Set entityIRIs = CommandLineHelper.getTerms(ioHelper, line, "term", "term-file");
- if (!entityIRIs.isEmpty()) {
- objects.addAll(OntologyHelper.getEntities(ontology, entityIRIs));
- hasInputIRIs = true;
- }
- }
-
- // Get a set of axiom types
- Set> axiomTypes = CommandLineHelper.getAxiomValues(line);
-
// Get a set of relation types, or annotations to select
List selects = CommandLineHelper.getOptionalValues(line, "select");
@@ -136,50 +126,119 @@ public CommandState execute(CommandState state, String[] args) throws Exception
selects.add("self");
}
- // Track if selection was 'imports' or 'ontology'
- // These get processed separately and then removed
- // If no other select options are provided, we save and quit after that
- boolean hadSelection = false;
-
- // Copy the unchanged ontology to reserve for filling gaps later
- OWLOntology copy =
- OWLManager.createOWLOntologyManager().copyOntology(ontology, OntologyCopy.DEEP);
-
// Selects should be processed in order, allowing unions in one --select
List> selectGroups = new ArrayList<>();
+ boolean anonymous = false;
for (String select : selects) {
// The single group is a split of the one --select
List selectGroup = CommandLineHelper.splitSelects(select);
// Imports should be handled separately
if (selectGroup.contains("imports")) {
OntologyHelper.removeImports(ontology);
- hadSelection = true;
selectGroup.remove("imports");
- } else if (selectGroup.contains("ontology")) {
+ }
+ if (selectGroup.contains("ontology")) {
OntologyHelper.removeOntologyAnnotations(ontology);
- hadSelection = true;
selectGroup.remove("ontology");
}
+ if (selectGroup.contains("anonymous")) {
+ anonymous = true;
+ }
if (!selectGroup.isEmpty()) {
selectGroups.add(selectGroup);
}
}
- if (hadSelection && selectGroups.isEmpty() && objects.isEmpty()) {
- // If removing imports or ontology annotations
- // and there are no other selects, save and return
+ // Get the objects to remove
+ Set relatedObjects = getObjects(line, ioHelper, ontology, selectGroups);
+ if (relatedObjects.isEmpty()) {
+ // nothing to remove - save and exit
CommandLineHelper.maybeSaveOutput(line, ontology);
state.setOntology(ontology);
return state;
- } else if (objects.isEmpty() && hasInputIRIs) {
+ }
+
+ // Copy the unchanged ontology to reserve for filling gaps later
+ OWLOntology copy =
+ OWLManager.createOWLOntologyManager().copyOntology(ontology, OntologyCopy.DEEP);
+
+ // Remove specific axioms
+ List axiomSelectors = CommandLineHelper.cleanAxiomStrings(line);
+ List baseNamespaces = CommandLineHelper.getBaseNamespaces(line, ioHelper);
+ boolean trim = CommandLineHelper.getBooleanValue(line, "trim", true);
+ boolean signature = CommandLineHelper.getBooleanValue(line, "signature", false);
+ manager.removeAxioms(
+ ontology,
+ RelatedObjectsHelper.filterAxioms(
+ ontology.getAxioms(), relatedObjects, axiomSelectors, baseNamespaces, trim, signature));
+
+ // Handle gaps
+ boolean preserveStructure = CommandLineHelper.getBooleanValue(line, "preserve-structure", true);
+ if (preserveStructure) {
+ // Since we are preserving the structure between the objects that were NOT removed, we need to
+ // get the complement of the removed object set and build relationships between those objects.
+ Set complementObjects =
+ RelatedObjectsHelper.select(ontology, ioHelper, relatedObjects, "complement");
+ manager.addAxioms(
+ ontology, RelatedObjectsHelper.spanGaps(copy, complementObjects, anonymous));
+ }
+
+ // Save the changed ontology and return the state
+ CommandLineHelper.maybeSaveOutput(line, ontology);
+ state.setOntology(ontology);
+ return state;
+ }
+
+ /**
+ * Given a command line, an IOHelper, an ontology, and a list of select groups, return the objects
+ * from the ontology based on the select groups.
+ *
+ * @param line CommandLine to get options from
+ * @param ioHelper IOHelper to get IRIs
+ * @param ontology OWLOntology to get objects from
+ * @param selectGroups List of select groups (lists of select options)
+ * @return set of selected objects from the ontology
+ * @throws Exception on issue getting terms or processing selects
+ */
+ protected static Set getObjects(
+ CommandLine line, IOHelper ioHelper, OWLOntology ontology, List> selectGroups)
+ throws Exception {
+ // Get a set of entities to start with
+ Set objects = new HashSet<>();
+ // track if a set of input IRIs were provided
+ boolean hasInputIRIs = false;
+ if (line.hasOption("term") || line.hasOption("term-file")) {
+ Set entityIRIs = CommandLineHelper.getTerms(ioHelper, line, "term", "term-file");
+ if (!entityIRIs.isEmpty()) {
+ objects.addAll(OntologyHelper.getEntities(ontology, entityIRIs));
+ hasInputIRIs = true;
+ }
+ }
+
+ boolean hadSelection = CommandLineHelper.hasFlagOrCommand(line, "select");
+ boolean axiomSelector = false;
+ List axiomSelectors = CommandLineHelper.cleanAxiomStrings(line);
+ for (String ats : axiomSelectors) {
+ if (ats.equalsIgnoreCase("internal")) {
+ axiomSelector = true;
+ } else if (ats.equalsIgnoreCase("external")) {
+ axiomSelector = true;
+ } else if (ats.contains("tautologies")) {
+ axiomSelector = true;
+ }
+ }
+
+ if (hadSelection && selectGroups.isEmpty() && objects.isEmpty() && !axiomSelector) {
+ // If removing imports or ontology annotations
+ // and there are no other selects, save and return
+ return objects;
+ } else if (objects.isEmpty() && hasInputIRIs && !axiomSelector) {
// if objects is empty AND there WERE input IRIs
// there is nothing to remove because the IRIs do not exist in the ontology
- // save and exit
- CommandLineHelper.maybeSaveOutput(line, ontology);
- state.setOntology(ontology);
- return state;
+ return objects;
} else if (objects.isEmpty()) {
// if objects is empty AND there were NO input IRIs add all
+ // OR internal/external were selected
// this means that we are adding everything to the set to start
objects.addAll(OntologyHelper.getObjects(ontology));
}
@@ -196,25 +255,24 @@ public CommandState execute(CommandState state, String[] args) throws Exception
relatedObjects.addAll(includeObjects);
}
- // Use these two options to determine which axioms to remove
- boolean trim = CommandLineHelper.getBooleanValue(line, "trim", true);
- boolean signature = CommandLineHelper.getBooleanValue(line, "signature", false);
-
- // Get the axioms and remove them
- Set axiomsToRemove =
- RelatedObjectsHelper.getAxioms(ontology, relatedObjects, axiomTypes, trim, signature);
- manager.removeAxioms(ontology, axiomsToRemove);
+ // Remove all the excluded terms from that set
+ if (line.hasOption("exclude-term") || line.hasOption("exclude-terms")) {
+ Set excludeIRIs =
+ CommandLineHelper.getTerms(ioHelper, line, "exclude-term", "exclude-terms");
+ Set excludeObjects =
+ new HashSet<>(OntologyHelper.getEntities(ontology, excludeIRIs));
+ relatedObjects.removeAll(excludeObjects);
+ }
- // Handle gaps
- boolean preserveStructure = CommandLineHelper.getBooleanValue(line, "preserve-structure", true);
- if (preserveStructure) {
- relatedObjects = RelatedObjectsHelper.select(ontology, ioHelper, objects, "complement");
- manager.addAxioms(ontology, RelatedObjectsHelper.spanGaps(copy, relatedObjects));
+ // Add all the include terms
+ if (line.hasOption("include-term") || line.hasOption("include-terms")) {
+ Set includeIRIs =
+ CommandLineHelper.getTerms(ioHelper, line, "include-term", "include-terms");
+ Set includeObjects =
+ new HashSet<>(OntologyHelper.getEntities(ontology, includeIRIs));
+ relatedObjects.addAll(includeObjects);
}
- // Save the changed ontology and return the state
- CommandLineHelper.maybeSaveOutput(line, ontology);
- state.setOntology(ontology);
- return state;
+ return relatedObjects;
}
}
diff --git a/robot-core/src/main/java/org/obolibrary/robot/IOHelper.java b/robot-core/src/main/java/org/obolibrary/robot/IOHelper.java
index 5337161b9..2bc086e4c 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/IOHelper.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/IOHelper.java
@@ -115,6 +115,9 @@ public class IOHelper {
+ "SYNTAX ERROR unable to load '%s' with Jena - "
+ "check that this file is in RDF/XML or TTL syntax and try again.";
+ /** Optional base namespaces. */
+ private Set baseNamespaces = new HashSet<>();
+
/** Path to default context as a resource. */
private static String defaultContextPath = "/obo_context.jsonld";
@@ -888,6 +891,43 @@ public static Context parseContext(String jsonString) throws IOException {
}
}
+ /**
+ * Add a base namespace to the IOHelper.
+ *
+ * @param baseNamespace namespace to add to bases.
+ */
+ public void addBaseNamespace(String baseNamespace) {
+ baseNamespaces.add(baseNamespace);
+ }
+
+ /**
+ * Add a set of base namespaces to the IOHelper from file. Each base namespace should be on its
+ * own line.
+ *
+ * @param baseNamespacePath path to base namespace file
+ * @throws IOException if file does not exist
+ */
+ public void addBaseNamespaces(String baseNamespacePath) throws IOException {
+ File prefixFile = new File(baseNamespacePath);
+ if (!prefixFile.exists()) {
+ throw new IOException(String.format(fileDoesNotExistError, baseNamespacePath));
+ }
+
+ List lines = FileUtils.readLines(new File(baseNamespacePath));
+ for (String l : lines) {
+ baseNamespaces.add(l.trim());
+ }
+ }
+
+ /**
+ * Get the base namespaces.
+ *
+ * @return set of base namespaces
+ */
+ public Set getBaseNamespaces() {
+ return baseNamespaces;
+ }
+
/**
* Get a copy of the default context.
*
diff --git a/robot-core/src/main/java/org/obolibrary/robot/ReasonOperation.java b/robot-core/src/main/java/org/obolibrary/robot/ReasonOperation.java
index 9bddb9429..caf4282a4 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/ReasonOperation.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/ReasonOperation.java
@@ -112,6 +112,81 @@ public static void reason(
assertInferred(ontology, reasoner, gens, options);
}
+ /**
+ * Create a tautology checker.
+ *
+ * @param structural if true, return null - we do not need a checker for the structural patterns
+ * @return new OWLReasoner for empty ontology or null
+ * @throws OWLOntologyCreationException on issue creating empty ontology
+ */
+ public static OWLReasoner getTautologyChecker(boolean structural)
+ throws OWLOntologyCreationException {
+ if (!structural) {
+ OWLOntology empty = OWLManager.createOWLOntologyManager().createOntology();
+ return new ReasonerFactory().createReasoner(empty);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Given an OWLAxiom, a tautology checker reasoner, and a boolean, determine if the axiom is a
+ * tautology.
+ *
+ * @param axiom OWLAxiom to check
+ * @param tautologyChecker OWLReasoner for empty ontology
+ * @param structural if true, only check for hard-coded structural patterns (checker can be null)
+ * @return true if axiom is tautological
+ */
+ public static boolean isTautological(
+ OWLAxiom axiom, OWLReasoner tautologyChecker, boolean structural) {
+ if (structural) {
+ if (axiom instanceof OWLSubClassOfAxiom) {
+ OWLSubClassOfAxiom subClassOfAxiom = (OWLSubClassOfAxiom) axiom;
+ if (subClassOfAxiom.getSuperClass().isOWLThing()) {
+ // X subClassOf owl:Thing
+ return true;
+ } else if (subClassOfAxiom.getSubClass().isOWLNothing()) {
+ // owl:Nothing subClassOf X
+ return true;
+ } else {
+ // X subClassOf X
+ return subClassOfAxiom.getSubClass().equals(subClassOfAxiom.getSuperClass());
+ }
+ } else if (axiom instanceof OWLEquivalentClassesAxiom) {
+ // X equivalentTo X
+ OWLEquivalentClassesAxiom equivAxiom = (OWLEquivalentClassesAxiom) axiom;
+ return equivAxiom.getClassExpressions().size() < 2;
+ } else if (axiom instanceof OWLClassAssertionAxiom) {
+ // X a owl:Thing
+ OWLClassAssertionAxiom classAssertion = (OWLClassAssertionAxiom) axiom;
+ return classAssertion.getClassExpression().isOWLThing();
+ } else if (axiom instanceof OWLObjectPropertyAssertionAxiom) {
+ // X owl:topDataProperty ...
+ OWLObjectPropertyAssertionAxiom assertion = (OWLObjectPropertyAssertionAxiom) axiom;
+ return assertion.getProperty().isOWLTopObjectProperty();
+ } else if (axiom instanceof OWLDataPropertyAssertionAxiom) {
+ // X owl:topObjectProperty ...
+ OWLDataPropertyAssertionAxiom assertion = (OWLDataPropertyAssertionAxiom) axiom;
+ return assertion.getProperty().isOWLTopDataProperty();
+ } else if (axiom instanceof OWLDeclarationAxiom) {
+ // owl:Thing a owl:Class, owl:Nothing a owl:Class, etc.
+ OWLDeclarationAxiom declaration = (OWLDeclarationAxiom) axiom;
+ return declaration.getEntity().isBuiltIn();
+ }
+ } else if (tautologyChecker != null) {
+ if (axiom instanceof OWLDeclarationAxiom) {
+ // ignore declaration UNLESS it is built in
+ OWLDeclarationAxiom declaration = (OWLDeclarationAxiom) axiom;
+ return declaration.getEntity().isBuiltIn();
+ } else if (axiom instanceof OWLLogicalAxiom) {
+ // otherwise check if axiom is entailed by empty ontology
+ return tautologyChecker.isEntailed(axiom);
+ }
+ }
+ return false;
+ }
+
/**
* Remove subClassAxioms where there is a more direct axiom, and the subClassAxiom does not have
* any annotations.
@@ -383,13 +458,9 @@ private static void addInferredAxioms(
// If we will need a tautology checker, create it only once
String tautologiesOption = OptionsHelper.getOption(options, "exclude-tautologies", "false");
- OWLReasoner tautologyChecker;
- if (tautologiesOption.equalsIgnoreCase("all")) {
- OWLOntology empty = OWLManager.createOWLOntologyManager().createOntology();
- tautologyChecker = new ReasonerFactory().createReasoner(empty);
- } else {
- tautologyChecker = null;
- }
+ boolean excludeTautologies = !tautologiesOption.equalsIgnoreCase("false");
+ boolean structural = tautologiesOption.equalsIgnoreCase("structural");
+ OWLReasoner tautologyChecker = getTautologyChecker(structural);
// Look at each inferred axiom
// Check the options, and maybe add the inferred axiom to the ontology
@@ -437,41 +508,9 @@ private static void addInferredAxioms(
}
}
- if (tautologiesOption.equalsIgnoreCase("structural")) {
- if (a instanceof OWLSubClassOfAxiom) {
- OWLSubClassOfAxiom subClassOfAxiom = (OWLSubClassOfAxiom) a;
- if (subClassOfAxiom.getSuperClass().isOWLThing()) {
- continue;
- } else if (subClassOfAxiom.getSubClass().isOWLNothing()) {
- continue;
- } else if (subClassOfAxiom.getSubClass().equals(subClassOfAxiom.getSuperClass())) {
- continue;
- }
- } else if (a instanceof OWLEquivalentClassesAxiom) {
- OWLEquivalentClassesAxiom equivAxiom = (OWLEquivalentClassesAxiom) a;
- if (equivAxiom.getClassExpressions().size() < 2) {
- continue;
- }
- } else if (a instanceof OWLClassAssertionAxiom) {
- OWLClassAssertionAxiom classAssertion = (OWLClassAssertionAxiom) a;
- if (classAssertion.getClassExpression().isOWLThing()) {
- continue;
- }
- } else if (a instanceof OWLObjectPropertyAssertionAxiom) {
- OWLObjectPropertyAssertionAxiom assertion = (OWLObjectPropertyAssertionAxiom) a;
- if (assertion.getProperty().isOWLTopObjectProperty()) {
- continue;
- }
- } else if (a instanceof OWLDataPropertyAssertionAxiom) {
- OWLDataPropertyAssertionAxiom assertion = (OWLDataPropertyAssertionAxiom) a;
- if (assertion.getProperty().isOWLTopDataProperty()) {
- continue;
- }
- }
- } else if (tautologiesOption.equalsIgnoreCase("all") && (tautologyChecker != null)) {
- if (tautologyChecker.isEntailed(a)) {
- continue;
- }
+ // Maybe exclude tautologies
+ if (excludeTautologies && isTautological(a, tautologyChecker, structural)) {
+ continue;
}
// If the axiom has not been skipped, add it to the ontology
@@ -496,7 +535,7 @@ private static void checkReferenceViolations(OWLOntology ontology, Map referenceViolations =
InvalidReferenceChecker.getInvalidReferenceViolations(ontology, false);
- Set filteredViolations = new HashSet();
+ Set filteredViolations = new HashSet<>();
if (referenceViolations.size() > 0) {
for (InvalidReferenceViolation v : referenceViolations) {
diff --git a/robot-core/src/main/java/org/obolibrary/robot/RelatedObjectsHelper.java b/robot-core/src/main/java/org/obolibrary/robot/RelatedObjectsHelper.java
index f5a959d98..4b98feb92 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/RelatedObjectsHelper.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/RelatedObjectsHelper.java
@@ -4,9 +4,11 @@
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.model.parameters.Imports;
+import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.search.EntitySearcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -28,6 +30,9 @@ public class RelatedObjectsHelper {
/** Namespace for error messages. */
private static final String NS = "errors#";
+ /** Error message when --axioms is not a valid AxiomType. Expects: input string. */
+ private static final String axiomTypeError = NS + "AXIOM TYPE ERROR %s is not a valid axiom type";
+
/**
* Error message when a datatype is given for an annotation, but the annotation value does not
* match the datatype.
@@ -81,52 +86,107 @@ public static Set getAnnotationAxioms(OWLOntology ontology, Set getAxioms(
- OWLOntology ontology,
+ /**
+ * Filter a set of OWLAxioms based on the provided arguments.
+ *
+ * @param axioms Set of OWLAxioms to filter
+ * @param objects Set of OWLObjects to get axioms for
+ * @param axiomSelectors List of string selectors for types of axioms
+ * @param baseNamespaces List of string base namespaces used for internal/external selections
+ * @param partial if true, get any axiom containing at least one OWLObject from objects
+ * @param namedOnly if true, ignore anonymous OWLObjects in axioms
+ * @return set of filtered OWLAxioms
+ * @throws OWLOntologyCreationException on issue creating empty ontology for tautology checker
+ */
+ public static Set filterAxioms(
+ Set axioms,
Set objects,
- Set> axiomTypes,
+ List axiomSelectors,
+ List baseNamespaces,
boolean partial,
- boolean signature) {
- if (partial) {
- return RelatedObjectsHelper.getPartialAxioms(ontology, objects, axiomTypes, signature);
- } else {
- return RelatedObjectsHelper.getCompleteAxioms(ontology, objects, axiomTypes, signature);
+ boolean namedOnly)
+ throws OWLOntologyCreationException {
+
+ // Go through the axiom selectors in order and process selections
+ boolean internal = false;
+ boolean external = false;
+ for (String axiomSelector : axiomSelectors) {
+ if (axiomSelector.equalsIgnoreCase("internal")) {
+ if (external) {
+ logger.error(
+ "ignoring 'internal' axiom selector - 'internal' and 'external' together will remove all axioms");
+ }
+ axioms = RelatedObjectsHelper.filterInternalAxioms(axioms, baseNamespaces);
+ internal = true;
+ } else if (axiomSelector.equalsIgnoreCase("external")) {
+ if (internal) {
+ logger.error(
+ "ignoring 'external' axiom selector - 'internal' and 'external' together will remove all axioms");
+ }
+ axioms = RelatedObjectsHelper.filterExternalAxioms(axioms, baseNamespaces);
+ external = true;
+ } else if (axiomSelector.equalsIgnoreCase("tautologies")) {
+ axioms = RelatedObjectsHelper.filterTautologicalAxioms(axioms, false);
+ } else if (axiomSelector.equalsIgnoreCase("structural-tautologies")) {
+ axioms = RelatedObjectsHelper.filterTautologicalAxioms(axioms, true);
+ } else {
+ // Assume this is a normal OWLAxiom type
+ Set> axiomTypes =
+ RelatedObjectsHelper.getAxiomValues(axiomSelector);
+ axioms = filterAxiomsByAxiomType(axioms, objects, axiomTypes, partial, namedOnly);
+ }
}
+
+ return axioms;
}
/**
- * Given an ontology, a set of objects, and a set of axiom types, return a set of axioms where all
- * the objects in those axioms are in the set of objects.
+ * Given a set of OWLAxioms, a set of OWLObjects, a set of OWLAxiom Classes, a partial boolean,
+ * and a named-only boolean, return a set of OWLAxioms based on OWLAxiom type. The axiom is added
+ * to the set if it is an instance of an OWLAxiom Class in the axiomTypes set. If partial, return
+ * any axioms that use at least one object from the objects set. Otherwise, only return axioms
+ * that use objects in the set. If namedOnly, only consider named OWLObjects in the axioms and
+ * ignore any anonymous objects when selecting the axioms.
*
- * @param ontology OWLOntology to get axioms from
- * @param objects Set of objects to match in axioms
- * @param axiomTypes OWLAxiom types to return
- * @return Set of OWLAxioms containing only the OWLObjects
+ * @param axioms set of OWLAxioms to filter
+ * @param objects set of OWLObjects to get axioms for
+ * @param axiomTypes set of OWLAxiom Classes that determines what type of axioms will be selected
+ * @param partial if true, include all axioms that use at least one OWLObject from objects
+ * @param namedOnly if true, ignore anonymous OWLObjects used in axioms
+ * @return set of filtered axioms
*/
- public static Set getCompleteAxioms(
- OWLOntology ontology, Set objects, Set> axiomTypes) {
- return getCompleteAxioms(ontology, objects, axiomTypes, false);
+ public static Set filterAxiomsByAxiomType(
+ Set axioms,
+ Set objects,
+ Set> axiomTypes,
+ boolean partial,
+ boolean namedOnly) {
+ if (partial) {
+ return RelatedObjectsHelper.filterPartialAxioms(axioms, objects, axiomTypes, namedOnly);
+ } else {
+ return RelatedObjectsHelper.filterCompleteAxioms(axioms, objects, axiomTypes, namedOnly);
+ }
}
/**
- * Given an ontology, a set of objects, and a set of axiom types, return a set of axioms where all
- * the objects in those axioms are in the set of objects.
+ * Given a st of axioms, a set of objects, and a set of axiom types, return a set of axioms where
+ * all the objects in those axioms are in the set of objects.
*
- * @param ontology OWLOntology to get axioms from
+ * @param inputAxioms Set of OWLAxioms to filter
* @param objects Set of objects to match in axioms
* @param axiomTypes OWLAxiom types to return
* @param namedOnly when true, consider only named OWLObjects
* @return Set of OWLAxioms containing only the OWLObjects
*/
- public static Set getCompleteAxioms(
- OWLOntology ontology,
+ public static Set filterCompleteAxioms(
+ Set inputAxioms,
Set objects,
Set> axiomTypes,
boolean namedOnly) {
axiomTypes = setDefaultAxiomType(axiomTypes);
Set axioms = new HashSet<>();
Set iris = getIRIs(objects);
- for (OWLAxiom axiom : ontology.getAxioms()) {
+ for (OWLAxiom axiom : inputAxioms) {
if (OntologyHelper.extendsAxiomTypes(axiom, axiomTypes)) {
// Check both the full annotated axiom and axiom without annotations (if annotated)
Set axiomObjects;
@@ -177,38 +237,64 @@ public static Set getCompleteAxioms(
}
/**
- * Given an ontology, a set of objects, and a set of axiom types, return a set of axioms where at
- * least one object in those axioms is also in the set of objects.
+ * Given a list of base namespaces and a set of axioms, return only the axioms that DO NOT have a
+ * subject in the base namespaces.
*
- * @param ontology OWLOntology to get axioms from
- * @param objects Set of objects to match in axioms
- * @param axiomTypes OWLAxiom types to return
- * @return Set of OWLAxioms containing at least one of the OWLObjects
+ * @param axioms set of OWLAxioms
+ * @param baseNamespaces list of base namespaces
+ * @return external OWLAxioms
*/
- public static Set getPartialAxioms(
- OWLOntology ontology, Set objects, Set> axiomTypes) {
- return getPartialAxioms(ontology, objects, axiomTypes, false);
+ public static Set filterExternalAxioms(
+ Set axioms, List baseNamespaces) {
+ Set externalAxioms = new HashSet<>();
+ for (OWLAxiom axiom : axioms) {
+ Set subjects = getAxiomSubjects(axiom);
+ if (!isBase(baseNamespaces, subjects)) {
+ externalAxioms.add(axiom);
+ }
+ }
+ return externalAxioms;
}
/**
- * Given an ontology, a set of objects, and a set of axiom types, return a set of axioms where at
- * least one object in those axioms is also in the set of objects.
+ * Given a list of base namespaces and a set of axioms, return only the axioms that have a subject
+ * in the base namespaces.
*
- * @param ontology OWLOntology to get axioms from
- * @param objects Set of objects to match in axioms
+ * @param axioms set of OWLAxioms
+ * @param baseNamespaces list of base namespaces
+ * @return internal OWLAxioms
+ */
+ public static Set filterInternalAxioms(
+ Set axioms, List baseNamespaces) {
+ Set internalAxioms = new HashSet<>();
+ for (OWLAxiom axiom : axioms) {
+ Set subjects = getAxiomSubjects(axiom);
+ if (isBase(baseNamespaces, subjects)) {
+ internalAxioms.add(axiom);
+ }
+ }
+ return internalAxioms;
+ }
+
+ /**
+ * Given a set of axioms, a set of objects, and a set of axiom types, return a set of axioms where
+ * at least one object in those axioms is also in the set of objects.
+ *
+ * @param inputAxioms Set of OWLAxioms to filter
+ * @param objects Set of OWLObjects to match in axioms
* @param axiomTypes OWLAxiom types to return
* @param namedOnly when true, only consider named OWLObjects
* @return Set of OWLAxioms containing at least one of the OWLObjects
*/
- public static Set getPartialAxioms(
- OWLOntology ontology,
+ public static Set filterPartialAxioms(
+ Set inputAxioms,
Set objects,
Set> axiomTypes,
boolean namedOnly) {
axiomTypes = setDefaultAxiomType(axiomTypes);
Set axioms = new HashSet<>();
Set iris = getIRIs(objects);
- for (OWLAxiom axiom : ontology.getAxioms()) {
+ for (OWLAxiom axiom : inputAxioms) {
if (OntologyHelper.extendsAxiomTypes(axiom, axiomTypes)) {
if (axiom instanceof OWLAnnotationAssertionAxiom) {
OWLAnnotationAssertionAxiom a = (OWLAnnotationAssertionAxiom) axiom;
@@ -245,6 +331,190 @@ public static Set getPartialAxioms(
return axioms;
}
+ /**
+ * Given a set of OWLAxioms and a structural boolean, filter for tautological axioms, i.e., those
+ * that would be true in any ontology.
+ *
+ * @param axioms set of OWLAxioms to filter
+ * @param structural if true, only filter for structural tautological axioms based on a hard-coded
+ * set of patterns (e.g., X subClassOf owl:Thing, owl:Nothing subClassOf X, X subClassOf X)
+ * @return tautological OWLAxioms from original set
+ * @throws OWLOntologyCreationException on issue creating empty ontology for tautology checker
+ */
+ public static Set filterTautologicalAxioms(Set axioms, boolean structural)
+ throws OWLOntologyCreationException {
+ // If structural, checker will be null
+ OWLReasoner tautologyChecker = ReasonOperation.getTautologyChecker(structural);
+ Set tautologies = new HashSet<>();
+ for (OWLAxiom a : axioms) {
+ if (ReasonOperation.isTautological(a, tautologyChecker, structural)) {
+ tautologies.add(a);
+ }
+ }
+ return tautologies;
+ }
+
+ /**
+ * @deprecated replaced by {@link #filterAxiomsByAxiomType(Set, Set, Set, boolean, boolean)}
+ * @param ontology OWLOntology to get axioms from
+ * @param objects OWLObjects to get axioms about
+ * @param axiomTypes Set of OWLAxiom Classes that are the types of OWLAxioms to return
+ * @param partial if true, return any OWLAxiom that has at least one OWLObject from objects
+ * @param signature if true, ignore anonymous OWLObjects in axioms
+ * @return axioms from ontology based on options
+ */
+ @Deprecated
+ public static Set getAxioms(
+ OWLOntology ontology,
+ Set objects,
+ Set> axiomTypes,
+ boolean partial,
+ boolean signature) {
+ if (partial) {
+ return RelatedObjectsHelper.getPartialAxioms(ontology, objects, axiomTypes, signature);
+ } else {
+ return RelatedObjectsHelper.getCompleteAxioms(ontology, objects, axiomTypes, signature);
+ }
+ }
+
+ /**
+ * Given a string axiom selector, return the OWLAxiom Class type(s) or null. The selector is
+ * either a special keyword that represents a set of axiom classes or the name of an OWLAxiom
+ * Class.
+ *
+ * @param axiomSelector string option to get the OWLAxiom Class type or types for
+ * @return set of OWLAxiom Class types based on the string option
+ */
+ public static Set> getAxiomValues(String axiomSelector) {
+ Set ignore =
+ new HashSet<>(
+ Arrays.asList("internal", "external", "tautologies", "structural-tautologies"));
+ if (ignore.contains(axiomSelector)) {
+ // Ignore special axiom options
+ return null;
+ }
+
+ Set> axiomTypes = new HashSet<>();
+ if (axiomSelector.equalsIgnoreCase("all")) {
+ axiomTypes.add(OWLAxiom.class);
+ } else if (axiomSelector.equalsIgnoreCase("logical")) {
+ axiomTypes.add(OWLLogicalAxiom.class);
+ } else if (axiomSelector.equalsIgnoreCase("annotation")) {
+ axiomTypes.add(OWLAnnotationAxiom.class);
+ } else if (axiomSelector.equalsIgnoreCase("subclass")) {
+ axiomTypes.add(OWLSubClassOfAxiom.class);
+ } else if (axiomSelector.equalsIgnoreCase("subproperty")) {
+ axiomTypes.add(OWLSubObjectPropertyOfAxiom.class);
+ axiomTypes.add(OWLSubDataPropertyOfAxiom.class);
+ axiomTypes.add(OWLSubAnnotationPropertyOfAxiom.class);
+ } else if (axiomSelector.equalsIgnoreCase("equivalent")) {
+ axiomTypes.add(OWLEquivalentClassesAxiom.class);
+ axiomTypes.add(OWLEquivalentObjectPropertiesAxiom.class);
+ axiomTypes.add(OWLEquivalentDataPropertiesAxiom.class);
+ } else if (axiomSelector.equalsIgnoreCase("disjoint")) {
+ axiomTypes.add(OWLDisjointClassesAxiom.class);
+ axiomTypes.add(OWLDisjointObjectPropertiesAxiom.class);
+ axiomTypes.add(OWLDisjointDataPropertiesAxiom.class);
+ axiomTypes.add(OWLDisjointUnionAxiom.class);
+ } else if (axiomSelector.equalsIgnoreCase("type")) {
+ axiomTypes.add(OWLClassAssertionAxiom.class);
+ } else if (axiomSelector.equalsIgnoreCase("abox")) {
+ axiomTypes.addAll(
+ AxiomType.ABoxAxiomTypes.stream()
+ .map(AxiomType::getActualClass)
+ .collect(Collectors.toSet()));
+ } else if (axiomSelector.equalsIgnoreCase("tbox")) {
+ axiomTypes.addAll(
+ AxiomType.TBoxAxiomTypes.stream()
+ .map(AxiomType::getActualClass)
+ .collect(Collectors.toSet()));
+ } else if (axiomSelector.equalsIgnoreCase("rbox")) {
+ axiomTypes.addAll(
+ AxiomType.RBoxAxiomTypes.stream()
+ .map(AxiomType::getActualClass)
+ .collect(Collectors.toSet()));
+ } else if (axiomSelector.equalsIgnoreCase("declaration")) {
+ axiomTypes.add(OWLDeclarationAxiom.class);
+ } else {
+ AxiomType> at = AxiomType.getAxiomType(axiomSelector);
+ if (at != null) {
+ // Attempt to get the axiom type based on AxiomType names
+ axiomTypes.add(at.getActualClass());
+ } else {
+ throw new IllegalArgumentException(String.format(axiomTypeError, axiomSelector));
+ }
+ }
+ return axiomTypes;
+ }
+
+ /**
+ * Given an ontology, a set of objects, and a set of axiom types, return a set of axioms where all
+ * the objects in those axioms are in the set of objects. Prefer {@link #filterCompleteAxioms(Set,
+ * Set, Set, boolean)}.
+ *
+ * @param ontology OWLOntology to get axioms from
+ * @param objects Set of objects to match in axioms
+ * @param axiomTypes OWLAxiom types to return
+ * @return Set of OWLAxioms containing only the OWLObjects
+ */
+ public static Set getCompleteAxioms(
+ OWLOntology ontology, Set objects, Set> axiomTypes) {
+ return filterCompleteAxioms(ontology.getAxioms(), objects, axiomTypes, false);
+ }
+
+ /**
+ * Given an ontology, a set of objects, and a set of axiom types, return a set of axioms where all
+ * the objects in those axioms are in the set of objects. Prefer {@link #filterCompleteAxioms(Set,
+ * Set, Set, boolean)}.
+ *
+ * @param ontology OWLOntology to get axioms from
+ * @param objects Set of objects to match in axioms
+ * @param axiomTypes OWLAxiom types to return
+ * @param namedOnly when true, consider only named OWLObjects
+ * @return Set of OWLAxioms containing only the OWLObjects
+ */
+ public static Set getCompleteAxioms(
+ OWLOntology ontology,
+ Set objects,
+ Set> axiomTypes,
+ boolean namedOnly) {
+ return filterCompleteAxioms(ontology.getAxioms(), objects, axiomTypes, namedOnly);
+ }
+
+ /**
+ * Given an ontology, a set of objects, and a set of axiom types, return a set of axioms where at
+ * least one object in those axioms is also in the set of objects. Prefer {@link
+ * #filterPartialAxioms(Set, Set, Set, boolean)}.
+ *
+ * @param ontology OWLOntology to get axioms from
+ * @param objects Set of objects to match in axioms
+ * @param axiomTypes OWLAxiom types to return
+ * @return Set of OWLAxioms containing at least one of the OWLObjects
+ */
+ public static Set getPartialAxioms(
+ OWLOntology ontology, Set objects, Set> axiomTypes) {
+ return filterPartialAxioms(ontology.getAxioms(), objects, axiomTypes, false);
+ }
+
+ /**
+ * Given an ontology, a set of objects, and a set of axiom types, return a set of axioms where at
+ * least one object in those axioms is also in the set of objects. Prefer {@link
+ * #filterPartialAxioms(Set, Set, Set, boolean)}.
+ *
+ * @param ontology OWLOntology to get axioms from
+ * @param objects Set of objects to match in axioms
+ * @param axiomTypes OWLAxiom types to return
+ * @param namedOnly when true, only consider named OWLObjects
+ * @return Set of OWLAxioms containing at least one of the OWLObjects
+ */
+ public static Set getPartialAxioms(
+ OWLOntology ontology,
+ Set objects,
+ Set> axiomTypes,
+ boolean namedOnly) {
+ return filterPartialAxioms(ontology.getAxioms(), objects, axiomTypes, namedOnly);
+ }
+
/**
* Given an ontology, a set of objects, and a list of select groups (as lists), return the objects
* related to the set of OWLObjects based on each set of selectors. Each selector group will build
@@ -350,6 +620,8 @@ public static Set select(
return selectPattern(ontology, ioHelper, objects, selector);
} else if (Pattern.compile("<.*>").matcher(selector).find()) {
return selectIRI(objects, selector);
+ } else if (selector.contains(":")) {
+ return selectCURIE(ioHelper, objects, selector);
} else {
logger.error(String.format("%s is not a valid selector and will be ignored", selector));
return new HashSet<>();
@@ -471,6 +743,24 @@ public static Set selectComplement(OWLOntology ontology, Set selectCURIE(
+ IOHelper ioHelper, Set objects, String selector) {
+ String prefix = selector.split(":")[0];
+ String pattern = selector.split(":")[1];
+ Map prefixes = ioHelper.getPrefixes();
+ String namespace = prefixes.getOrDefault(prefix, null);
+
+ if (namespace == null) {
+ logger.error(String.format("Prefix '%s' is not a loaded prefix and will be ignored", prefix));
+ return objects;
+ }
+
+ String iriPattern = namespace + pattern;
+
+ return selectIRI(objects, iriPattern);
+ }
+
/**
* Given a set of objects, return a set of OWLDataProperties from the starting set.
*
@@ -762,6 +1052,10 @@ public static Set selectTypes(OWLOntology ontology, Set ob
return relatedObjects;
}
+ public static Set spanGaps(OWLOntology ontology, Set objects) {
+ return spanGaps(ontology, objects, false);
+ }
+
/**
* Given an ontology and a set of objects, construct a set of subClassOf axioms that span the gaps
* between classes to maintain a hierarchy.
@@ -770,7 +1064,8 @@ public static Set selectTypes(OWLOntology ontology, Set ob
* @param objects set of Objects to build hierarchy
* @return set of OWLAxioms to maintain hierarchy
*/
- public static Set spanGaps(OWLOntology ontology, Set objects) {
+ public static Set spanGaps(
+ OWLOntology ontology, Set objects, boolean excludeAnonymous) {
Set