initial
This commit is contained in:
commit
2450169bc0
6 changed files with 269 additions and 0 deletions
68
cas.rb
Normal file
68
cas.rb
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'simp_rules'
|
||||||
|
|
||||||
|
# TODO: natural numbers :)
|
||||||
|
# TODO: little lang that transpiles to ruby
|
||||||
|
|
||||||
|
# unnecessary if i standardize on parenthezing every binary op anyway!
|
||||||
|
def lispify(bla)
|
||||||
|
if bla.is_a? Array
|
||||||
|
l = bla[0]
|
||||||
|
op = bla[1]
|
||||||
|
r = bla[2]
|
||||||
|
[op, [lispify(l), lispify(r)]]
|
||||||
|
else
|
||||||
|
bla
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# doesn't account for actually important stuff, gonna need to do equal'
|
||||||
|
def simp_rule(); end
|
||||||
|
|
||||||
|
def simp(expr, rules = SIMP_RULES, limit: 413)
|
||||||
|
expr = expr.dup
|
||||||
|
|
||||||
|
limit.times do
|
||||||
|
rules.each do |rule|
|
||||||
|
expr = simp_single(expr, rule)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
expr
|
||||||
|
end
|
||||||
|
|
||||||
|
def simp_single(expr, rule)
|
||||||
|
if rule.concrete?
|
||||||
|
expr = simp_applied_rule(expr, rule)
|
||||||
|
else
|
||||||
|
targets = potential_rule_targets(expr)
|
||||||
|
targets.each do |target|
|
||||||
|
concrete_rule = rule.clone.concrete(target)
|
||||||
|
expr = simp_single(expr, concrete_rule)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
expr
|
||||||
|
end
|
||||||
|
|
||||||
|
def simp_applied_rule(expr, rule)
|
||||||
|
lhs = rule.lhs
|
||||||
|
rhs = rule.rhs
|
||||||
|
|
||||||
|
if expr == lhs
|
||||||
|
rhs
|
||||||
|
elsif expr.is_a? Array
|
||||||
|
expr.map { |expr| simp_applied_rule(expr, rule) }
|
||||||
|
else
|
||||||
|
expr
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def potential_rule_targets(expr)
|
||||||
|
if expr.is_a? Array
|
||||||
|
(expr + expr.flatten).uniq
|
||||||
|
else
|
||||||
|
[expr]
|
||||||
|
end
|
||||||
|
end
|
11
messing_with_eq.rb
Normal file
11
messing_with_eq.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'cas'
|
||||||
|
require 'rule'
|
||||||
|
require 'simp_rules'
|
||||||
|
require 'rw_rules'
|
||||||
|
|
||||||
|
def add_right_cancel
|
||||||
|
rule([%i[a + c], :==, %i[b + c]] => %i[a == b]).forall(:a, :b, :c)
|
||||||
|
end
|
||||||
|
|
99
rule.rb
Normal file
99
rule.rb
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
class Rule
|
||||||
|
def forall(*syms)
|
||||||
|
syms.each do |sym|
|
||||||
|
forall_single(sym)
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def forall_single(sym)
|
||||||
|
@generality ||= 0
|
||||||
|
@generality += 1
|
||||||
|
@syms ||= []
|
||||||
|
@syms += [sym]
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(name, hash)
|
||||||
|
@name = name
|
||||||
|
@lhs = hash.keys.last
|
||||||
|
@rhs = hash.values.last
|
||||||
|
@syms ||= []
|
||||||
|
@generality ||= 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def general?
|
||||||
|
@generality.positive?
|
||||||
|
end
|
||||||
|
|
||||||
|
def concrete?
|
||||||
|
!general?
|
||||||
|
end
|
||||||
|
|
||||||
|
# concrete is a verb :]
|
||||||
|
def concrete(*xs)
|
||||||
|
xs.each { |x| concrete_single(x) }
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def concrete_single(x)
|
||||||
|
unless concrete?
|
||||||
|
sym = @syms.delete_at 0
|
||||||
|
replace_rule = Rule.new(sym => x)
|
||||||
|
@lhs = simp_single(@lhs, replace_rule)
|
||||||
|
@rhs = simp_single(@rhs, replace_rule)
|
||||||
|
|
||||||
|
@generality -= 1
|
||||||
|
@sym = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def apply(expr)
|
||||||
|
simp_single(expr, self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def swap
|
||||||
|
rule = dup
|
||||||
|
rule.lhs = @rhs
|
||||||
|
rule.rhs = @lhs
|
||||||
|
rule
|
||||||
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
"#<Rule \"#{@name}\": #{forall_display}#{pretty_side @lhs} <=> #{pretty_side @rhs}>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def forall_display
|
||||||
|
if concrete?
|
||||||
|
''
|
||||||
|
else
|
||||||
|
"∀#{@syms.join ' '}, "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_accessor :lhs, :rhs, :generality, :name
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
other.is_a? Rule and
|
||||||
|
@lhs == other.lhs and
|
||||||
|
@rhs == other.rhs and
|
||||||
|
@generality == other.generality
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pretty_side(side)
|
||||||
|
if side.is_a? Array
|
||||||
|
"(#{side.map { |side_| pretty_side side_ }.join ' '})"
|
||||||
|
else
|
||||||
|
side.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def rule(*syms)
|
||||||
|
Rule.new(*syms)
|
||||||
|
end
|
||||||
|
|
19
rw_rules.rb
Normal file
19
rw_rules.rb
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rule'
|
||||||
|
|
||||||
|
def rule(*args)
|
||||||
|
Rule.new(*args)
|
||||||
|
end
|
||||||
|
|
||||||
|
# not a simp rule! (loops)
|
||||||
|
def add_assoc
|
||||||
|
rule(
|
||||||
|
[%i[a + b], :+, :c] => [:a, :+, %i[b + c]]
|
||||||
|
).forall(:a, :b, :c)
|
||||||
|
end
|
||||||
|
|
||||||
|
RW_RULES = [
|
||||||
|
add_assoc,
|
||||||
|
rule(%i[a + b] => %i[b + a]).forall(:a, :b)
|
||||||
|
].freeze
|
23
simp_rules.rb
Normal file
23
simp_rules.rb
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rule'
|
||||||
|
|
||||||
|
class SimpRules
|
||||||
|
@@simp_rules = []
|
||||||
|
|
||||||
|
def self.register(rule)
|
||||||
|
@@simp_rules.push(rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.register_new(*args)
|
||||||
|
register(rule(*args))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
SimpRules.register_new('one_plus_one', [1, :+, 1] => 2)
|
||||||
|
SimpRules.register_new('add_zero', [:x, :+, 0] => :x).forall(:x)
|
||||||
|
SimpRules.register_new('zero_add', [0, :+, :x] => :x).forall(:x)
|
||||||
|
SimpRules.register_new('mul_one', [:x, :*, 1] => :x).forall(:x)
|
||||||
|
SimpRules.register_new('one_mul', [1, :*, :x] => :x).forall(:x)
|
||||||
|
SimpRules.register_new('mul_zero', [:x, :*, 0] => 0).forall(:x)
|
||||||
|
SimpRules.register_new('zero_mul', [0, :*, :x] => 0).forall(:x)
|
49
tree_solve.rb
Normal file
49
tree_solve.rb
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'cas'
|
||||||
|
require 'rule'
|
||||||
|
require 'rw_rules'
|
||||||
|
require 'simp_rules'
|
||||||
|
|
||||||
|
# sucks
|
||||||
|
class Solver
|
||||||
|
def initialize(solve_for: :x, given: [])
|
||||||
|
@solve_for = solve_for
|
||||||
|
@visited = MySet.new([given])
|
||||||
|
end
|
||||||
|
|
||||||
|
def winner
|
||||||
|
found = @visited.find { |g| g.lhs == @solve_for || g.rhs == @solve_for && g.lhs != g.rhs }
|
||||||
|
return unless found
|
||||||
|
|
||||||
|
simp(if found.lhs == @solve_for
|
||||||
|
found.rhs
|
||||||
|
else
|
||||||
|
found.lhs
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def elaborate!
|
||||||
|
@visited.each do |t|
|
||||||
|
(SIMP_RULES + RW_RULES).each do |rule|
|
||||||
|
@visited.add(rule.apply(t))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
simp!
|
||||||
|
end
|
||||||
|
|
||||||
|
def simp!
|
||||||
|
@visited.map! { |g| g.simp }
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class MySet < Set
|
||||||
|
def add(item)
|
||||||
|
super.add(item) unless any? { |i| item == i }
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue