catlogic 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +36 -0
  9. data/Rakefile +7 -0
  10. data/bin2/.idea/.name +1 -0
  11. data/bin2/.idea/bin.iml +9 -0
  12. data/bin2/.idea/encodings.xml +5 -0
  13. data/bin2/.idea/misc.xml +5 -0
  14. data/bin2/.idea/modules.xml +9 -0
  15. data/bin2/.idea/scopes/scope_settings.xml +5 -0
  16. data/bin2/.idea/vcs.xml +7 -0
  17. data/bin2/.idea/workspace.xml +129 -0
  18. data/bin2/displayInferredTruths.rb +43 -0
  19. data/bin2/getAllValidPropositions.rb +24 -0
  20. data/bin2/testCombineSets.rb +27 -0
  21. data/bin2/testIfUnique.rb +14 -0
  22. data/bin2/testPremisePair.rb +10 -0
  23. data/bin2/testProposition.rb +47 -0
  24. data/bin2/testPropositionType.rb +40 -0
  25. data/bin2/testQuantity.rb +12 -0
  26. data/bin2/testReduceToUniqueSet.rb +18 -0
  27. data/bin2/testSyllogism.rb +45 -0
  28. data/bin2/testSyllogismForm.rb +51 -0
  29. data/catlogic.gemspec +25 -0
  30. data/lib/catlogic/distribution.rb +16 -0
  31. data/lib/catlogic/figure.rb +45 -0
  32. data/lib/catlogic/form.rb +22 -0
  33. data/lib/catlogic/mood.rb +14 -0
  34. data/lib/catlogic/premise_collection.rb +211 -0
  35. data/lib/catlogic/premise_pair.rb +61 -0
  36. data/lib/catlogic/proposition.rb +181 -0
  37. data/lib/catlogic/proposition_type.rb +47 -0
  38. data/lib/catlogic/quality.rb +16 -0
  39. data/lib/catlogic/quantity.rb +16 -0
  40. data/lib/catlogic/syllogism.rb +171 -0
  41. data/lib/catlogic/term.rb +32 -0
  42. data/lib/catlogic/version.rb +3 -0
  43. data/lib/catlogic.rb +17 -0
  44. data/spec/distribution_spec.rb +26 -0
  45. data/spec/figure_spec.rb +27 -0
  46. data/spec/form_spec.rb +22 -0
  47. data/spec/mood_spec.rb +17 -0
  48. data/spec/premise_pair_spec.rb +51 -0
  49. data/spec/proposition_spec.rb +215 -0
  50. data/spec/proposition_type_spec.rb +37 -0
  51. data/spec/quality_spec.rb +17 -0
  52. data/spec/quantity_spec.rb +19 -0
  53. data/spec/spec_helper.rb +89 -0
  54. data/spec/syllogism_spec.rb +121 -0
  55. data/spec/term_spec.rb +35 -0
  56. metadata +166 -0
data/catlogic.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'catlogic/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "catlogic"
8
+ spec.version = Catlogic::VERSION
9
+ spec.authors = ["Jeffrey C. Witt"]
10
+ spec.email = ["jeffreycwitt@gmail.com"]
11
+ spec.summary = %q{A gem for building categorial propositions and syllogisms}
12
+ spec.description = %q{A gem for building categorial propositions and syllogisms}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency 'rspec'
24
+ spec.add_development_dependency 'pry'
25
+ end
@@ -0,0 +1,16 @@
1
+ class Distribution
2
+ attr_reader :label
3
+
4
+ def initialize(distribution)
5
+ @label = distribution
6
+ end
7
+
8
+ def opposite
9
+ if self.label == 'distributed'
10
+ opposite = Distribution.new('undistributed')
11
+ elsif self.label == 'undistributed'
12
+ opposite = Distribution.new('distributed')
13
+ end
14
+ return opposite
15
+ end
16
+ end
@@ -0,0 +1,45 @@
1
+ class Figure
2
+ attr_reader :label
3
+
4
+ def initialize(figure)
5
+ @label = figure
6
+ end
7
+
8
+
9
+ def major_subject
10
+ if @label == 1 || @label == 3
11
+ subject = Term.new('M')
12
+
13
+ elsif @label == 2 || @label == 4
14
+ subject = Term.new('P')
15
+ end
16
+ return subject
17
+ end
18
+
19
+ def major_predicate
20
+ if @label == 1 || @label == 3
21
+ predicate = Term.new("P")
22
+ elsif @label == 2 || @label == 4
23
+ predicate = Term.new("M")
24
+ end
25
+ return predicate
26
+ end
27
+ def minor_subject
28
+ if @label == 1 || @label == 2
29
+ subject = Term.new("S")
30
+
31
+ elsif @label == 3 || @label == 4
32
+ subject = Term.new("M")
33
+
34
+ end
35
+ return subject
36
+ end
37
+ def minor_predicate
38
+ if @label == 1 || @label == 2
39
+ predicate = Term.new("M")
40
+ elsif @label == 3 || @label == 4
41
+ predicate = Term.new("S")
42
+ end
43
+ return predicate
44
+ end
45
+ end
@@ -0,0 +1,22 @@
1
+ class Form
2
+ attr_reader :mood, :figure, :label
3
+ # takes three Mood Object and Figure Object
4
+ def initialize(mood, figure)
5
+ @mood = mood
6
+ @figure = figure
7
+ @label = "#{@mood.label}#{@figure.label}"
8
+ end
9
+ def syllogism
10
+ majorproposition = Proposition.new(@mood.majortype.quantity, @figure.major_subject, @mood.majortype.quality, @figure.major_predicate, true)
11
+ minorproposition = Proposition.new(@mood.minortype.quantity, @figure.minor_subject, @mood.minortype.quality, @figure.minor_predicate, true)
12
+ conclusion = Proposition.new(@mood.conclusiontype.quantity, Term.new("S"), @mood.conclusiontype.quality, Term.new("P"), true)
13
+
14
+ syllogism = Syllogism.new(majorproposition, minorproposition, conclusion)
15
+
16
+ return syllogism
17
+ end
18
+ def validity
19
+ syllogism = self.syllogism
20
+ syllogism.validity
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ class Mood
2
+ attr_reader :majortype, :minortype, :conclusiontype
3
+
4
+ # takes three propositionType objects
5
+ def initialize(majortype, minortype, conclusiontype)
6
+ @majortype = majortype
7
+ @minortype = minortype
8
+ @conclusiontype = conclusiontype
9
+ end
10
+
11
+ def label
12
+ "#{@majortype.label}#{@minortype.label}#{@conclusiontype.label}"
13
+ end
14
+ end
@@ -0,0 +1,211 @@
1
+ class PremiseCollection
2
+ def initialize(propositionarray)
3
+ @collection = propositionarray
4
+ end
5
+
6
+ def getAllValidSyllogisms
7
+
8
+ if @collection.count < 2
9
+ puts "collection must include two or more propositions"
10
+ else
11
+ #inputconclusions = @collection
12
+ validsyllogisms = []
13
+ pairs = []
14
+
15
+ @collection.each do |proposition|
16
+
17
+ @collection.each do |secondproposition|
18
+ unless proposition.equal? secondproposition
19
+ pairs << PremisePair.new(proposition, secondproposition)
20
+ end
21
+ end
22
+ end
23
+ pairs.each do |pair|
24
+ if pair.isThreeTermPair?
25
+ conclusions = pair.getPossibleConclusions
26
+ conclusions.each do |conclusion|
27
+ syllogism = Syllogism.new(pair.getMajor, pair.getMinor, conclusion)
28
+ if syllogism.validity == "valid"
29
+ validsyllogisms << syllogism
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ return validsyllogisms
36
+ end
37
+
38
+ def getUniqueValidSyllogisms
39
+ inputconclusions = @collection
40
+ validsyllogisms = self.getAllValidSyllogisms
41
+ uniquevalidsyllogisms = []
42
+
43
+ validsyllogisms.each do |syllogism|
44
+ validconclusion = syllogism.getConclusion
45
+ if (validconclusion.isUnique?(inputconclusions))
46
+ uniquevalidsyllogisms << syllogism
47
+ end
48
+ end
49
+ return uniquevalidsyllogisms
50
+ end
51
+
52
+ =begin
53
+ def getUniqueInferredTruths
54
+
55
+ uniquevalidsyllogisms = self.getUniqueValidSyllogisms
56
+ uniqueinferredtruths = []
57
+
58
+ uniquevalidsyllogisms.each do |syllogism|
59
+ uniqueinferredtruths << syllogism.getConclusion
60
+ end
61
+
62
+ return uniqueinferredtruths
63
+ end
64
+ =end
65
+
66
+ def getAllInferredTruths
67
+ inputconclusions = @collection
68
+ inferredconclusions = []
69
+
70
+ validsyllogisms = self.getAllValidSyllogisms
71
+ validsyllogisms.each do |syllogism|
72
+ validconclusion = syllogism.getConclusion
73
+
74
+ if (validconclusion.isUnique?(inputconclusions))
75
+ inferredconclusions << validconclusion
76
+ end
77
+ end
78
+ return inferredconclusions
79
+ end
80
+
81
+
82
+ def getUniqueInferredTruths
83
+ newset = PremiseCollection.new(self.getAllInferredTruths)
84
+ unique_inferredconclusions = newset.reduceToUniqueSet
85
+ return unique_inferredconclusions
86
+ end
87
+
88
+
89
+
90
+ def displayLoopedInferredTruths
91
+
92
+ #get first set of inferences from initial collection set
93
+ inferredtruths = self.getUniqueInferredTruths
94
+ #combine with existing - on first interation will be comined with empty array
95
+ combinedset = self.combineSets(inferredtruths)
96
+
97
+ puts "======================="
98
+ puts "first set of inferences"
99
+ puts inferredtruths.count
100
+ puts "======================="
101
+
102
+
103
+ self.displayAllValidSyllogisms
104
+ self.displayUniqueSyllogisms
105
+ self.displayInferredTruths
106
+
107
+
108
+ while (inferredtruths.count != 0)
109
+
110
+ ## create new collection object
111
+ newcollection = PremiseCollection.new(combinedset)
112
+
113
+ ## get next set of inferences
114
+
115
+ #reset inferred truths
116
+ inferredtruths = newcollection.getUniqueInferredTruths
117
+ #rest combined set
118
+ combinedset = newcollection.combineSets(inferredtruths)
119
+
120
+ puts "======================="
121
+ puts "next set of inferences"
122
+ puts inferredtruths.count
123
+ puts "======================="
124
+
125
+ #display inferred set
126
+ newcollection.displayAllValidSyllogisms
127
+ newcollection.displayUniqueSyllogisms
128
+ newcollection.displayInferredTruths
129
+
130
+ end
131
+ end
132
+
133
+
134
+ def combineSets(newset)
135
+ newcollection = []
136
+
137
+ newcollection << @collection
138
+ newcollection << newset
139
+
140
+
141
+ return newcollection.flatten
142
+ end
143
+
144
+
145
+
146
+ def reduceToUniqueSet
147
+ unique_knownconclusions = []
148
+
149
+ @collection.each do |conclusion|
150
+ if unique_knownconclusions.count == 0
151
+ unique_knownconclusions << conclusion
152
+ elsif conclusion.isUnique?(unique_knownconclusions)
153
+ unique_knownconclusions << conclusion
154
+ end
155
+
156
+
157
+ end
158
+ return unique_knownconclusions
159
+ end
160
+
161
+ def displayInferredTruths
162
+ truths = self.getUniqueInferredTruths
163
+ puts
164
+ puts "==== Begin Display All Unique Inferred Truths ==="
165
+ truths.each do |truth|
166
+ truth.displayProposition
167
+ end
168
+ puts "==== End Display All Unique Inferred Truths ==="
169
+ puts
170
+
171
+ end
172
+
173
+ def displayAllValidSyllogisms
174
+ puts
175
+ puts "====== Begin Display All Valid Syllogisms==="
176
+ allvalidsyllogisms = self.getAllValidSyllogisms
177
+ allvalidsyllogisms.each do |syllogism|
178
+ syllogism.displayForm
179
+ syllogism.displaySyllogism
180
+ puts
181
+ end
182
+ puts "======End All Vallid Syllogisms==="
183
+ puts
184
+ end
185
+
186
+ def displayUniqueSyllogisms
187
+
188
+ puts
189
+ puts "======Begin Display All Syllogism Producing new truths==="
190
+ uniquevalidsyllogisms = self.getUniqueValidSyllogisms
191
+ uniquevalidsyllogisms.each do |syllogism|
192
+ syllogism.displayForm
193
+ syllogism.displaySyllogism
194
+ puts
195
+ end
196
+ puts "======End Display All Syllogism Producing new truths==="
197
+ puts
198
+
199
+ end
200
+
201
+
202
+ def getNumberOfInferredTruths
203
+ self.getUniqueInferredTruths.count
204
+ end
205
+ def getNumberOfInputTruths
206
+ @collection.count
207
+ end
208
+ def getRatioInputToInferred
209
+ self.getNumberOfInferredTruths / self.getNumberOfInputTruths
210
+ end
211
+ end
@@ -0,0 +1,61 @@
1
+ class PremisePair
2
+
3
+ attr_reader :major, :minor
4
+
5
+ def initialize(major, minor)
6
+ @major = major
7
+ @minor = minor
8
+ end
9
+
10
+ def middle
11
+ termarray = [@major.subject.label, @major.predicate.label, @minor.subject.label, @minor.predicate.label]
12
+ middle = nil
13
+ if self.three_term_pair?
14
+ termarray.detect do |term|
15
+ if termarray.count(term) == 2
16
+ middle = Term.new(term)
17
+ end
18
+ end
19
+ else
20
+ middle = "Error: this is not a three term syllogism"
21
+ end
22
+ return middle
23
+ end
24
+
25
+ def three_term_pair?
26
+ termarray = [@major.subject.label, @major.predicate.label, @minor.subject.label, @minor.predicate.label]
27
+ if termarray.uniq.size == 3
28
+ answer = true
29
+ else
30
+ answer = false
31
+ end
32
+ end
33
+
34
+ def majorterm
35
+ if @major.subject.label == self.middle.label
36
+ majorterm = @major.predicate
37
+ else
38
+ majorterm = @major.subject
39
+ end
40
+ majorterm
41
+ end
42
+ def minorterm
43
+ if @minor.subject.label == self.middle.label
44
+ minorterm = @minor.predicate
45
+ else
46
+ minorterm = @minor.subject
47
+ end
48
+ minorterm
49
+ end
50
+
51
+ # still need a test for this
52
+ def possible_conclusions
53
+ @possible_conclusions = [
54
+ Proposition.new(Quantity.new("universal"), self.minor, Quality.new("affirmative"), self.minor, true),
55
+ Proposition.new(Quantity.new("universal"), self.minor, Quality.new("negative"), self.minor, true),
56
+ Proposition.new(Quantity.new("particular"), self.minor, Quality.new("affirmative"), self.minor, true),
57
+ Proposition.new(Quantity.new("particular"), self.minor, Quality.new("negative"), self.minor, true)
58
+ ]
59
+ end
60
+
61
+ end
@@ -0,0 +1,181 @@
1
+ class Proposition
2
+
3
+ attr_reader :quantity, :subject, :quality, :predicate, :truthvalue
4
+
5
+ def initialize(quantity, subject, quality, predicate, truthvalue)
6
+ @quantity=quantity
7
+ @subject=subject
8
+ @quality=quality
9
+ @predicate=predicate
10
+ @truthvalue=truthvalue
11
+ end
12
+
13
+ def type
14
+ if @quantity.label == 'universal' && @quality.label == 'affirmative'
15
+ @type=PropositionType.new("A")
16
+ elsif @quantity.label == 'universal' && @quality.label == 'negative'
17
+ @type=PropositionType.new("E")
18
+ elsif @quantity.label == 'particular' && @quality.label == 'affirmative'
19
+ @type=PropositionType.new("I")
20
+ elsif @quantity.label == 'particular' && @quality.label == 'negative'
21
+ @type=PropositionType.new("O")
22
+ end
23
+ return @type
24
+ end
25
+
26
+ def contradictory
27
+
28
+ quantity = @quantity.opposite
29
+ quality = @quality.opposite
30
+
31
+ @contradictory = Proposition.new(quantity, @subject, quality, @predicate, !@truthvalue)
32
+ return @contradictory
33
+ end
34
+
35
+ def subaltern
36
+
37
+ quantity = @quantity.opposite
38
+
39
+ if @quantity.label == "universal"
40
+ if @truthvalue
41
+ truthvalue = @truthvalue
42
+ elsif !@truthvalue
43
+ truthvalue = "unknown"
44
+ end
45
+ elsif @quantity.label == "particular"
46
+ if !@truthvalue
47
+ truthvalue = !@truthvalue
48
+ elsif @truthvalue
49
+ truthvalue = "unknown"
50
+ end
51
+ end
52
+
53
+ @subaltern = Proposition.new(quantity, @subject, @quality, @predicate, truthvalue)
54
+ return @subaltern
55
+ end
56
+
57
+ def contrary
58
+ if @quantity.label == "particular"
59
+ abort("There is no contrary for this type of propostion. Try subcontrary")
60
+ end
61
+ quality = @quality.opposite
62
+
63
+ if @truthvalue
64
+ truthvalue = !@truthvalue
65
+ elsif !@truthvalue
66
+ truthvalue = "unknown"
67
+ end
68
+
69
+ contrary = Proposition.new(@quantity, @subject, quality, @predicate, truthvalue)
70
+ return contrary
71
+ end
72
+
73
+ def subcontrary
74
+ if @quantity.label == "universal"
75
+ abort("There is no subcontrary for this type of propostion. Try contrary.")
76
+ end
77
+
78
+ quality = @quality.opposite
79
+
80
+ if !@truthvalue
81
+ truthvalue = !@truthvalue
82
+ elsif @truthvalue
83
+ truthvalue = "unknown"
84
+ end
85
+
86
+ subcontrary = Proposition.new(@quantity, @subject, quality, @predicate, truthvalue)
87
+ return subcontrary
88
+ end
89
+
90
+ def converse
91
+ if self.type.label == "A" || self.type.label == "O"
92
+ truthvalue = "unknown"
93
+ else
94
+ truthvalue = @truthvalue
95
+ end
96
+ @converse = Proposition.new(@quantity, @predicate, @quality, @subject, truthvalue)
97
+ end
98
+
99
+ def obverse
100
+ quality = @quality.opposite
101
+
102
+ predicate = @predicate.opposite
103
+ @obverse = Proposition.new(@quantity, @subject, quality, predicate, @truthvalue)
104
+ end
105
+
106
+ def contrapolated
107
+ if self.type.label == "E" || self.type.label == "I"
108
+ truthvalue = "unknown"
109
+ else
110
+ truthvalue = @truthvalue
111
+ end
112
+ subject = @subject.opposite
113
+ predicate = @predicate.opposite
114
+
115
+ @contrapolated = Proposition.new(@quantity, predicate, @quality, subject, truthvalue)
116
+
117
+ end
118
+
119
+ def position_of_term(term)
120
+ if self.subject.label == term.label
121
+ @positionofmiddle = 'subject'
122
+ elsif self.predicate.label == term.label
123
+ @positionofmiddle = 'predicate'
124
+ end
125
+ return @positionofmiddle
126
+ end
127
+
128
+ def label
129
+ if @quantity.label == "universal"
130
+ if @quality.label == "affirmative"
131
+ display_quantity = "All"
132
+ display_quality = "are"
133
+ elsif @quality.label == "negative"
134
+ display_quantity = "No"
135
+ display_quality = "are"
136
+ end
137
+ elsif @quantity.label == "particular"
138
+ if @quality.label == "affirmative"
139
+ display_quantity = "Some"
140
+ display_quality = "are"
141
+ elsif @quality.label == "negative"
142
+ display_quantity = "Some"
143
+ display_quality = "are not"
144
+ end
145
+ end
146
+ "#{display_quantity} #{@subject.label} #{display_quality} #{@predicate.label}"
147
+ end
148
+
149
+ def distribution(position)
150
+ if position == 'subject'
151
+ distribution = @subject.distribution_subject(@quantity)
152
+ elsif position == 'predicate'
153
+ distribution = @predicate.distribution_predicate(@quality)
154
+ end
155
+ return distribution
156
+ end
157
+
158
+ def unique?(set)
159
+ numerofoccurences = self.number_of_occurences(set)
160
+ if numerofoccurences == 0
161
+ true
162
+ else
163
+ false
164
+ end
165
+ end
166
+
167
+ def number_of_occurences(set)
168
+ @occurences = 0
169
+ set.each do |proposition|
170
+ if (proposition.quantity.label == self.quantity.label &&
171
+ proposition.subject.label == self.subject.label &&
172
+ proposition.quality.label == self.quality.label &&
173
+ proposition.predicate.label == self.predicate.label &&
174
+ proposition.truthvalue == self.truthvalue)
175
+ @occurences += 1
176
+ end
177
+ end
178
+ @occurences
179
+ end
180
+
181
+ end
@@ -0,0 +1,47 @@
1
+ class PropositionType
2
+
3
+ attr_reader :label, :truthvalue
4
+
5
+ def initialize(type, truthvalue=true)
6
+ @type = type
7
+ @label = type
8
+ @truthvalue = truthvalue
9
+ end
10
+ def getType
11
+ @type
12
+ end
13
+
14
+ def quantity
15
+ if @label == "A"
16
+ quantity = Quantity.new("universal")
17
+ elsif @label == "E"
18
+ quantity = Quantity.new("universal")
19
+ elsif @label == "I"
20
+ quantity = Quantity.new("particular")
21
+ elsif @label == "O"
22
+ quantity = Quantity.new("particular")
23
+ else
24
+ quantity = "not a valid type"
25
+ end
26
+ return quantity
27
+ end
28
+ def quality
29
+ if @label == "A"
30
+ quality = Quality.new("affirmative")
31
+ elsif @label == "E"
32
+ quality = Quality.new("negative")
33
+ elsif @label == "I"
34
+ quality = Quality.new("affirmative")
35
+ elsif @label == "O"
36
+ quality = Quality.new("negative")
37
+ else
38
+ quality = "not a valid type"
39
+ end
40
+ return quality
41
+ end
42
+
43
+ def proposition
44
+ proposition = Proposition.new(Quantity.new(self.quantity.label), Term.new("S"), Quality.new(self.quality.label), Term.new("P"), @truthvalue)
45
+ return proposition
46
+ end
47
+ end
@@ -0,0 +1,16 @@
1
+ class Quality
2
+ attr_reader :label
3
+
4
+ def initialize(quality)
5
+ @label = quality
6
+ end
7
+
8
+ def opposite
9
+ if self.label == 'negative'
10
+ qualityopposite = Quality.new('affirmative')
11
+ elsif self.label == 'affirmative'
12
+ qualityopposite = Quality.new('negative')
13
+ end
14
+ return qualityopposite
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ class Quantity
2
+ attr_reader :label
3
+
4
+ def initialize(quantity)
5
+ @label = quantity
6
+ end
7
+
8
+ def opposite
9
+ if self.label == 'universal'
10
+ quantityopposite = Quantity.new('particular')
11
+ elsif self.label == 'particular'
12
+ quantityopposite = Quantity.new('universal')
13
+ end
14
+ return quantityopposite
15
+ end
16
+ end