logic_tools 0.2.4 → 0.3.0

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.
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ #########################################################################
3
+ # Simplifies a logic expression using the ESPRESSO algorithm #
4
+ #########################################################################
5
+
6
+
7
+ # For building logic trees
8
+ require "logic_tools/logictree.rb"
9
+
10
+ # For parsing the inputs
11
+ require "logic_tools/logicparse.rb"
12
+
13
+ # For simplifying with the ESPRESSO method.
14
+ require "logic_tools/logicsimplify_es.rb"
15
+
16
+ # For the command line interface
17
+ require "logic_tools/logicinput.rb"
18
+
19
+ include LogicTools
20
+
21
+
22
+
23
+
24
+
25
+ ############################
26
+ # The main program
27
+
28
+ # Iterrate on each expression
29
+ each_input do |expr|
30
+ # Parse the expression
31
+ parsed = string2logic(expr)
32
+
33
+ # Simplify it
34
+ simple = parsed.simplify
35
+ # print "Computation done\n"
36
+
37
+ # Display the result
38
+ print simple.to_s, "\n"
39
+ end
@@ -10,11 +10,8 @@ require "logic_tools/logictree.rb"
10
10
  # For parsing the inputs
11
11
  require "logic_tools/logicparse.rb"
12
12
 
13
- # For simplifying
14
- require "logic_tools/logicsimplify.rb"
15
-
16
- # For the command line interface
17
- require "logic_tools/logicinput.rb"
13
+ # For simplifying with the Quine Mc Cluskey method.
14
+ require "logic_tools/logicsimplify_qm.rb"
18
15
 
19
16
  # For the command line interface
20
17
  require "logic_tools/logicinput.rb"
@@ -28,19 +25,6 @@ include LogicTools
28
25
  ############################
29
26
  # The main program
30
27
 
31
- ## Now use the common command line interface
32
- # # First gets the expression to treat
33
- # $expr = nil
34
- # # Is it in the arguments?
35
- # unless $*.empty? then
36
- # # Yes, get the expression from them
37
- # $expr = $*.join
38
- # else
39
- # # Get the expression from standard input
40
- # print "Please enter your expression and end with ^D:\n"
41
- # $expr = ARGF.read
42
- # end
43
- #
44
28
 
45
29
  # Iterrate on each expression
46
30
  each_input do |expr|
@@ -0,0 +1,161 @@
1
+ ######################################################################
2
+ # The test program for logic tools #
3
+ # #
4
+ # NOTE: This still a very imcomplete work! #
5
+ ######################################################################
6
+
7
+ # require 'minitest/autorun'
8
+ require "logic_tools/logicsimplify_es.rb"
9
+ require "logic_tools/logicgenerator.rb"
10
+
11
+ include LogicTools
12
+
13
+ ## Class for testing the implementation of the ESPRESSO algorithm.
14
+ class TestEspresso # < MiniTest::Unit::TestCase
15
+
16
+ ## Creates the tester with a +seed+ for random generation, a
17
+ # +deadline+ for the simplify steps and a +volume+ before splitting
18
+ # the cover.
19
+ def initialize(seed = 0, deadline = Float::INFINITY,
20
+ volume = Float::INFINITY)
21
+ @seed = seed
22
+ @deadline = deadline
23
+ @volume = volume
24
+ end
25
+
26
+ ## Checks if a +cover+ is a tautology by generating its truth table.
27
+ def truth_tautology(cover)
28
+ ## Generate each possible input and test it on the cover.
29
+ (2**(cover.width)).times do |i|
30
+ return false unless cover.eval(i)
31
+ end
32
+ return true
33
+ end
34
+
35
+ ## Tests the tautology check on covers generated by a random +generator+.
36
+ #
37
+ # NOTE: ends when a tautology is actually found.
38
+ def test_tautology_random(generator)
39
+ # Create the cover.
40
+ cover = Cover.new(*generator.each_variable)
41
+ # Tautology results.
42
+ taut0, taut1 = false, false
43
+ # Add random cubes to the cover until a tautology is met while.
44
+ begin
45
+ # Add a random cube.
46
+ cover << generator.random_cube
47
+ print "Tautology check on cover=[#{cover.to_s}]...\n"
48
+ # Check if the cover is a tautology using the standard approach.
49
+ taut0 = cover.is_tautology?
50
+ print "Through is_tautology?: #{taut0}; "
51
+ # Check it again with a truth table.
52
+ taut1 = truth_tautology(cover)
53
+ print "through truth table: #{taut1}\n"
54
+ raise "Test failure" unless taut0 == taut1
55
+ end while (!taut0)
56
+ return true
57
+ end
58
+
59
+ ## Tests randomly +number+ tautology cases on a +dimensions+ boolean
60
+ # space.
61
+ def test_tautologies_random(number = 1024, dimensions = 4)
62
+ # Create the variables.
63
+ base = "`"
64
+ variables = dimensions.times.map { |i| base.next!.clone }
65
+ # Create the generator.
66
+ generator = Generator.new(*variables)
67
+ generator.seed = @seed
68
+ # Performs the tests.
69
+ number.times do |i|
70
+ print "Test #{i}: "
71
+ return false unless test_tautology_random(generator)
72
+ end
73
+ return true
74
+ end
75
+
76
+
77
+ ## Checks if covers have the same truth table.
78
+ def same_truth_table?(cover0,cover1)
79
+ return false unless cover0.width == cover1.width
80
+ # Check for each entry.
81
+ (2**cover0.width).times do |i|
82
+ return false unless cover0.eval(i) == cover1.eval(i)
83
+ end
84
+ return true
85
+ end
86
+
87
+
88
+ ## Tests espresso on a given +cover+.
89
+ def test_espresso(cover)
90
+ print "ESPRESSO on cover=[#{cover.to_s}]...\n"
91
+ simple = cover.simplify(@deadline,@volume)
92
+ print "result: [#{simple}]\n"
93
+ check0 = (cover + simple.complement).is_tautology?
94
+ # check0 = same_truth_table?(cover,simple)
95
+ # assert_equal(true,check0)
96
+ print "check 0 = #{check0}\n"
97
+ raise "Test failure" unless check0
98
+ check1 = (cover.complement + simple).is_tautology?
99
+ # assert_equal(true,check1)
100
+ print "check 1 = #{check1}\n"
101
+ raise "Test failure" unless check1
102
+ return true
103
+ end
104
+
105
+ ## Tests the implementation of the espresso algorithm on each
106
+ # possible 1-cube cover of 4 variables.
107
+ #
108
+ # Test only on cover if a +test+ number is given.
109
+ def test_espresso_all(test = nil)
110
+ generator = Generator.new("a","b","c","d")
111
+ generator.seed = @seed
112
+ if test then
113
+ test = test.to_i
114
+ print "Test #{test}: "
115
+ return test_espresso(generator.make_1cover(test))
116
+ else
117
+ generator.each_1cover.with_index do |cover,i|
118
+ print "Test #{i}: "
119
+ return false unless test_espresso(cover)
120
+ end
121
+ return true
122
+ end
123
+ end
124
+
125
+ ## Tests ESPRESSO on a cover generated by a random +generator+.
126
+ def test_espresso_random(generator)
127
+ # Genrate a random cover.
128
+ cover = generator.random_cover
129
+ # Test it.
130
+ return false unless test_espresso(cover)
131
+ return true
132
+ end
133
+
134
+ ## Tests ESPRESSO on randomly +number+ cover cases on a +dimensions+ boolean
135
+ # space, including at most +max+ cubes.
136
+ def test_espressos_random(number = 1024, dimensions = 4, max = nil)
137
+ # Create the variables.
138
+ base = "`"
139
+ variables = dimensions.times.map { |i| base.next!.clone }
140
+ # Create the generator.
141
+ generator = Generator.new(*variables)
142
+ generator.seed = @seed
143
+ generator.max = max if max
144
+ # Ensures a rate of "-" large enough to have a high probability of
145
+ # an interesting cover (i.e., which is actually simplifiable).
146
+ # This rate +r+ is obainted as the solution of the followings:
147
+ # max/2 * 2**(r*dimensions) >= 2**dimensions
148
+ # NOTE: max/2 is the average size of the cover.
149
+ generator.rate = Math::log2(2**(dimensions+1)/max.to_f)/dimensions
150
+ # Ensures the rate is not too small though.
151
+ generator.rate = 0.3 unless generator.rate >= 0.3
152
+ print "rate=#{generator.rate}\n"
153
+ # Performs the tests.
154
+ number.times do |i|
155
+ print "Test #{i}: "
156
+ return false unless test_espresso_random(generator)
157
+ end
158
+ return true
159
+ end
160
+
161
+ end
@@ -0,0 +1,116 @@
1
+ require 'logger.rb'
2
+
3
+
4
+ module LogicTools
5
+
6
+ ## Small class for indenting
7
+ class Indenter
8
+ ## Creates a new indenter.
9
+ def initialize
10
+ @indent = 0
11
+ end
12
+
13
+ ## Increase the indent level by +value+.
14
+ #
15
+ # NOTE:
16
+ # * the indent level cannot be bellow 0.
17
+ # * the value can be negative.
18
+ def inc(value = 1)
19
+ @indent += value.to_i
20
+ @indent = 0 if @indent < 0
21
+ end
22
+
23
+ ## Decreases the indent level by +value+.
24
+ #
25
+ # NOTE:
26
+ # * the indent level cannot be bellow 0.
27
+ # * the value can be negative.
28
+ def dec(value = 1)
29
+ @indent -= value.to_i
30
+ @indent = 0 if @indent < 0
31
+ end
32
+
33
+ ## Converts to a string (generates the indent.)
34
+ def to_s
35
+ return " " * @indent
36
+ end
37
+ end
38
+
39
+
40
+ module Traces
41
+
42
+ # Add traces support to the logic tools.
43
+
44
+
45
+ ## The logger used for displaying the traces.
46
+ TRACES = Logger.new(STDOUT)
47
+
48
+ ## The indent for the traces.
49
+ TRACES_INDENT = Indenter.new
50
+
51
+ # Format the traces
52
+ TRACES.formatter = proc do |severity, datetime, progname, msg|
53
+ "[#{severity}] #{datetime}: #{TRACES_INDENT.to_s}#{msg}\n"
54
+ end
55
+ TRACES.datetime_format = '%H:%M:%S'
56
+
57
+ # By default the trace level is set warn.
58
+ TRACES.level = Logger::WARN
59
+
60
+
61
+ ## Sets the trace level to error.
62
+ def traces_error
63
+ TRACES.level = Logger::ERROR
64
+ end
65
+
66
+ ## Sets the trace level to warn.
67
+ def traces_warn
68
+ TRACES.level = Logger::WARN
69
+ end
70
+
71
+ ## Sets the trace level to info.
72
+ def traces_info
73
+ TRACES.level = Logger::INFO
74
+ end
75
+
76
+ ## Sets the trace level to debug
77
+ def traces_debug
78
+ TRACES.level = Logger::DEBUG
79
+ end
80
+
81
+
82
+ ## Sends an error-level trace.
83
+ def error(&blk)
84
+ TRACES.error(&blk)
85
+ end
86
+
87
+ ## Sends a warn-level trace.
88
+ def warn(&blk)
89
+ TRACES.warn(&blk)
90
+ end
91
+
92
+ ## Sends an info-level trace.
93
+ def info(&blk)
94
+ TRACES.info(&blk)
95
+ end
96
+
97
+ ## Sends a debug-level trace.
98
+ def debug(&blk)
99
+ TRACES.debug(&blk)
100
+ end
101
+
102
+
103
+ ## Increases the indent level by +value+.
104
+ def inc_indent(value = 1)
105
+ TRACES_INDENT.inc(value)
106
+ end
107
+
108
+ ## Deacreases the indent level by +value+.
109
+ def dec_indent(value = 1)
110
+ TRACES_INDENT.dec(value)
111
+ end
112
+
113
+
114
+ end
115
+
116
+ end
@@ -39,7 +39,7 @@ include LogicTools
39
39
  # $parsed = string2logic($expr)
40
40
  #
41
41
  # # Display the variables
42
- # $vars = $parsed.getVariables
42
+ # $vars = $parsed.get_variables
43
43
  # $vars.each { |var| print "#{var} " }
44
44
  # print "\n"
45
45
  #
@@ -55,7 +55,7 @@ each_input do |expr|
55
55
  parsed = string2logic(expr)
56
56
 
57
57
  # Display the variables
58
- vars = parsed.getVariables
58
+ vars = parsed.get_variables
59
59
  vars.each { |var| print "#{var} " }
60
60
  print "\n"
61
61
 
@@ -1,3 +1,3 @@
1
1
  module LogicTools
2
- VERSION = "0.2.4"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logic_tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lovic Gauthier
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-23 00:00:00.000000000 Z
11
+ date: 2017-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -74,6 +74,8 @@ description: "LogicTools is a set of command-line tools for processing logic exp
74
74
  email:
75
75
  - lovic@ariake-nct.ac.jp
76
76
  executables:
77
+ - is_tautology
78
+ - simplify_es
77
79
  - simplify_qm
78
80
  - std_conj
79
81
  - std_dij
@@ -89,19 +91,30 @@ files:
89
91
  - Rakefile
90
92
  - bin/console
91
93
  - bin/setup
94
+ - exe/is_tautology
95
+ - exe/simplify_es
92
96
  - exe/simplify_qm
93
97
  - exe/std_conj
94
98
  - exe/std_dij
95
99
  - exe/truth_tbl
96
100
  - lib/logic_tools.rb
101
+ - lib/logic_tools/is_tautology.rb
102
+ - lib/logic_tools/logicconvert.rb
103
+ - lib/logic_tools/logiccover.rb
104
+ - lib/logic_tools/logicgenerator.rb
97
105
  - lib/logic_tools/logicinput.rb
98
106
  - lib/logic_tools/logicparse.rb
99
- - lib/logic_tools/logicsimplify.rb
107
+ - lib/logic_tools/logicsimplify_es.rb
108
+ - lib/logic_tools/logicsimplify_qm.rb
100
109
  - lib/logic_tools/logictree.rb
110
+ - lib/logic_tools/minimal_column_covers.rb
101
111
  - lib/logic_tools/simplify_bug.txt
112
+ - lib/logic_tools/simplify_es.rb
102
113
  - lib/logic_tools/simplify_qm.rb
103
114
  - lib/logic_tools/std_conj.rb
104
115
  - lib/logic_tools/std_dij.rb
116
+ - lib/logic_tools/test_logic_tools.rb
117
+ - lib/logic_tools/traces.rb
105
118
  - lib/logic_tools/truth_tbl.rb
106
119
  - lib/logic_tools/version.rb
107
120
  - logic_tools.gemspec