/* rational.c Ruby/GSL: Ruby extension library for GSL (GNU Scientific Library) (C) Copyright 2004 by Yoshiki Tsunesada Ruby/GSL is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. */ #include "include/rb_gsl_rational.h" #include "include/rb_gsl_array.h" VALUE cgsl_rational; static gsl_rational* gsl_rational_div_poly(const gsl_rational *r1, const gsl_poly *p); static void gsl_rational_mark(gsl_rational *r); gsl_rational* gsl_rational_alloc() { gsl_rational *r = NULL; r = ALLOC(gsl_rational); r->num = (VALUE) NULL; r->den = (VALUE) NULL; return r; } gsl_rational* gsl_rational_new(const gsl_poly *num, const gsl_poly *den) { gsl_rational *r = NULL; r = gsl_rational_alloc(); r->pnum = make_vector_clone(num); r->pden = make_vector_clone(den); r->num = Data_Wrap_Struct(cgsl_poly, 0, gsl_vector_free, r->pnum); r->den = Data_Wrap_Struct(cgsl_poly, 0, gsl_vector_free, r->pden); return r; } gsl_rational* gsl_rational_new2(const gsl_poly *num, const gsl_poly *den) { gsl_rational *r = NULL; r = gsl_rational_alloc(); r->pnum = (gsl_poly *) num; r->pden = (gsl_poly *) den; r->num = Data_Wrap_Struct(cgsl_poly, 0, gsl_vector_free, r->pnum); r->den = Data_Wrap_Struct(cgsl_poly, 0, gsl_vector_free, r->pden); return r; } void gsl_rational_free(gsl_rational *r) { free((gsl_rational *) r); } static gsl_rational* gsl_rational_add(const gsl_rational *r, const gsl_rational *r2) { gsl_rational *rnew = NULL; gsl_poly *dennew = NULL, *numnew = NULL; gsl_poly *a = NULL, *b = NULL; int flag = 0; if (rbgsl_vector_equal(r->pden, r2->pden, 1e-10)) { dennew = r->pden; numnew = gsl_poly_add(r->pnum, r2->pnum); flag = 0; } else { dennew = gsl_poly_conv_vector(r->pden, r2->pden); a = gsl_poly_conv_vector(r->pden, r2->pnum); b = gsl_poly_conv_vector(r2->pden, r->pnum); numnew = gsl_poly_add(a, b); gsl_vector_free(a); gsl_vector_free(b); flag = 1; } rnew = gsl_rational_new(numnew, dennew); gsl_vector_free(numnew); if (flag == 1) gsl_vector_free(dennew); return rnew; } static gsl_rational* gsl_rational_add_poly(const gsl_rational *r, const gsl_poly *p) { gsl_rational *rnew = NULL; gsl_poly *numnew = NULL; gsl_poly *a = NULL; a = gsl_poly_conv_vector(r->pden, p); numnew = gsl_poly_add(a, r->pnum); rnew = gsl_rational_new(numnew, r->pden); gsl_vector_free(a); gsl_vector_free(numnew); return rnew; } static gsl_rational* gsl_rational_mul(const gsl_rational *r1, const gsl_rational *r2) { gsl_rational *rnew = NULL; gsl_poly *num = NULL, *den = NULL; num = gsl_poly_conv_vector(r1->pnum, r2->pnum); den = gsl_poly_conv_vector(r1->pden, r2->pden); rnew = gsl_rational_new2(num, den); return rnew; } static gsl_rational* gsl_rational_mul_poly(const gsl_rational *r1, const gsl_poly *p) { gsl_rational *rnew = NULL; gsl_poly *num = NULL; num = gsl_poly_conv_vector(r1->pnum, p); rnew = gsl_rational_new(num, r1->pden); gsl_vector_free(num); return rnew; } static gsl_rational* gsl_rational_div(const gsl_rational *r1, const gsl_rational *r2) { gsl_rational *rnew = NULL; gsl_poly *num = NULL, *den = NULL; num = gsl_poly_conv_vector(r1->pnum, r2->pden); den = gsl_poly_conv_vector(r1->pden, r2->pnum); rnew = gsl_rational_new2(num, den); return rnew; } static gsl_rational* gsl_rational_div_poly(const gsl_rational *r1, const gsl_poly *p) { gsl_rational *rnew = NULL; gsl_poly *den = NULL; den = gsl_poly_conv_vector(r1->pden, p); rnew = gsl_rational_new(r1->pnum, den); gsl_vector_free(den); return rnew; } static gsl_rational* gsl_rational_inverse(const gsl_rational *r) { return gsl_rational_new(r->pden, r->pnum); } /* static gsl_poly* gsl_rational_partial_fraction(const gsl_rational *r) { gsl_poly *num = NULL, *r = NULL; num = gsl_poly_deconv_vector(r->pnum, r->pden, &r); if (gsl_vector_isnull(r)) { gsl_vector_free(num); gsl_vector_free(r); return NULL; } gsl_vector_free(num); return r; } */ /*****/ gsl_poly* get_poly_get(VALUE obj, int *flag); static void gsl_rational_mark(gsl_rational *r) { rb_gc_mark(r->num); rb_gc_mark(r->den); } static VALUE rb_gsl_rational_new(int argc, VALUE *argv, VALUE klass) { gsl_poly *den = NULL, *num = NULL; gsl_rational *r = NULL; int flag1 = 0, flag2 = 0; switch (argc) { case 0: r = gsl_rational_alloc(); break; case 2: den = get_poly_get(argv[0], &flag1); num = get_poly_get(argv[1], &flag2); r = gsl_rational_new(den, num); break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 2)", argc); break; } if (flag1 == 1) gsl_vector_free(den); if (flag2 == 1) gsl_vector_free(num); return Data_Wrap_Struct(klass, gsl_rational_mark, gsl_rational_free, r); } /* singleton */ static VALUE rb_gsl_poly_make_rational(VALUE obj, VALUE other) { gsl_rational *rnew = NULL; gsl_poly *p, *p2; size_t i; Data_Get_Struct(obj, gsl_poly, p); if (VECTOR_P(other)) { Data_Get_Struct(other, gsl_vector, p2); rnew = gsl_rational_new(p, p2); } else { switch (TYPE(other)) { case T_ARRAY: p2 = gsl_vector_alloc(RARRAY_LEN(other)); for (i = 0; i < p2->size; i++) gsl_vector_set(p2, i, NUM2DBL(rb_ary_entry(other, i))); rnew = gsl_rational_new(p, p2); gsl_vector_free(p2); break; case T_FLOAT: case T_FIXNUM: p2 = make_vector_clone(p); gsl_vector_scale(p2, 1.0/NUM2DBL(other)); return Data_Wrap_Struct(cgsl_poly, 0, gsl_vector_free, p2); break; default: rb_raise(rb_eTypeError, "wrong argument type %s", rb_class2name(CLASS_OF(other))); break; } } return Data_Wrap_Struct(cgsl_rational, gsl_rational_mark, gsl_rational_free, rnew); } static VALUE rb_gsl_rational_print(VALUE obj) { gsl_rational *r = NULL; Data_Get_Struct(obj, gsl_rational, r); gsl_vector_print(r->pnum, cgsl_vector); gsl_vector_print(r->pden, cgsl_vector); return Qnil; } static VALUE rb_gsl_rational_to_s(VALUE obj) { gsl_rational *r = NULL; VALUE str; Data_Get_Struct(obj, gsl_rational, r); str = rb_gsl_vector_to_s(r->num); rb_str_concat(str, rb_str_new2("\n")); rb_str_concat(str, rb_gsl_vector_to_s(r->den)); return str; } static VALUE rb_gsl_rational_inspect(VALUE obj) { VALUE str; str = rb_str_new2(rb_class2name(CLASS_OF(obj))); rb_str_concat(str, rb_str_new2("\n")); rb_str_concat(str, rb_gsl_rational_to_s(obj)); return str; } static VALUE rb_gsl_rational_add(VALUE obj, VALUE other) { gsl_rational *r = NULL, *r2 = NULL, *rnew = NULL; gsl_poly *p = NULL; int flag = 0; Data_Get_Struct(obj, gsl_rational, r); if (RATIONAL_P(other)) { Data_Get_Struct(other, gsl_rational, r2); rnew = gsl_rational_add(r, r2); } else { p = get_poly_get(other, &flag); rnew = gsl_rational_add_poly(r, p); if (flag == 1) gsl_vector_free(p); } return Data_Wrap_Struct(cgsl_rational, gsl_rational_mark, gsl_rational_free, rnew); } static VALUE rb_gsl_rational_deconv(VALUE obj) { gsl_rational *r = NULL; Data_Get_Struct(obj, gsl_rational, r); return rb_gsl_poly_deconv(r->num, r->den); } static VALUE rb_gsl_rational_uminus(VALUE obj) { gsl_rational *r = NULL, *rnew; gsl_poly *p = NULL, *ptmp; int flag = 0; size_t i; if (RATIONAL_P(obj)) { Data_Get_Struct(obj, gsl_rational, r); rnew = gsl_rational_new(r->pnum, r->pden); for (i = 0; i < rnew->pnum->size; i++) gsl_vector_set(rnew->pnum, i, -gsl_vector_get(r->pnum, i)); return Data_Wrap_Struct(cgsl_rational, gsl_rational_mark, gsl_rational_free, rnew); } else { if (POLY_P(obj)) { Data_Get_Struct(obj, gsl_vector, ptmp); p = make_vector_clone(ptmp); } else { p = get_poly_get(obj, &flag); } for (i = 0; i < p->size; i++) gsl_vector_set(p, i, -gsl_vector_get(p, i)); return Data_Wrap_Struct(cgsl_poly, 0, gsl_vector_free, p); } } static VALUE rb_gsl_rational_uplus(VALUE obj) { return obj; } static VALUE rb_gsl_rational_sub(VALUE obj, VALUE other) { return rb_gsl_rational_add(obj, rb_gsl_rational_uminus(other)); } static VALUE rb_gsl_rational_mul(VALUE obj, VALUE other) { gsl_rational *r = NULL, *r2 = NULL, *rnew = NULL; gsl_poly *p; int flag = 0; Data_Get_Struct(obj, gsl_rational, r); if (RATIONAL_P(other)) { Data_Get_Struct(other, gsl_rational, r2); rnew = gsl_rational_mul(r, r2); } else if (VECTOR_P(other)) { Data_Get_Struct(other, gsl_vector, p); rnew = gsl_rational_mul_poly(r, p); } else { p = get_poly_get(other, &flag); rnew = gsl_rational_mul_poly(r, p); gsl_vector_free(p); } return Data_Wrap_Struct(cgsl_rational, gsl_rational_mark, gsl_rational_free, rnew); } static VALUE rb_gsl_rational_div(VALUE obj, VALUE other) { gsl_rational *r = NULL, *r2 = NULL, *rnew = NULL; gsl_poly *p; size_t i; Data_Get_Struct(obj, gsl_rational, r); if (RATIONAL_P(other)) { Data_Get_Struct(other, gsl_rational, r2); rnew = gsl_rational_div(r, r2); } else if (VECTOR_P(other)) { Data_Get_Struct(other, gsl_vector, p); rnew = gsl_rational_div_poly(r, p); } else { switch (TYPE(other)) { case T_ARRAY: p = gsl_vector_alloc(RARRAY_LEN(other)); for (i = 0; i < p->size; i++) gsl_vector_set(p, i, NUM2DBL(rb_ary_entry(other, i))); rnew = gsl_rational_div_poly(r, p); gsl_vector_free(p); break; case T_FLOAT: case T_FIXNUM: rnew = gsl_rational_new(r->pnum, r->pden); gsl_vector_scale(rnew->pnum, 1.0/NUM2DBL(other)); break; default: rb_raise(rb_eTypeError, "wrong argument type %s", rb_class2name(CLASS_OF(other))); break; } } return Data_Wrap_Struct(cgsl_rational, gsl_rational_mark, gsl_rational_free, rnew); } static VALUE rb_gsl_rational_inverse(VALUE obj) { gsl_rational *r = NULL, *rnew = NULL; Data_Get_Struct(obj, gsl_rational, r); rnew = gsl_rational_inverse(r); return Data_Wrap_Struct(cgsl_rational, gsl_rational_mark, gsl_rational_free, rnew); } static VALUE rb_gsl_rational_den(VALUE obj) { gsl_rational *r = NULL; Data_Get_Struct(obj, gsl_rational, r); return r->den; } static VALUE rb_gsl_rational_num(VALUE obj) { gsl_rational *r = NULL; Data_Get_Struct(obj, gsl_rational, r); return r->num; } static VALUE rb_gsl_rational_coerce(VALUE obj, VALUE other) { gsl_rational *r = NULL; gsl_poly *p = NULL, *ptmp = NULL; size_t i; switch (TYPE(other)) { case T_FLOAT: case T_FIXNUM: p = gsl_vector_alloc(1); gsl_vector_set(p, 0, NUM2DBL(other)); break; case T_ARRAY: p = gsl_vector_alloc(RARRAY_LEN(other)); for (i = 0; i < p->size; i++) gsl_vector_set(p, i, NUM2DBL(rb_ary_entry(other, i))); break; default: CHECK_VECTOR(other); Data_Get_Struct(other, gsl_vector, ptmp); p = make_vector_clone(ptmp); break; } ptmp = gsl_vector_alloc(1); gsl_vector_set(ptmp, 0, 1.0); r = gsl_rational_new2(p, ptmp); return rb_ary_new3(2, Data_Wrap_Struct(cgsl_rational, gsl_rational_mark, gsl_rational_free, r), obj); } static VALUE rb_gsl_rational_zero(VALUE obj) { gsl_rational *r = NULL; Data_Get_Struct(obj, gsl_rational, r); return rb_gsl_poly_complex_solve(1, &(r->num), cgsl_rational); } static VALUE rb_gsl_rational_pole(VALUE obj) { gsl_rational *r = NULL; Data_Get_Struct(obj, gsl_rational, r); return rb_gsl_poly_complex_solve(1, &(r->den), cgsl_rational); } static VALUE rb_gsl_poly_inverse(VALUE obj) { gsl_poly *p = NULL, *ptmp = NULL; gsl_rational *r = NULL; Data_Get_Struct(obj, gsl_poly, p); ptmp = gsl_vector_alloc(1); gsl_vector_set(ptmp, 0, 1.0); r = gsl_rational_new(ptmp, p); gsl_vector_free(ptmp); return Data_Wrap_Struct(cgsl_rational, gsl_rational_mark, gsl_rational_free, r); } void Init_gsl_rational(VALUE module) { cgsl_rational = rb_define_class_under(module, "Rational", cGSL_Object); rb_define_singleton_method(cgsl_rational, "new", rb_gsl_rational_new, -1); rb_define_singleton_method(cgsl_rational, "[]", rb_gsl_rational_new, -1); rb_define_singleton_method(cgsl_rational, "alloc", rb_gsl_rational_new, -1); rb_define_method(cgsl_rational, "den", rb_gsl_rational_den, 0); rb_define_method(cgsl_rational, "num", rb_gsl_rational_num, 0); rb_define_method(cgsl_rational, "print", rb_gsl_rational_print, 0); rb_define_method(cgsl_rational, "to_s", rb_gsl_rational_to_s, 0); rb_define_method(cgsl_rational, "inspect", rb_gsl_rational_inspect, 0); rb_define_method(cgsl_rational, "deconv", rb_gsl_rational_deconv, 0); rb_define_method(cgsl_rational, "-@", rb_gsl_rational_uminus, 0); rb_define_method(cgsl_rational, "+@", rb_gsl_rational_uplus, 0); rb_define_method(cgsl_rational, "add", rb_gsl_rational_add, 1); rb_define_alias(cgsl_rational, "+", "add"); rb_define_method(cgsl_rational, "sub", rb_gsl_rational_sub, 1); rb_define_alias(cgsl_rational, "-", "sub"); rb_define_method(cgsl_rational, "mul", rb_gsl_rational_mul, 1); rb_define_alias(cgsl_rational, "*", "mul"); rb_define_method(cgsl_rational, "div", rb_gsl_rational_div, 1); rb_define_alias(cgsl_rational, "/", "div"); rb_define_method(cgsl_rational, "inverse", rb_gsl_rational_inverse, 0); rb_define_alias(cgsl_rational, "inv", "inverse"); /***** Methods of poly *****/ rb_define_method(cgsl_poly, "inverse", rb_gsl_poly_inverse, 0); rb_define_alias(cgsl_poly, "inv", "inverse"); rb_define_method(cgsl_poly, "make_rational", rb_gsl_poly_make_rational, 1); rb_define_alias(cgsl_poly, "/", "make_rational"); rb_define_method(cgsl_rational, "coerce", rb_gsl_rational_coerce, 1); rb_define_method(cgsl_rational, "zero", rb_gsl_rational_zero, 0); rb_define_method(cgsl_rational, "pole", rb_gsl_rational_pole, 0); }