├── .gitignore ├── Logic_Law ├── Logic.hs └── TestSuite.hs ├── Peano_Numbers ├── Makefile ├── peano.h ├── run_test.sh ├── test_add.cpp ├── test_div.cpp ├── test_mul.cpp ├── test_other.cpp └── test_sub.cpp ├── Project ├── docs.md └── main.py ├── README.md └── Rationals ├── Makefile └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # 忽略操作系统生成的文件 2 | .DS_Store 3 | Thumbs.db 4 | 5 | # 忽略编译生成的文件 6 | *.o 7 | *.out 8 | *.exe 9 | 10 | # 忽略IDE和编辑器生成的文件 11 | .idea/ 12 | .vscode/ -------------------------------------------------------------------------------- /Logic_Law/Logic.hs: -------------------------------------------------------------------------------- 1 | module Logic where 2 | 3 | data Logic = A | B | C 4 | | And Logic Logic 5 | | Or Logic Logic 6 | | Not Logic 7 | | Imply Logic Logic 8 | | Equiv Logic Logic 9 | deriving (Eq, Show) 10 | 11 | -- Distribute function applying the distributive law 12 | distribute :: Logic -> Logic 13 | distribute (Or p (And q r)) = And (Or (distribute p) (distribute q)) (Or (distribute p) (distribute r)) 14 | distribute (Or (And p q) r) = And (Or (distribute p) (distribute r)) (Or (distribute q) (distribute r)) 15 | distribute (And p q) = And (distribute p) (distribute q) 16 | distribute (Or p q) = Or (distribute p) (distribute q) 17 | distribute (Not p) = Not (distribute p) 18 | distribute (Imply p q) = Imply (distribute p) (distribute q) 19 | distribute (Equiv p q) = Equiv (distribute p) (distribute q) 20 | distribute p = p -- No distribution needed for other cases 21 | 22 | -- deMorgan function applying De Morgan's laws 23 | deMorgan :: Logic -> Logic 24 | deMorgan (Not (Or p q)) = And (Not (deMorgan p)) (Not (deMorgan q)) 25 | deMorgan (Not (And p q)) = Or (Not (deMorgan p)) (Not (deMorgan q)) 26 | deMorgan (And p q) = And (deMorgan p) (deMorgan q) 27 | deMorgan (Or p q) = Or (deMorgan p) (deMorgan q) 28 | deMorgan (Not p) = Not (deMorgan p) 29 | deMorgan (Imply p q) = Imply (deMorgan p) (deMorgan q) 30 | deMorgan (Equiv p q) = Equiv (deMorgan p) (deMorgan q) 31 | deMorgan p = p -- No De Morgan's law applies to other cases 32 | -------------------------------------------------------------------------------- /Logic_Law/TestSuite.hs: -------------------------------------------------------------------------------- 1 | module TestSuite where 2 | 3 | import Logic 4 | 5 | -- Helper function to assert equality of Logic expressions 6 | assertEqual :: (Eq a, Show a) => String -> a -> a -> IO () 7 | assertEqual label expected actual = 8 | if expected == actual 9 | then putStrLn $ label ++ " passed" 10 | else putStrLn $ label ++ " FAILED: expected " ++ show expected ++ ", got " ++ show actual 11 | 12 | -- Test cases for distribute function 13 | testDistribute1 = assertEqual "testDistribute1" (Or (And A B) (And A C)) (distribute (And A (Or B C))) 14 | testDistribute2 = assertEqual "testDistribute2" (And (Or A B) (Or A C)) (distribute (Or A (And B C))) 15 | 16 | -- Test cases for deMorgan function 17 | testDeMorgan1 = assertEqual "testDeMorgan1" (And (Not A) (Not B)) (deMorgan (Not (Or A B))) 18 | testDeMorgan2 = assertEqual "testDeMorgan2" (Or (Not A) (Not B)) (deMorgan (Not (And A B))) 19 | 20 | -- Main function to run all tests 21 | main :: IO () 22 | main = do 23 | testDistribute1 24 | testDistribute2 25 | testDeMorgan1 26 | testDeMorgan2 27 | -------------------------------------------------------------------------------- /Peano_Numbers/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -std=c++11 3 | 4 | SRCS := test_add.cpp test_sub.cpp test_mul.cpp \ 5 | test_div.cpp test_other.cpp 6 | 7 | 8 | OBJS := ${SRCS:cpp=o} 9 | PROGS := ${SRCS:.cpp=} 10 | 11 | .PHONY: all 12 | all: ${PROGS} 13 | 14 | ${PROGS} : % : %.o Makefile 15 | ${CXX} $< -o $@ ${LIBS} 16 | 17 | clean: 18 | rm -f ${PROGS} ${OBJS} 19 | 20 | %.o: %.cpp Makefile 21 | ${CXX} ${CXXFLAGS} -c $< -------------------------------------------------------------------------------- /Peano_Numbers/peano.h: -------------------------------------------------------------------------------- 1 | namespace Peano_Numbers { 2 | struct Peano{ 3 | }; 4 | struct Zero : Peano{ 5 | static constexpr int value = 0; 6 | }; 7 | 8 | template 9 | struct Succ : Peano{ 10 | static constexpr int value = T::value + 1; 11 | }; 12 | 13 | // Add operation 14 | template 15 | struct Add : Peano{ 16 | static constexpr int value = A::value + B::value; 17 | }; 18 | 19 | // Subtract operation 20 | template 21 | struct Sub : Peano{ 22 | // The result of subtraction is always non-negative, print error message if the result is negative 23 | static_assert(A::value >= B::value, "Subtraction result is negative"); 24 | static constexpr int value = A::value - B::value; 25 | }; 26 | 27 | // Multiply operation 28 | template 29 | struct Mul : Peano{ 30 | static constexpr int value = A::value * B::value; 31 | }; 32 | 33 | // Divide operation 34 | template 35 | struct Div : Peano{ 36 | static_assert(B::value != 0, "Division by zero"); 37 | static constexpr int value = A::value / B::value; 38 | }; 39 | 40 | // Even operation 41 | template 42 | struct Even : Peano{ 43 | static constexpr bool value = A::value % 2 == 0; 44 | }; 45 | 46 | // Odd operation 47 | template 48 | struct Odd : Peano{ 49 | static constexpr bool value = A::value % 2 != 0; 50 | }; 51 | // LT, Less than operation 52 | template 53 | struct LT : Peano{ 54 | static constexpr bool value = A::value < B::value; 55 | }; 56 | // GT, Greater than operation 57 | template 58 | struct GT : Peano{ 59 | static constexpr bool value = A::value > B::value; 60 | }; 61 | // EQ, Equal operation 62 | template 63 | struct EQ : Peano{ 64 | static constexpr bool value = A::value == B::value; 65 | }; 66 | } -------------------------------------------------------------------------------- /Peano_Numbers/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make all 4 | all_test_files="test_add test_div test_mul test_sub test_other" 5 | for test_file in ${all_test_files}; do 6 | echo "Running ${test_file}..." 7 | ./${test_file} 8 | echo "===========================" 9 | done 10 | 11 | echo "All tests completed." 12 | make clean 13 | -------------------------------------------------------------------------------- /Peano_Numbers/test_add.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "peano.h" // 替换为你的文件名 3 | 4 | using namespace std; 5 | using namespace Peano_Numbers; 6 | 7 | int main() { 8 | // Test addition 9 | using Result1 = Add; 10 | static_assert(Result1::value == 0, "Test 1 failed, expected 0"); 11 | using Result2 = Add>; 12 | static_assert(Result2::value == 1, "Test 2 failed, expected 1"); 13 | using Result3 = Add, Zero>; 14 | static_assert(Result3::value == 1, "Test 3 failed, expected 1"); 15 | using Result4 = Add, Succ>; 16 | static_assert(Result4::value == 2, "Test 4 failed, expected 2"); 17 | cout << "All addition tests passed!" << endl; 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /Peano_Numbers/test_div.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "peano.h" 3 | 4 | using namespace std; 5 | using namespace Peano_Numbers; 6 | 7 | int main() { 8 | // Test division 9 | using Result1 = Div>; 10 | static_assert(Result1::value == 0, "Test 1 failed, expected 0"); 11 | 12 | using Result2 = Div>, Succ>; 13 | static_assert(Result2::value == 2, "Test 2 failed, expected 2"); 14 | 15 | // Test division by zero 16 | // This test should trigger a static_assertion failure 17 | // A divided by 0 18 | // using Result3 = Div; 19 | // printf("Result3::value = %d\n", Result3::value); // Uncommenting this line will cause a static_assertion failure 20 | 21 | cout << "All division tests passed!" << endl; 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /Peano_Numbers/test_mul.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "peano.h" 3 | 4 | using namespace std; 5 | using namespace Peano_Numbers; 6 | 7 | int main() { 8 | // Test multiplication 9 | using Result1 = Mul; 10 | static_assert(Result1::value == 0, "Test 1 failed, expected 0"); 11 | 12 | using Result2 = Mul>; 13 | static_assert(Result2::value == 0, "Test 2 failed, expected 0"); 14 | 15 | using Result3 = Mul, Zero>; 16 | static_assert(Result3::value == 0, "Test 3 failed, expected 0"); 17 | 18 | using Result4 = Mul, Succ>; 19 | static_assert(Result4::value == 1, "Test 4 failed, expected 1"); 20 | 21 | using Result5 = Mul>, Succ>>; 22 | static_assert(Result5::value == 4, "Test 5 failed, expected 4"); 23 | 24 | cout << "All multiplication tests passed!" << endl; 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /Peano_Numbers/test_other.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "peano.h" // 替换为你的文件名 3 | 4 | using namespace std; 5 | using namespace Peano_Numbers; 6 | 7 | int main() { 8 | // Test Even operation 9 | { 10 | // Test Even1 11 | using Even1 = Even; 12 | static_assert(Even1::value == true, "Test Even1 failed"); 13 | 14 | // Test Even2 15 | using Even2 = Even>; 16 | static_assert(Even2::value == false, "Test Even2 failed"); 17 | 18 | // Test Even3 19 | using Even3 = Even>>; 20 | static_assert(Even3::value == true, "Test Even3 failed"); 21 | 22 | cout << "All Even tests passed!" << endl; 23 | } 24 | 25 | // Test Odd operation 26 | { 27 | // Test Odd1 28 | using Odd1 = Odd; 29 | static_assert(Odd1::value == false, "Test Odd1 failed"); 30 | 31 | // Test Odd2 32 | using Odd2 = Odd>; 33 | static_assert(Odd2::value == true, "Test Odd2 failed"); 34 | 35 | // Test Odd3 36 | using Odd3 = Odd>>; 37 | static_assert(Odd3::value == false, "Test Odd3 failed"); 38 | 39 | cout << "All Odd tests passed!" << endl; 40 | } 41 | 42 | // Test Less than operation 43 | { 44 | // Test LT1 45 | using LT1 = LT; 46 | static_assert(LT1::value == false, "Test LT1 failed"); 47 | 48 | // Test LT2 49 | using LT2 = LT>; 50 | static_assert(LT2::value == true, "Test LT2 failed"); 51 | 52 | // Test LT3 53 | using LT3 = LT, Zero>; 54 | static_assert(LT3::value == false, "Test LT3 failed"); 55 | 56 | // Test LT4 57 | using LT4 = LT, Succ>; 58 | static_assert(LT4::value == false, "Test LT4 failed"); 59 | 60 | cout << "All Less than tests passed!" << endl; 61 | } 62 | 63 | // Test Greater than operation 64 | { 65 | // Test GT1 66 | using GT1 = GT; 67 | static_assert(GT1::value == false, "Test GT1 failed"); 68 | 69 | // Test GT2 70 | using GT2 = GT>; 71 | static_assert(GT2::value == false, "Test GT2 failed"); 72 | 73 | // Test GT3 74 | using GT3 = GT, Zero>; 75 | static_assert(GT3::value == true, "Test GT3 failed"); 76 | 77 | // Test GT4 78 | using GT4 = GT, Succ>; 79 | static_assert(GT4::value == false, "Test GT4 failed"); 80 | 81 | cout << "All Greater than tests passed!" << endl; 82 | } 83 | 84 | // Test Equal operation 85 | { 86 | // Test EQ1 87 | using EQ1 = EQ; 88 | static_assert(EQ1::value == true, "Test EQ1 failed"); 89 | 90 | // Test EQ2 91 | using EQ2 = EQ>; 92 | static_assert(EQ2::value == false, "Test EQ2 failed"); 93 | 94 | // Test EQ3 95 | using EQ3 = EQ, Zero>; 96 | static_assert(EQ3::value == false, "Test EQ3 failed"); 97 | 98 | // Test EQ4 99 | using EQ4 = EQ, Succ>; 100 | static_assert(EQ4::value == true, "Test EQ4 failed"); 101 | 102 | cout << "All Equal tests passed!" << endl; 103 | } 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /Peano_Numbers/test_sub.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "peano.h" 3 | 4 | using namespace std; 5 | using namespace Peano_Numbers; 6 | 7 | int main() { 8 | // Test subtraction 9 | using Result1 = Sub; 10 | static_assert(Result1::value == 0, "Test 1 failed, expected 0"); 11 | using Result2 = Sub, Zero>; 12 | static_assert(Result2::value == 1, "Test 2 failed, expected 1"); 13 | using Result3 = Sub>, Succ>; 14 | static_assert(Result3::value == 1, "Test 3 failed, expected 0"); 15 | 16 | // Test subtraction with negative result 17 | // This test should trigger a static_assertion failure 18 | // A < B 19 | // using Result4 = Sub>>; // 0 - 2 20 | // printf("Result4::value = %d\n", Result4::value); 21 | cout << "All subtraction tests passed!" << endl; 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /Project/docs.md: -------------------------------------------------------------------------------- 1 | ## Problem 2 | 3 | You're cordially invited to develop a reasoner for EL or its extensions, then apply the normalisation procedure to the TBox 4 | 5 | $$ 6 | \begin{aligned} 7 | \mathcal{T} = \left\lbrace 8 | \begin{array}{ccc} 9 | A & \sqsubseteq & B \sqcap \exists r.C, \\ 10 | & \\ 11 | C & \sqsubseteq & \exists s.D, \\ 12 | \exists r.\exists s.\top & \sqcap & B \sqsubseteq D 13 | \end{array} 14 | \right\rbrace 15 | \end{aligned} 16 | $$ 17 | 18 | and then check whether it entails 19 | 20 | $$ 21 | A\sqsubseteq D. 22 | $$ 23 | 24 | The reasoner can be developed in any programming language you like, but comments or documentation are always necessary. 25 | 26 | ## Report: Development and Application of a Lightweight EL Reasoner for Terminology Box Normalization and Query Entailment Analysis 27 | 28 | ### 1 Introduction 29 | 30 | This report documents the development and application of a simple reasoner for Description Logic (DL), specifically tailored towards the lightweight subset known as the EL family, which allows existential quantification and conjunction operations. The primary objective is to demonstrate the implementation of a reasoner capable of normalizing a given Terminology Box (TBox) and checking entailment queries. The problem statement involves a TBox with specific subsumption axioms and a query to verify whether A ⊑ D is entailed. 31 | 32 | ### 2 Implementation Details 33 | 34 | #### 2.1 System Architecture 35 | 36 | The solution is implemented in Python, leveraging object-oriented programming to model fundamental DL constructs such as Concepts, Roles, Existentials, Conjunctions, Subsumptions, and a TBox. Each class encapsulates the necessary logic to represent DL expressions and perform basic operations like equality checks, hashing, and string representation for readability.This design choice bolsters readability, maintainability, and extensibility. 37 | 38 | ##### 2.1.1 Core Classes and Their Functions 39 | 40 | - **Concept**: Serves as the fundamental unit representing named concepts within the DL framework. 41 | - **Role**: Models semantic relationships or properties connecting concepts. 42 | - **Existential**: Formalizes existential restrictions, signifying the existence of related objects satisfying a given concept. 43 | - **Conjunction**: Facilitates the representation of logical conjunctions between two concepts. 44 | - **Subsumption**: Codifies subclass relationships, crucial for expressing hierarchical structures. 45 | - **TBox**: Constitutes a container for subsumption axioms, featuring methods for TBox normalization, closure computation, and entailment checks. 46 | 47 | #### 2.2 Reasoning Procedures 48 | 49 | ##### 2.2.1 Normalization of TBox 50 | 51 | Normalization constitutes a pivotal process in refining TBox axioms into a less convoluted form, thereby streamlining entailment assessments. The `normalize` function embedded within the TBox class disassembles composite axioms, particularly those entailing conjunctions, into simpler, more manageable components. 52 | 53 | ##### 2.2.2 Closure Computation 54 | 55 | The `closure` method systematically generates the deductive closure of the normalized TBox. By iteratively deducing all implications inherent in the axioms and incorporating these into the closure set, it establishes a comprehensive repository of derivable knowledge. This process is vital for entailment verification, as inclusion of a query in the closure signifies entailment. 56 | 57 | ##### 2.2.3 Entailment Verification 58 | 59 | The `entails` method systematically assesses whether a proposed query (subsumption) is logically inferred from the TBox. Following normalization and closure computation, it confirms the presence of the query within the closure set, affirming entailment. 60 | 61 | #### 2.3 Demonstration and Findings 62 | 63 | Given the provided TBox and query, the implemented reasoner successfully demonstrates the following steps: 64 | 65 | 1. Initializes the TBox with the given subsumption axioms. 66 | 67 | 2. Normalizes the TBox, decomposing complex axioms. 68 | 69 | 3. Computes the closure to generate all derivable consequences. 70 | 71 | 4. Determines that A ⊑ D is indeed entailed by the TBox, showcasing the reasoner's correctness. 72 | 73 | 74 | ### 3 Conclusion and Future Perspectives 75 | 76 | This project showcases a basic yet functional implementation of a DL reasoner focusing on EL-like languages. It emphasizes the importance of normalization in simplifying reasoning tasks and highlights the process of entailment verification through closure computation. The code is well-documented to facilitate understanding and future extensions to more expressive DL fragments.* 77 | 78 | Potential enhancements include incorporating more advanced DL features (e.g., number restrictions, disjunctions), optimizing the reasoning algorithms for scalability, and integrating with standardized OWL or RDF frameworks for practical applications in knowledge representation and semantic web technologies. 79 | 80 | The attached code snippet serves as a proof-of-concept for the described functionality and can be further extended or modified to suit more complex requirements in DL-based systems. 81 | 82 | ### References 83 | 84 | - Horrocks, I., Sattler, U., Tobies, S. (1999). Practical Reasoning for Expressive Description Logics. In: Ganzinger, H., McAllester, D., Voronkov, A. (eds) Logic for Programming and Automated Reasoning. LPAR 1999. Lecture Notes in Computer Science(), vol 1705. Springer, Berlin, Heidelberg. https://doi.org/10.1007/3-540-48242-3_11 85 | 86 | - Baader F, Calvanese D, McGuinness DL, Nardi D, Patel-Schneider PF, eds. *The Description Logic Handbook: Theory, Implementation and Applications*. 2nd ed. Cambridge University Press; 2007. 87 | 88 | - Cucala D T, Grau B C, Horrocks I. Consequence-based reasoning for description logics with disjunction, inverse roles, number restrictions, and nominals[J]. arXiv preprint arXiv:1805.01396, 2018. 89 | -------------------------------------------------------------------------------- /Project/main.py: -------------------------------------------------------------------------------- 1 | class Concept: 2 | """ 3 | Represents a concept in Description Logic, identified by a unique name. 4 | """ 5 | def __init__(self, name): 6 | self.name = name 7 | 8 | def __eq__(self, other): 9 | return isinstance(other, Concept) and self.name == other.name 10 | 11 | def __hash__(self): 12 | return hash(self.name) 13 | 14 | def __repr__(self): 15 | return self.name 16 | 17 | class Role: 18 | """ 19 | Represents a role (also known as a property or relationship) connecting concepts in Description Logic. 20 | """ 21 | def __init__(self, name): 22 | self.name = name 23 | 24 | def __eq__(self, other): 25 | return isinstance(other, Role) and self.name == other.name 26 | 27 | def __hash__(self): 28 | return hash(self.name) 29 | 30 | def __repr__(self): 31 | return self.name 32 | 33 | class Existential: 34 | """ 35 | Represents an existential restriction in Description Logic, indicating that there exists an object 36 | related via a role that satisfies a certain concept. 37 | """ 38 | def __init__(self, role, concept): 39 | self.role = role 40 | self.concept = concept 41 | 42 | def __eq__(self, other): 43 | return isinstance(other, Existential) and self.role == other.role and self.concept == other.concept 44 | 45 | def __hash__(self): 46 | return hash((self.role, self.concept)) 47 | 48 | def __repr__(self): 49 | return f"∃{self.role}.{self.concept}" 50 | 51 | class Conjunction: 52 | """ 53 | Represents the conjunction (AND operation) of two concepts. 54 | """ 55 | def __init__(self, left, right): 56 | self.left = left 57 | self.right = right 58 | 59 | def __eq__(self, other): 60 | return isinstance(other, Conjunction) and self.left == other.left and self.right == other.right 61 | 62 | def __hash__(self): 63 | return hash((self.left, self.right)) 64 | 65 | def __repr__(self): 66 | return f"({self.left} ⊓ {self.right})" 67 | 68 | class Subsumption: 69 | """ 70 | Represents a subsumption (subclass) relationship between two concepts. 71 | """ 72 | def __init__(self, sub, sup): 73 | self.sub = sub 74 | self.sup = sup 75 | 76 | def __eq__(self, other): 77 | return isinstance(other, Subsumption) and self.sub == other.sub and self.sup == other.sup 78 | 79 | def __hash__(self): 80 | return hash((self.sub, self.sup)) 81 | 82 | def __repr__(self): 83 | return f"{self.sub} ⊑ {self.sup}" 84 | 85 | class TBox: 86 | """ 87 | Represents a Terminology Box (TBox), containing a set of subsumption axioms defining the concept hierarchy. 88 | """ 89 | def __init__(self, axioms=None): 90 | self.axioms = axioms if axioms else set() 91 | 92 | def add_axiom(self, axiom): 93 | self.axioms.add(axiom) 94 | 95 | def normalize(self): 96 | normalized_tbox = set() 97 | print("Normalizing TBox:") 98 | for axiom in self.axioms: 99 | print(f"Processing {axiom}") 100 | if isinstance(axiom.sub, Conjunction): 101 | # If the subsumption has a conjunction on the left side 102 | normalized_tbox.add(Subsumption(axiom.sub.left, axiom.sup)) 103 | normalized_tbox.add(Subsumption(axiom.sub.right, axiom.sup)) 104 | print(f"Added {Subsumption(axiom.sub.left, axiom.sup)}") 105 | print(f"Added {Subsumption(axiom.sub.right, axiom.sup)}") 106 | elif isinstance(axiom.sup, Conjunction): 107 | # If the subsumption has a conjunction on the right side 108 | normalized_tbox.add(Subsumption(axiom.sub, axiom.sup.left)) 109 | normalized_tbox.add(Subsumption(axiom.sub, axiom.sup.right)) 110 | print(f"Added {Subsumption(axiom.sub, axiom.sup.left)}") 111 | print(f"Added {Subsumption(axiom.sub, axiom.sup.right)}") 112 | else: 113 | # If the subsumption is a regular subsumption 114 | normalized_tbox.add(axiom) 115 | print(f"Added {axiom}") 116 | print("Normalization complete.\n") 117 | return TBox(normalized_tbox) 118 | 119 | def closure(self): 120 | closure_set = set(self.axioms) 121 | derivation = [] 122 | added = True 123 | print("Computing closure:") 124 | while added: 125 | added = False 126 | new_axioms = set() 127 | for axiom1 in closure_set: 128 | for axiom2 in closure_set: 129 | if isinstance(axiom1.sup, Concept) and axiom1.sup == axiom2.sub: 130 | # If there is a match for subsumption and concept 131 | new_axiom = Subsumption(axiom1.sub, axiom2.sup) 132 | if new_axiom not in closure_set: 133 | new_axioms.add(new_axiom) 134 | derivation.append((axiom1, axiom2, new_axiom)) 135 | added = True 136 | print(f"Derived {new_axiom} from {axiom1} and {axiom2}") 137 | closure_set.update(new_axioms) 138 | print("Closure computation complete.\n") 139 | return TBox(closure_set), derivation 140 | 141 | def entails(self, query): 142 | normalized_tbox = self.normalize() 143 | closure_tbox, derivation = normalized_tbox.closure() 144 | if query in closure_tbox.axioms: 145 | return True, derivation 146 | return False, derivation 147 | 148 | def __repr__(self): 149 | return "\n".join(str(axiom) for axiom in self.axioms) 150 | 151 | # Utility function to print the derivation process 152 | def print_derivation(derivation): 153 | print("\nDerivation Process:") 154 | for step in derivation: 155 | axiom1, axiom2, result = step 156 | print(f"From {axiom1} and {axiom2}, derive {result}") 157 | 158 | # Define concepts 159 | A = Concept("A") 160 | B = Concept("B") 161 | C = Concept("C") 162 | D = Concept("D") 163 | top = Concept("⊤") 164 | 165 | # Define roles 166 | r = Role("r") 167 | s = Role("s") 168 | 169 | # Define TBox 170 | tbox = TBox({ 171 | Subsumption(A, Conjunction(B, Existential(r, C))), 172 | Subsumption(C, Existential(s, D)), 173 | Subsumption(Conjunction(Existential(r, Existential(s, top)), B), D) 174 | }) 175 | 176 | # Print TBox 177 | print(f"TBox:\n{tbox}") 178 | 179 | # Define the query 180 | query = Subsumption(A, B) 181 | print(f"\nQuery: {query}\n") 182 | 183 | # Check entailment 184 | entails, derivation = tbox.entails(query) 185 | 186 | print(f"Entailment: {entails}") 187 | if entails: 188 | print_derivation(derivation) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 应用逻辑 -------------------------------------------------------------------------------- /Rationals/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -std=c++11 3 | 4 | SRCS := main.cpp 5 | 6 | 7 | OBJS := ${SRCS:cpp=o} 8 | PROGS := ${SRCS:.cpp=} 9 | 10 | .PHONY: all 11 | all: ${PROGS} 12 | 13 | ${PROGS} : % : %.o Makefile 14 | ${CXX} $< -o $@ ${LIBS} 15 | 16 | clean: 17 | rm -f ${PROGS} ${OBJS} 18 | 19 | %.o: %.cpp Makefile 20 | ${CXX} ${CXXFLAGS} -c $< -------------------------------------------------------------------------------- /Rationals/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | class RationalNumber { 9 | public: 10 | RationalNumber(int numerator, int denominator, int symbol = 1) : num(numerator), den(denominator), symbol(symbol) {} 11 | 12 | // Function to simplify the rational number 13 | RationalNumber simplify() { 14 | int gcdVal = gcd(num, den); 15 | int new_num = num / gcdVal; 16 | int new_den = den / gcdVal; 17 | return RationalNumber(new_num, new_den); 18 | } 19 | 20 | // Function to get the next rational number 21 | RationalNumber next() const { 22 | if (num < den) { 23 | return RationalNumber(num + 1, den); 24 | } else { 25 | return RationalNumber(1, den + 1); 26 | } 27 | } 28 | 29 | // Overloading the < operator for comparing rational numbers 30 | bool operator<(const RationalNumber& other) const { 31 | return symbol * num * other.den < other.symbol * other.num * den; 32 | } 33 | 34 | // Overloading the == operator for checking equality of rational numbers 35 | bool operator==(const RationalNumber& other) const { 36 | return symbol * num * other.den == other.symbol * other.num * den; 37 | } 38 | 39 | // Overloading the << operator for printing 40 | friend ostream& operator<<(ostream& os, const RationalNumber& rational) { 41 | if (rational.symbol == -1) os << "-"; 42 | os << rational.num << "/" << rational.den; 43 | return os; 44 | } 45 | 46 | void set_symbol(int s) { 47 | symbol = s; 48 | } 49 | 50 | private: 51 | int num; // numerator 52 | int den; // denominator, den != 0 53 | int symbol; // 1 for positive, -1 for negative 54 | 55 | // Function to calculate the greatest common divisor 56 | int gcd(int a, int b) { 57 | while (b != 0) { 58 | int temp = b; 59 | b = a % b; 60 | a = temp; 61 | } 62 | return a; 63 | } 64 | }; 65 | 66 | // use the set to remove redundant rationals 67 | set generateRationals(int N) { 68 | set rationals; 69 | RationalNumber cur = RationalNumber(0, 1); 70 | rationals.insert(cur.simplify()); 71 | while (rationals.size() < N) { 72 | cur = cur.next(); 73 | RationalNumber temp = cur.simplify(); 74 | rationals.insert(temp); 75 | 76 | if (rationals.size() >= N) break; 77 | 78 | // get its opposite 79 | temp.set_symbol(-1); 80 | rationals.insert(temp); 81 | } 82 | return rationals; 83 | } 84 | 85 | int main(int argc, char* argv[]) { 86 | if (argc > 2 || (argc == 2 && atoi(argv[1]) <= 0)) { 87 | cout << "Usage: " << argv[0] << " [number_of_rationals]" << endl; 88 | return 1; 89 | } 90 | int N = argc == 2 ? atoi(argv[1]) : 20; // default 20 rationals 91 | 92 | set rationals = generateRationals(N); 93 | cout << "First " << N << " rationals: [ "; 94 | for (auto rational : rationals) { 95 | cout << rational << ", "; 96 | } 97 | cout << "\b\b ]" << endl; 98 | return 0; 99 | } --------------------------------------------------------------------------------