diff --git a/ext/symengine/CMakeLists.txt b/ext/symengine/CMakeLists.txt index 0fad727..b587bb6 100644 --- a/ext/symengine/CMakeLists.txt +++ b/ext/symengine/CMakeLists.txt @@ -5,7 +5,8 @@ set(RUBY_WRAPPER_SRC ruby_rational.c ruby_constant.c ruby_function.c - symengine_macros.c + ruby_ntheory.c + symengine_utils.c symengine.c ) diff --git a/ext/symengine/ruby_basic.h b/ext/symengine/ruby_basic.h index 62d9bc2..792efaa 100644 --- a/ext/symengine/ruby_basic.h +++ b/ext/symengine/ruby_basic.h @@ -4,7 +4,7 @@ #include #include -#include "symengine_macros.h" +#include "symengine_utils.h" void cbasic_free(void *ptr); diff --git a/ext/symengine/ruby_constant.h b/ext/symengine/ruby_constant.h index d0f0454..bfaeabe 100644 --- a/ext/symengine/ruby_constant.h +++ b/ext/symengine/ruby_constant.h @@ -4,9 +4,8 @@ #include #include -#include "ruby_basic.h" #include "symengine.h" -#include "symengine_macros.h" +#include "symengine_utils.h" VALUE cconstant_const(void (*cwfunc_ptr)(basic_struct*)); diff --git a/ext/symengine/ruby_function.c b/ext/symengine/ruby_function.c index f4c8783..e8be33a 100644 --- a/ext/symengine/ruby_function.c +++ b/ext/symengine/ruby_function.c @@ -1,25 +1,8 @@ #include "ruby_function.h" - -VALUE cfunction_onearg(void (*cwfunc_ptr)(basic_struct*, const basic_struct*), VALUE operand1) { - basic_struct *cresult; - VALUE result; - - basic cbasic_operand1; - basic_new_stack(cbasic_operand1); - sympify(operand1, cbasic_operand1); - - cresult = basic_new_heap(); - cwfunc_ptr(cresult, cbasic_operand1); - result = Data_Wrap_Struct(Klass_of_Basic(cresult), NULL , cbasic_free_heap, cresult); - basic_free_stack(cbasic_operand1); - - return result; -} - #define IMPLEMENT_ONE_ARG_FUNC(func) \ VALUE cfunction_ ## func(VALUE self, VALUE operand1) { \ - return cfunction_onearg(basic_ ## func, operand1); \ + return function_onearg(basic_ ## func, operand1); \ } IMPLEMENT_ONE_ARG_FUNC(abs); diff --git a/ext/symengine/ruby_function.h b/ext/symengine/ruby_function.h index d40bd58..e55b63b 100644 --- a/ext/symengine/ruby_function.h +++ b/ext/symengine/ruby_function.h @@ -4,11 +4,8 @@ #include #include -#include "ruby_basic.h" #include "symengine.h" -#include "symengine_macros.h" - -VALUE cfunction_func(void (*cwfunc_ptr)(basic_struct*, const basic_struct*), VALUE operand1); +#include "symengine_utils.h" VALUE cfunction_abs(VALUE self, VALUE operand1); VALUE cfunction_sin(VALUE self, VALUE operand1); diff --git a/ext/symengine/ruby_integer.c b/ext/symengine/ruby_integer.c index 229a4c5..b61a34f 100644 --- a/ext/symengine/ruby_integer.c +++ b/ext/symengine/ruby_integer.c @@ -6,3 +6,4 @@ VALUE cinteger_init(VALUE self, VALUE num_value) { GET_SYMINTFROMVAL(num_value, this); return self; } + diff --git a/ext/symengine/ruby_ntheory.c b/ext/symengine/ruby_ntheory.c new file mode 100644 index 0000000..141ee70 --- /dev/null +++ b/ext/symengine/ruby_ntheory.c @@ -0,0 +1,70 @@ +#include "ruby_ntheory.h" + +VALUE cntheory_nextprime(VALUE self, VALUE operand1) { + return function_onearg(ntheory_nextprime, operand1); +} + +VALUE cntheory_gcd(VALUE self, VALUE operand1, VALUE operand2) { + return function_twoarg(ntheory_gcd, operand1, operand2); +} + +VALUE cntheory_lcm(VALUE self, VALUE operand1, VALUE operand2) { + return function_twoarg(ntheory_lcm, operand1, operand2); +} + +VALUE cntheory_mod(VALUE self, VALUE operand2) { + VALUE ans = function_twoarg(ntheory_mod, self, operand2); + VALUE ans1 = cbasic_add(ans, operand2); + return function_twoarg(ntheory_mod, ans1, operand2); +} + +VALUE cntheory_quotient(VALUE self, VALUE operand1, VALUE operand2) { + return function_twoarg(ntheory_quotient, operand1, operand2); +} + +VALUE cntheory_fibonacci(VALUE self, VALUE operand1){ + basic_struct *cresult; + VALUE result; + + unsigned long cbasic_operand1; + cbasic_operand1 = NUM2ULONG(operand1); + + cresult = basic_new_heap(); + ntheory_fibonacci(cresult, cbasic_operand1); + result = Data_Wrap_Struct(Klass_of_Basic(cresult), NULL , cbasic_free_heap, cresult); + + return result; +} + +VALUE cntheory_lucas(VALUE self, VALUE operand1){ + basic_struct *cresult; + VALUE result; + + unsigned long cbasic_operand1; + cbasic_operand1 = NUM2ULONG(operand1); + + cresult = basic_new_heap(); + ntheory_lucas(cresult, cbasic_operand1); + result = Data_Wrap_Struct(Klass_of_Basic(cresult), NULL , cbasic_free_heap, cresult); + + return result; +} + +VALUE cntheory_binomial(VALUE self, VALUE operand1, VALUE operand2){ + basic_struct *cresult; + VALUE result; + + basic cbasic_operand1; + basic_new_stack(cbasic_operand1); + sympify(operand1, cbasic_operand1); + + unsigned long cbasic_operand2; + cbasic_operand2 = NUM2ULONG(operand2); + + cresult = basic_new_heap(); + ntheory_binomial(cresult, cbasic_operand1, cbasic_operand2); + result = Data_Wrap_Struct(Klass_of_Basic(cresult), NULL , cbasic_free_heap, cresult); + basic_free_stack(cbasic_operand1); + + return result; +} diff --git a/ext/symengine/ruby_ntheory.h b/ext/symengine/ruby_ntheory.h new file mode 100644 index 0000000..a5508c0 --- /dev/null +++ b/ext/symengine/ruby_ntheory.h @@ -0,0 +1,20 @@ +#ifndef RUBY_NTHEORY_H_ +#define RUBY_NTHEORY_H_ + +#include +#include + +#include "symengine.h" +#include "ruby_basic.h" +#include "symengine_utils.h" + +VALUE cntheory_gcd(VALUE self, VALUE operand1, VALUE operand2); +VALUE cntheory_lcm(VALUE self, VALUE operand1, VALUE operand2); +VALUE cntheory_nextprime(VALUE self, VALUE operand1); +VALUE cntheory_mod(VALUE self, VALUE operand2); +VALUE cntheory_quotient(VALUE self, VALUE operand1, VALUE operand2); +VALUE cntheory_fibonacci(VALUE self, VALUE operand1); +VALUE cntheory_lucas(VALUE self, VALUE operand1); +VALUE cntheory_binomial(VALUE self, VALUE operand1, VALUE operand2); + +#endif //RUBY_NTHEORY_H_ diff --git a/ext/symengine/symengine.c b/ext/symengine/symengine.c index e04deb8..2f9f22c 100644 --- a/ext/symengine/symengine.c +++ b/ext/symengine/symengine.c @@ -5,6 +5,7 @@ #include "ruby_rational.h" #include "ruby_constant.h" #include "ruby_function.h" +#include "ruby_ntheory.h" #include "symengine.h" /////////////////// @@ -52,6 +53,7 @@ void Init_symengine() { c_integer = rb_define_class_under(m_symengine, "Integer", c_basic); rb_define_alloc_func(c_integer, cbasic_alloc); rb_define_method(c_integer, "initialize", cinteger_init, 1); + rb_define_method(c_integer, "%", cntheory_mod, 1); //Rational class c_rational = rb_define_class_under(m_symengine, "Rational", c_basic); @@ -145,4 +147,13 @@ void Init_symengine() { rb_define_module_function(m_symengine, "zeta", cfunction_zeta, 1); rb_define_module_function(m_symengine, "gamma", cfunction_gamma, 1); + //NTheory Functions as Module Level Functions + rb_define_module_function(m_symengine, "gcd", cntheory_gcd, 2); + rb_define_module_function(m_symengine, "lcm", cntheory_lcm, 2); + rb_define_module_function(m_symengine, "nextprime", cntheory_nextprime, 1); + rb_define_module_function(m_symengine, "quotient", cntheory_quotient, 2); + rb_define_module_function(m_symengine, "fibonacci", cntheory_fibonacci, 1); + rb_define_module_function(m_symengine, "lucas", cntheory_lucas, 1); + rb_define_module_function(m_symengine, "binomial", cntheory_binomial, 2); + } diff --git a/ext/symengine/symengine_macros.c b/ext/symengine/symengine_utils.c similarity index 72% rename from ext/symengine/symengine_macros.c rename to ext/symengine/symengine_utils.c index 5c18744..f914ac3 100644 --- a/ext/symengine/symengine_macros.c +++ b/ext/symengine/symengine_utils.c @@ -1,4 +1,4 @@ -#include "symengine_macros.h" +#include "symengine_utils.h" #include "symengine.h" void sympify(VALUE operand2, basic_struct *cbasic_operand2) { @@ -111,3 +111,41 @@ VALUE Klass_of_Basic(const basic_struct *basic_ptr) { return c_basic; } } + +VALUE function_onearg(void (*cwfunc_ptr)(basic_struct*, const basic_struct*), VALUE operand1) { + basic_struct *cresult; + VALUE result; + + basic cbasic_operand1; + basic_new_stack(cbasic_operand1); + sympify(operand1, cbasic_operand1); + + cresult = basic_new_heap(); + cwfunc_ptr(cresult, cbasic_operand1); + result = Data_Wrap_Struct(Klass_of_Basic(cresult), NULL , cbasic_free_heap, cresult); + basic_free_stack(cbasic_operand1); + + return result; +} + +VALUE function_twoarg(void (*cwfunc_ptr)(basic_struct*, const basic_struct*, const basic_struct*), + VALUE operand1, VALUE operand2) { + basic_struct *cresult; + VALUE result; + + basic cbasic_operand1; + basic_new_stack(cbasic_operand1); + sympify(operand1, cbasic_operand1); + + basic cbasic_operand2; + basic_new_stack(cbasic_operand2); + sympify(operand2, cbasic_operand2); + + cresult = basic_new_heap(); + cwfunc_ptr(cresult, cbasic_operand1, cbasic_operand2); + result = Data_Wrap_Struct(Klass_of_Basic(cresult), NULL , cbasic_free_heap, cresult); + basic_free_stack(cbasic_operand1); + basic_free_stack(cbasic_operand2); + + return result; +} diff --git a/ext/symengine/symengine_macros.h b/ext/symengine/symengine_utils.h similarity index 64% rename from ext/symengine/symengine_macros.h rename to ext/symengine/symengine_utils.h index 6de1562..572b839 100644 --- a/ext/symengine/symengine_macros.h +++ b/ext/symengine/symengine_utils.h @@ -2,12 +2,18 @@ #define SYMENGINE_MACROS_H_ #include "ruby.h" +#include "ruby_basic.h" #include "symengine/cwrapper.h" //Returns the pointer wrapped inside the Ruby VALUE void sympify(VALUE operand2, basic_struct *cbasic_operand2); //Returns the Ruby class of the corresponding basic_struct pointer VALUE Klass_of_Basic(const basic_struct *basic_ptr); +//Returns the result from the function pointed by cwfunc_ptr: for one argument functions +VALUE function_onearg(void (*cwfunc_ptr)(basic_struct*, const basic_struct*), VALUE operand1); +//Returns the result from the function pointed by cwfunc_ptr: for two argument functions +VALUE function_twoarg(void (*cwfunc_ptr)(basic_struct*, const basic_struct*, const basic_struct*), + VALUE operand1, VALUE operand2); //Obtains the value from Ruby Fixnum or Bignum to an already allocated basic_struct #define GET_SYMINTFROMVAL(num_value, this) { \ diff --git a/lib/symengine.rb b/lib/symengine.rb index b454130..31e5f3e 100644 --- a/lib/symengine.rb +++ b/lib/symengine.rb @@ -34,3 +34,4 @@ def symbols ary_or_string, *params require 'symengine/symengine' require 'symengine/iruby' require 'symengine/basic' +require 'symengine/integer' diff --git a/lib/symengine/integer.rb b/lib/symengine/integer.rb new file mode 100644 index 0000000..965eff6 --- /dev/null +++ b/lib/symengine/integer.rb @@ -0,0 +1,7 @@ +module SymEngine + class Integer + def to_int + self.to_s.to_i + end + end +end diff --git a/spec/ntheory_spec.rb b/spec/ntheory_spec.rb new file mode 100644 index 0000000..20ed4ae --- /dev/null +++ b/spec/ntheory_spec.rb @@ -0,0 +1,126 @@ +require 'spec_helper' + +describe SymEngine do + + before :each do + end + + describe 'NTheory' do + before :each do + @i1 = SymEngine::Integer.new(1) + @i4 = SymEngine::Integer.new(4) + @i5 = SymEngine::Integer.new(5) + @im4 = SymEngine::Integer.new(-4) + @im5 = SymEngine::Integer.new(-5) + end + + describe '#gcd' do + context 'GCD of 2 and 4' do + it 'returns 2' do + f = SymEngine::gcd(2, 4) + expect(f).to eql(2) + end + end + end + + describe '#lcm' do + context 'LCM of 2 and 4' do + it 'returns 4' do + f = SymEngine::lcm(2, 4) + expect(f).to eql(4) + end + end + end + + describe '#nextprime' do + context 'NextPrime after 4' do + it 'returns 5' do + f = SymEngine::nextprime(4) + expect(f).to eql(5) + end + end + end + + describe '#mod' do + context '5 mod 4' do + it 'returns 1' do + f = @i5 % @i4 + expect(f).to eql(1) + end + end + context '-5 mod -4' do + it 'returns -1' do + f = @im5 % @im4 + expect(f).to eql(-1) + end + end + context '5 mod -4' do + it 'returns -3' do + f = @i5 % @im4 + expect(f).to eql(-3) + end + end + context '-5 mod 4' do + it 'returns 3' do + f = @im5 % @i4 + expect(f).to eql(3) + end + end + end + + describe '#quotient' do + context 'quotient of 5 divided by 2' do + it 'returns 2' do + f = SymEngine::quotient(5, 2) + expect(f).to eql(2) + end + end + end + + describe '#fibonacci' do + context '5th Fibonacci Number' do + it 'returns 5' do + f = SymEngine::fibonacci(5) + expect(f).to eql(5) + end + end + context '5th Fibonacci Number' do + it 'returns 5' do + f = SymEngine::fibonacci(@i5) + expect(f).to eql(5) + end + end + end + + describe '#lucas' do + context '1st Lucas Number' do + it 'returns 1' do + f = SymEngine::lucas(1) + expect(f).to eql(1) + end + end + context '1st Lucas Number' do + it 'returns 1' do + f = SymEngine::lucas(@i1) + expect(f).to eql(1) + end + end + end + + describe '#binomial' do + context 'binomial (n=5, k=1)' do + it 'returns 5' do + f = SymEngine::binomial(5, 1) + expect(f).to eql(5) + end + end + context 'binomial (n=5, k=1)' do + it 'returns 5' do + f = SymEngine::binomial(@i5, @i1) + expect(f).to eql(5) + end + end + end + + end +end diff --git a/symengine_version.txt b/symengine_version.txt index f34b6ce..642392c 100644 --- a/symengine_version.txt +++ b/symengine_version.txt @@ -1 +1,2 @@ -46f54aeafbf2a93be0c8b1d492666f56f0ccbe73 +5e88e62b42c38200573eecf688d90b46beb38a77 +