symbolic 0.0.6 → 0.1.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.
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