symbolic 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,14 +1,16 @@
1
1
  Symbolic math for ruby.
2
2
 
3
- Installation:
3
+ == Installation:
4
+
4
5
  gem install symbolic
5
6
 
6
- Introduction:
7
+ == Introduction:
8
+
7
9
  Symbolic math can be really helpful if you want to simplify some giant equation or if you don't want to get a performance hit re-evaluating big math expressions every time when few variables change.
8
10
 
9
11
  Currently I've implemented only naive optimizations to simplify math expressions, but it's pretty simple to add your own - see Symbolic::Optimizations module for examples.
10
12
 
11
- Examples:
13
+ == Examples:
12
14
  x = var :name => 'x'
13
15
  y = var :name => 'y'
14
16
 
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ begin
5
5
  require 'jeweler'
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "symbolic"
8
- gem.version = '0.0.6'
8
+ gem.version = '0.1.0'
9
9
  gem.summary = 'Symbolic math for ruby'
10
10
  gem.description = %Q{Symbolic math can be really helpful if you want to simplify some giant equation or if you don't want to get a performance hit re-evaluating big math expressions every time when few variables change.}
11
11
  gem.email = "ravwar@gmail.com"
@@ -1,18 +1,14 @@
1
1
  module Symbolic
2
2
  class Expression < Operatable
3
+ attr_reader :var1, :var2, :operation
4
+
3
5
  def initialize(var1, var2, operation)
4
6
  var1, var2 = var2, var1 if operation == '*' && var2.is_a?(Numeric)
5
7
  @var1, @var2, @operation = var1, var2, operation
6
8
  end
7
9
 
8
10
  def to_s
9
- var1 = "#{@var1}"
10
- var2 = "#{@var2}"
11
- if ['*', '/'].include? @operation
12
- var1 = "(#{@var1})" if @var1.is_a?(Expression) && (@var1.plus? || @var1.minus?) || @var1.is_a?(UnaryMinus)
13
- var2 = "(#{@var2})" if @var2.is_a?(Expression) && (@var2.plus? || @var2.minus?) || @var2.is_a?(UnaryMinus)
14
- end
15
- "#{var1}#{@operation}#{var2}"
11
+ "#{brackets @var1}#{@operation}#{brackets @var2}"
16
12
  end
17
13
 
18
14
  def plus?
@@ -37,8 +33,20 @@ module Symbolic
37
33
  (undefined_variables_of(@var1) + undefined_variables_of(@var2)).uniq
38
34
  end
39
35
 
36
+ def ==(object)
37
+ object.var1 == @var1 && object.var2 == @var2 && object.operation == @operation
38
+ end
39
+
40
40
  private
41
41
 
42
+ def brackets(var)
43
+ brackets_conditional(var) ? "(#{var})" : var.to_s
44
+ end
45
+
46
+ def brackets_conditional(var)
47
+ %w(* /).include?(@operation) && (var.is_a?(UnaryMinus) || var.is_a?(Expression) && (var.plus? || var.minus?))
48
+ end
49
+
42
50
  def undefined_variables_of(variable)
43
51
  variable.is_a?(Operatable) ? variable.undefined_variables : []
44
52
  end
@@ -3,9 +3,11 @@ module Symbolic
3
3
  def self.addition(symbolic_var, var, reverse=false)
4
4
  if var == 0
5
5
  symbolic_var
6
+ elsif var.is_a?(Numeric) && var < 0
7
+ symbolic_var - (-var)
6
8
  elsif var.is_a? UnaryMinus
7
9
  symbolic_var - var.variable
8
- elsif reverse && symbolic_var.is_a?(UnaryMinus)
10
+ elsif symbolic_var.is_a? UnaryMinus
9
11
  var - symbolic_var.variable
10
12
  else
11
13
  if reverse
@@ -18,9 +20,11 @@ module Symbolic
18
20
 
19
21
  def self.subtraction(symbolic_var, var, reverse=false)
20
22
  if var == 0
21
- symbolic_var
23
+ symbolic_var * (reverse ? -1 : 1)
22
24
  elsif var.is_a? UnaryMinus
23
25
  symbolic_var + var.variable
26
+ elsif !reverse && var.is_a?(Numeric) && var < 0
27
+ symbolic_var + (-var)
24
28
  elsif reverse && symbolic_var.is_a?(UnaryMinus)
25
29
  var + symbolic_var.variable
26
30
  else
@@ -29,5 +29,9 @@ module Symbolic
29
29
  def undefined_variables
30
30
  @variable.undefined_variables
31
31
  end
32
+
33
+ def ==(object)
34
+ object.is_a?(UnaryMinus) && object.variable == @variable
35
+ end
32
36
  end
33
37
  end
@@ -5,7 +5,7 @@ module Symbolic
5
5
  @@index = 0
6
6
 
7
7
  def initialize(options)
8
- unless @name = options[:name]
8
+ unless @name = options[:name].to_s
9
9
  @@index += 1
10
10
  @name = "var#{@@index}"
11
11
  end
@@ -1,43 +1,89 @@
1
1
  require File.expand_path(File.dirname(__FILE__) +'/spec_helper')
2
2
 
3
3
  describe "Symbolic" do
4
- def self.x
5
- var :value => 1, :name => 'x'
4
+ before(:all) do
5
+ @x = var :name => :x, :value => 1
6
+ @y = var :name => :y, :value => 2
6
7
  end
7
8
 
8
- def self.y
9
- var :value => 2, :name => 'y'
9
+ def expression(string)
10
+ eval string.gsub(/[a-z]+/, '@\0')
10
11
  end
11
12
 
12
13
  describe "evaluation (x=1, y=2):" do
13
- def self.check_evaluation(conditions)
14
+ def self.should_evaluate_to(conditions)
14
15
  conditions.each do |symbolic_expression, result|
15
16
  it symbolic_expression do
16
- symbolic_expression.value.should == result
17
+ expression(symbolic_expression).value.should == result
17
18
  end
18
19
  end
19
20
  end
20
21
 
21
- check_evaluation \
22
- x => 1,
23
- y => 2,
24
- +x => 1,
25
- -x => -1,
26
- x + 4 => 5,
27
- 3 + x => 4,
28
- x + y => 3,
29
- x - 1 => 0,
30
- 1 - x => 0,
31
- x - y => -1,
32
- -x + 3 => 2,
33
- -y - x => -3,
34
- x*3 => 3,
35
- 4*y => 8,
36
- (+x)*(-y) => -2,
37
- x/2 => 0,
38
- y/2 => 1,
39
- x/2.0 => 0.5,
40
- -2/x => -2,
41
- 4/(-y) => -2
22
+ should_evaluate_to \
23
+ 'x' => 1,
24
+ 'y' => 2,
25
+ '+x' => 1,
26
+ '-x' => -1,
27
+ 'x + 4' => 5,
28
+ '3 + x' => 4,
29
+ 'x + y' => 3,
30
+ 'x - 1' => 0,
31
+ '1 - x' => 0,
32
+ 'x - y' => -1,
33
+ '-x + 3' => 2,
34
+ '-y - x' => -3,
35
+ 'x*3' => 3,
36
+ '4*y' => 8,
37
+ '(+x)*(-y)' => -2,
38
+ 'x/2' => 0,
39
+ 'y/2' => 1,
40
+ 'x/2.0' => 0.5,
41
+ '-2/x' => -2,
42
+ '4/(-y)' => -2
43
+ end
44
+
45
+ describe "optimization:" do
46
+ def self.should_equal(conditions)
47
+ conditions.each do |non_optimized, optimized|
48
+ it non_optimized do
49
+ expression(non_optimized).should == expression(optimized)
50
+ end
51
+ end
52
+ end
53
+
54
+ should_equal \
55
+ '-(-x)' => 'x',
56
+
57
+ '0 + x' => 'x',
58
+ 'x + 0' => 'x',
59
+ 'x + (-2)' => 'x - 2',
60
+ '-2 + x' => 'x - 2',
61
+ '-x + 2' => '2 - x',
62
+ 'x + (-y)' => 'x - y',
63
+ '-y + x' => 'x - y',
64
+
65
+ '0 - x' => '-x',
66
+ 'x - 0' => 'x',
67
+ 'x - (-2)' => 'x + 2',
68
+ '-2 - (-x)' => 'x - 2',
69
+ 'x - (-y)' => 'x + y',
70
+
71
+ '0 * x' => '0',
72
+ 'x * 0' => '0',
73
+ '1 * x' => 'x',
74
+ 'x * 1' => 'x',
75
+ '-1 * x' => '-x',
76
+ 'x * (-1)' => '-x',
77
+ 'x * (-3)' => '-(x*3)',
78
+ '-3 * x' => '-(x*3)',
79
+ '-3 * (-x)' => 'x*3',
80
+ 'x*(-y)' => '-(x*y)',
81
+ '-x*y' => '-(x*y)',
82
+ '(-x)*(-y)' => 'x*y',
83
+
84
+ 'x / 1' => 'x'
85
+ end
86
+
87
+ describe "formulas" do
42
88
  end
43
89
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: symbolic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - brainopia
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-24 00:00:00 +03:00
12
+ date: 2009-11-25 00:00:00 +03:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency