abst_int 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +22 -0
- data/.pryrc +18 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +34 -0
- data/Rakefile +12 -0
- data/abst_int.gemspec +26 -0
- data/lib/abst_int.rb +83 -0
- data/lib/abst_int/calculus_model/dfa.rb +287 -0
- data/lib/abst_int/calculus_model/nfa.rb +81 -0
- data/lib/abst_int/collection.rb +32 -0
- data/lib/abst_int/integer.rb +35 -0
- data/lib/abst_int/or_set.rb +105 -0
- data/lib/abst_int/set.rb +136 -0
- data/lib/abst_int/term.rb +125 -0
- data/lib/abst_int/variable.rb +18 -0
- data/lib/abst_int/version.rb +3 -0
- data/lib/fixnum.rb +10 -0
- data/spec/abst_int_spec.rb +37 -0
- data/spec/spec_helper.rb +94 -0
- metadata +141 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
require "set"
|
2
|
+
require "abst_int/calculus_model/dfa"
|
3
|
+
|
4
|
+
module AbstInt::CalculusModel
|
5
|
+
class Nfa
|
6
|
+
def initialize
|
7
|
+
@states = Set.new
|
8
|
+
@initial_states = Set.new
|
9
|
+
@final_states = Set.new
|
10
|
+
@inputs = Set.new
|
11
|
+
@transition = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_initial state
|
15
|
+
@states << state
|
16
|
+
@initial_states << state
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_final state
|
20
|
+
@states << state
|
21
|
+
@final_states << state
|
22
|
+
end
|
23
|
+
|
24
|
+
# [state] 1,2,3
|
25
|
+
# [input] 'a', 'b', 'c'
|
26
|
+
def add_trans state1, input, state2
|
27
|
+
@states << state1 << state2
|
28
|
+
@inputs << input
|
29
|
+
@transition[state1] ||= {}
|
30
|
+
@transition[state1][input] ||= Set.new
|
31
|
+
@transition[state1][input] << state2
|
32
|
+
end
|
33
|
+
|
34
|
+
def exists_initial?
|
35
|
+
not @initial_states.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_dfa
|
39
|
+
dfa = AbstInt::CalculusModel::Dfa.new
|
40
|
+
dfa.set_initial @initial_states
|
41
|
+
dfa = generate_dfa dfa, @initial_states, Set.new
|
42
|
+
dfa.each_states do |states|
|
43
|
+
dfa.add_final states unless (states & @final_states).empty?
|
44
|
+
end
|
45
|
+
return dfa
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
puts "[states]"
|
50
|
+
@states.each {|state| puts "#{state.is_a?(Array) ? state.map(&:to_s) : state}, " }
|
51
|
+
puts "[initial_states]"
|
52
|
+
@initial_states.each {|state| puts "#{state.is_a?(Array) ? state.map(&:to_s) : state}, " }
|
53
|
+
puts "[final_states]"
|
54
|
+
@final_states.each {|state| puts "#{state.is_a?(Array) ? state.map(&:to_s) : state}, " }
|
55
|
+
puts "[inputs]"
|
56
|
+
@inputs.each {|input| puts "#{input}, " }
|
57
|
+
puts "[transition]"
|
58
|
+
@transition.each do |state1, value|
|
59
|
+
value.each do |input, value|
|
60
|
+
value.each do |state2|
|
61
|
+
puts "#{state1.is_a?(Array) ? state1.map(&:to_s) : state1}, #{input}, #{state2.is_a?(Array) ? state2.map(&:to_s) : state2}"
|
62
|
+
end if value
|
63
|
+
end if value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
def generate_dfa dfa, states, state_setset
|
69
|
+
return dfa if state_setset.include? states
|
70
|
+
old_dfa = dfa.dup
|
71
|
+
@inputs.each do |input|
|
72
|
+
next_states = states.inject(Set.new) do |result, state|
|
73
|
+
@transition.try(:[], state).try(:[], input) ? result + (@transition[state][input]) : result
|
74
|
+
end
|
75
|
+
dfa.add_trans states, input, next_states
|
76
|
+
dfa = generate_dfa dfa, next_states, (state_setset << states)
|
77
|
+
end
|
78
|
+
return dfa
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class AbstInt::Collection < BasicObject
|
2
|
+
class NilClass
|
3
|
+
end
|
4
|
+
|
5
|
+
def initialize args
|
6
|
+
@objects = args
|
7
|
+
end
|
8
|
+
|
9
|
+
def == *args
|
10
|
+
self.method_missing :==, *args
|
11
|
+
end
|
12
|
+
|
13
|
+
def != *args
|
14
|
+
self.method_missing :"!=", *args
|
15
|
+
end
|
16
|
+
|
17
|
+
def equal? *args
|
18
|
+
self.method_missing :equal?, *args
|
19
|
+
end
|
20
|
+
|
21
|
+
def method_missing method_name, *args
|
22
|
+
result = ::AbstInt::Collection::NilClass.new
|
23
|
+
@objects.each do |object|
|
24
|
+
if result.is_a? ::AbstInt::Collection::NilClass
|
25
|
+
result = object.send(method_name, *args)
|
26
|
+
else
|
27
|
+
raise ::AbstInt::MultiResultError, "There are more results than one." unless result == object.send(method_name, *args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
return result
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "abst_int"
|
2
|
+
|
3
|
+
class AbstInt::Integer
|
4
|
+
def initialize abst_int
|
5
|
+
@abst_int = abst_int
|
6
|
+
end
|
7
|
+
|
8
|
+
def + abst_int_or_int
|
9
|
+
@abst_int + abst_int_or_int
|
10
|
+
end
|
11
|
+
|
12
|
+
def - abst_int_or_int
|
13
|
+
@abst_int - abst_int_or_int
|
14
|
+
end
|
15
|
+
|
16
|
+
def * abst_int_or_int
|
17
|
+
@abst_int * abst_int_or_int
|
18
|
+
end
|
19
|
+
|
20
|
+
def / abst_int_or_int
|
21
|
+
@abst_int / abst_int_or_int
|
22
|
+
end
|
23
|
+
|
24
|
+
def % num
|
25
|
+
@abst_int % num
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
@abst_int.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def _terms
|
33
|
+
@abst_int.terms
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require "abst_int/set"
|
2
|
+
require "abst_int/calculus_model/nfa"
|
3
|
+
require "abst_int/collection"
|
4
|
+
|
5
|
+
class AbstInt::OrSet
|
6
|
+
def initialize coefficient = nil, be_variable = false
|
7
|
+
@elements = []
|
8
|
+
if coefficient.is_a? Fixnum
|
9
|
+
self << (AbstInt::Set.new coefficient, be_variable)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def + orset
|
14
|
+
return self if orset.nil?
|
15
|
+
new_orset = AbstInt::OrSet.new
|
16
|
+
orset.each do |set1|
|
17
|
+
self.each do |set2|
|
18
|
+
new_orset << (set1 + set2)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
return new_orset
|
22
|
+
end
|
23
|
+
|
24
|
+
def - orset
|
25
|
+
self + orset * AbstInt::OrSet.new(-1)
|
26
|
+
end
|
27
|
+
|
28
|
+
def * orset
|
29
|
+
new_orset = AbstInt::OrSet.new
|
30
|
+
orset.each do |set1|
|
31
|
+
self.each do |set2|
|
32
|
+
new_orset << (set1 * set2)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
return new_orset
|
36
|
+
end
|
37
|
+
|
38
|
+
def % num
|
39
|
+
current_mod = []
|
40
|
+
self.each do |set|
|
41
|
+
mod = set % num
|
42
|
+
current_mod << mod
|
43
|
+
end
|
44
|
+
return AbstInt::Collection.new(current_mod)
|
45
|
+
end
|
46
|
+
|
47
|
+
def | orset
|
48
|
+
return self if orset.is_a? NilClass
|
49
|
+
cloned_self = self.dup
|
50
|
+
orset.each do |set|
|
51
|
+
cloned_self << set
|
52
|
+
end
|
53
|
+
return cloned_self
|
54
|
+
end
|
55
|
+
|
56
|
+
def & orset
|
57
|
+
left_dfa = (self.to_nfa.to_dfa)
|
58
|
+
right_dfa = (orset.to_nfa.to_dfa)
|
59
|
+
result = left_dfa & right_dfa
|
60
|
+
result = result.to_orset
|
61
|
+
return result
|
62
|
+
end
|
63
|
+
|
64
|
+
def not
|
65
|
+
return self.to_nfa.to_dfa.not.to_orset
|
66
|
+
end
|
67
|
+
|
68
|
+
def star
|
69
|
+
new_orset = AbstInt::OrSet.new
|
70
|
+
self.each do |set|
|
71
|
+
new_orset << set.star
|
72
|
+
end
|
73
|
+
return new_orset
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s
|
77
|
+
@elements.map{|element| element.to_s}.join("|")
|
78
|
+
end
|
79
|
+
|
80
|
+
protected
|
81
|
+
def to_nfa
|
82
|
+
nfa = AbstInt::CalculusModel::Nfa.new
|
83
|
+
self.each do |set|
|
84
|
+
nfa = set.generate_nfa nfa
|
85
|
+
end
|
86
|
+
return nfa
|
87
|
+
end
|
88
|
+
|
89
|
+
def each &block
|
90
|
+
@elements.each(&block)
|
91
|
+
end
|
92
|
+
|
93
|
+
def << set
|
94
|
+
expanded = false
|
95
|
+
@elements.each { |self_set|
|
96
|
+
next if expanded
|
97
|
+
expanded_set = self_set.expand(set) || set.expand(self_set)
|
98
|
+
next if expanded_set.nil?
|
99
|
+
expanded = true
|
100
|
+
@elements = @elements - [self_set]
|
101
|
+
self << expanded_set
|
102
|
+
}
|
103
|
+
@elements << set unless expanded
|
104
|
+
end
|
105
|
+
end
|
data/lib/abst_int/set.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
require "abst_int/term"
|
2
|
+
require "abst_int/calculus_model/nfa"
|
3
|
+
|
4
|
+
class AbstInt::Set
|
5
|
+
def initialize coefficient = nil, be_variable = false
|
6
|
+
@elements = []
|
7
|
+
if coefficient.is_a? Fixnum
|
8
|
+
self << (AbstInt::Term.new coefficient, be_variable)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def + set
|
13
|
+
cloned_self = self.dup
|
14
|
+
set.each do |term|
|
15
|
+
cloned_self << term
|
16
|
+
end
|
17
|
+
return cloned_self
|
18
|
+
end
|
19
|
+
|
20
|
+
def - set
|
21
|
+
self + set * AbstInt::Set.new(-1)
|
22
|
+
end
|
23
|
+
|
24
|
+
def * set
|
25
|
+
result = AbstInt::Set.new
|
26
|
+
cloned_self = self.dup
|
27
|
+
cloned_self.each do |self_term|
|
28
|
+
set.each do |term|
|
29
|
+
result << (self_term * term)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
return result
|
33
|
+
end
|
34
|
+
|
35
|
+
def % num
|
36
|
+
@elements.inject(0){|result, term| [result, term % num].max }
|
37
|
+
end
|
38
|
+
|
39
|
+
def star
|
40
|
+
result = AbstInt::Set.new
|
41
|
+
self.each do |term|
|
42
|
+
result << term.star
|
43
|
+
end
|
44
|
+
return result
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
@elements.map{|element| element.to_s}.join("+")
|
49
|
+
end
|
50
|
+
|
51
|
+
def generate_nfa nfa
|
52
|
+
self.each do |term|
|
53
|
+
# 各termごとの設定
|
54
|
+
nfa = term.generate_nfa nfa, self
|
55
|
+
end
|
56
|
+
unless nfa.exists_initial?
|
57
|
+
nfa.add_initial self
|
58
|
+
nfa.add_final self
|
59
|
+
end
|
60
|
+
return nfa
|
61
|
+
end
|
62
|
+
|
63
|
+
def include? set
|
64
|
+
# setの変数に0を代入して計算
|
65
|
+
set_offset = set.calc 0
|
66
|
+
# その値がselfに含まれているか確認
|
67
|
+
input_string = set_offset < 0 ? "b" * (- set_offset) : "a" * set_offset
|
68
|
+
return false unless self.to_nfa.to_dfa.accept? input_string
|
69
|
+
# 含まれているならば、変数項の係数の包含関係をチェック
|
70
|
+
set.each do |term|
|
71
|
+
next unless term.variable_exists?
|
72
|
+
include_check = false
|
73
|
+
self.each do |self_term|
|
74
|
+
next unless self_term.variable_exists?
|
75
|
+
include_check = include_check || self_term.include?(term)
|
76
|
+
end
|
77
|
+
return false unless include_check
|
78
|
+
end
|
79
|
+
return true
|
80
|
+
end
|
81
|
+
|
82
|
+
def expand set
|
83
|
+
return self if self.include? set
|
84
|
+
return nil unless self.check_lank == 1 && set.check_lank == 0
|
85
|
+
set_offset = set.calc 0
|
86
|
+
if self.calc(-1) == set_offset
|
87
|
+
new_set = AbstInt::Set.new
|
88
|
+
new_set << AbstInt::Term.new(set_offset)
|
89
|
+
self.each do |term|
|
90
|
+
new_set << term if term.variable_exists?
|
91
|
+
end
|
92
|
+
return new_set
|
93
|
+
else
|
94
|
+
return nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def check_lank
|
99
|
+
lank = 0
|
100
|
+
self.each do |term|
|
101
|
+
lank += 1 if term.variable_exists?
|
102
|
+
end
|
103
|
+
return lank
|
104
|
+
end
|
105
|
+
|
106
|
+
protected
|
107
|
+
def each &block
|
108
|
+
@elements.each(&block)
|
109
|
+
end
|
110
|
+
|
111
|
+
def << term
|
112
|
+
new_elements = []
|
113
|
+
added_flag = false
|
114
|
+
@elements.each do |element|
|
115
|
+
if (element =~ term) && (not added_flag)
|
116
|
+
new_elements << (element + term)
|
117
|
+
added_flag = true
|
118
|
+
else
|
119
|
+
new_elements << element
|
120
|
+
end
|
121
|
+
end
|
122
|
+
new_elements << term unless added_flag
|
123
|
+
@elements = new_elements
|
124
|
+
return nil
|
125
|
+
end
|
126
|
+
|
127
|
+
def to_nfa
|
128
|
+
nfa = AbstInt::CalculusModel::Nfa.new
|
129
|
+
nfa = self.generate_nfa nfa
|
130
|
+
return nfa
|
131
|
+
end
|
132
|
+
|
133
|
+
def calc num
|
134
|
+
@elements.inject(0){|sum, x| sum + (x.calc num)}
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require "abst_int/variable"
|
2
|
+
|
3
|
+
class AbstInt::Term
|
4
|
+
|
5
|
+
def initialize coefficient = nil, be_variable = false
|
6
|
+
@coefficient = coefficient || 1
|
7
|
+
@variables = []
|
8
|
+
self << AbstInt::Variable.new if be_variable
|
9
|
+
end
|
10
|
+
|
11
|
+
def << variable
|
12
|
+
@variables << variable
|
13
|
+
@variables.sort!
|
14
|
+
end
|
15
|
+
|
16
|
+
# like terms check
|
17
|
+
def =~ term
|
18
|
+
return false unless @variables.length == term.variables.length
|
19
|
+
@variables.each_with_index do |variable, i|
|
20
|
+
return false unless variable.id == term.variables[i].id
|
21
|
+
end
|
22
|
+
return true
|
23
|
+
end
|
24
|
+
|
25
|
+
# collect like terms
|
26
|
+
def + term
|
27
|
+
raise "this is not like terms." unless self =~ term
|
28
|
+
cloned_term = self.clone
|
29
|
+
cloned_term.coefficient += term.coefficient
|
30
|
+
return cloned_term
|
31
|
+
end
|
32
|
+
|
33
|
+
def * abst_int_or_term
|
34
|
+
cloned_term = self.clone
|
35
|
+
term = abst_int_or_term
|
36
|
+
cloned_term.coefficient *= term.coefficient
|
37
|
+
term.variables.each do |variable|
|
38
|
+
cloned_term << variable
|
39
|
+
end
|
40
|
+
return cloned_term
|
41
|
+
end
|
42
|
+
|
43
|
+
def % num
|
44
|
+
if @variables.empty?
|
45
|
+
return (@coefficient % num)
|
46
|
+
else
|
47
|
+
raise AbstInt::MultiResultError, "There are more results than one." if @coefficient % num != 0
|
48
|
+
return 0
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def star
|
53
|
+
cloned_term = AbstInt::Term.new
|
54
|
+
cloned_term.coefficient = @coefficient
|
55
|
+
cloned_term.variables = @variables
|
56
|
+
cloned_term.variables = cloned_term.variables + [AbstInt::Variable.new] if @variables.empty? && @coefficient != 0
|
57
|
+
return cloned_term
|
58
|
+
end
|
59
|
+
|
60
|
+
def generate_nfa nfa, set
|
61
|
+
if @variables.empty?
|
62
|
+
if @coefficient == 0
|
63
|
+
elsif @coefficient < 0
|
64
|
+
nfa.add_initial [self, @coefficient]
|
65
|
+
nfa.add_final set
|
66
|
+
state_proc = proc { |x| (x == 0) ? set : [self, x] }
|
67
|
+
(@coefficient...0).each do |i|
|
68
|
+
nfa.add_trans state_proc.call(i), 'b', state_proc.call(i+1)
|
69
|
+
end
|
70
|
+
else
|
71
|
+
nfa.add_initial set
|
72
|
+
nfa.add_final [self, @coefficient]
|
73
|
+
state_proc = proc { |x| (x == 0) ? set : [self, x] }
|
74
|
+
(0...@coefficient).each do |i|
|
75
|
+
nfa.add_trans state_proc.call(i), 'a', state_proc.call(i+1)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
else
|
79
|
+
state_proc = proc { |x| (x == 0 || x == @coefficient) ? set : [self, x] }
|
80
|
+
alphabet = @coefficient < 0 ? 'b' : 'a'
|
81
|
+
unsigned_coefficient = @coefficient < 0 ? -@coefficient : @coefficient
|
82
|
+
@coefficient.times do |i|
|
83
|
+
nfa.add_trans state_proc.call(i), alphabet, state_proc.call(i+1)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
return nfa
|
87
|
+
end
|
88
|
+
|
89
|
+
# for debug
|
90
|
+
def to_s
|
91
|
+
"#{@coefficient}#{@variables.map{|var| var.to_s}.join}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def calc num
|
95
|
+
return @variables.empty? ? @coefficient : @coefficient * num
|
96
|
+
end
|
97
|
+
|
98
|
+
def variable_exists?
|
99
|
+
return not(@variables.empty?)
|
100
|
+
end
|
101
|
+
|
102
|
+
# 一旦、変数ありterm同士の包含比較
|
103
|
+
def include? term
|
104
|
+
return false unless self.variable_exists? && term.variable_exists?
|
105
|
+
return true if term.coefficient % self.coefficient == 0
|
106
|
+
return false
|
107
|
+
end
|
108
|
+
|
109
|
+
protected
|
110
|
+
def coefficient
|
111
|
+
@coefficient
|
112
|
+
end
|
113
|
+
|
114
|
+
def coefficient= coefficient
|
115
|
+
@coefficient = coefficient
|
116
|
+
end
|
117
|
+
|
118
|
+
def variables
|
119
|
+
@variables
|
120
|
+
end
|
121
|
+
|
122
|
+
def variables= variables
|
123
|
+
@variables = variables
|
124
|
+
end
|
125
|
+
end
|