rational_funcs.tcl

Go to the documentation of this file.
00001 /*  rational_funcs.tcl --*/
00002 /*     Implement procedures to deal with rational functions*/
00003 /* */
00004 
00005 package require math::polynomials
00006 
00007 namespace ::math::rationalfunctions {
00008     variable count 0  ;/*  Count the number of specific commands*/
00009     namespace v {}
00010 
00011     namespace export rationalFunction ratioCmd evalRatio \
00012                      coeffsNumerator coeffsDenominator \
00013                      derivRatio  \
00014                      addRatio    subRatio multRatio \
00015                      divRatio
00016 
00017     namespace import ::math::polynomials::*
00018 }
00019 
00020 
00021 /*  rationalFunction --*/
00022 /*     Return a rational function definition*/
00023 /* */
00024 /*  Arguments:*/
00025 /*     num          The coefficients of the numerator*/
00026 /*     den          The coefficients of the denominator*/
00027 /*  Result:*/
00028 /*     Rational function definition*/
00029 /* */
00030 ret  ::math::rationalfunctions::rationalFunction (type num , type den) {
00031 
00032     foreach coeffs [list $num $den] {
00033         foreach coeff $coeffs {
00034             if { ! [string is double -strict $coeff] } {
00035                 return -code error "Coefficients must be real numbers"
00036             }
00037         }
00038     }
00039 
00040     #
00041     # The leading coefficient must be non-zero
00042     #
00043     return [list RATIONAL_FUNCTION [polynomial $num] [polynomial $den]]
00044 }
00045 
00046 /*  ratioCmd --*/
00047 /*     Return a procedure that implements a rational function evaluation*/
00048 /* */
00049 /*  Arguments:*/
00050 /*     num          The coefficients of the numerator*/
00051 /*     den          The coefficients of the denominator*/
00052 /*  Result:*/
00053 /*     New procedure*/
00054 /* */
00055 ret  ::math::rationalfunctions::ratioCmd (type num , optional den ={)} {
00056     variable count
00057 
00058     if { [llength $den] == 0 } {
00059         if { [lindex $num 0] == "RATIONAL_FUNCTION" } {
00060              den =  [lindex $num 2]
00061              num =  [lindex $num 1]
00062         }
00063     }
00064 
00065      degree1 =  [expr {[llength $num]-1}]
00066      degree2 =  [expr {[llength $num]-1}]
00067      body =  "expr \{([join $num +\$x*(][string repeat ) $degree1])/\
00068 (double([join $den +\$x*(][string repeat ) $degree2])\}"
00069 
00070     incr count
00071      name =  "::math::rationalfunctions::v::RATIO$count"
00072     ret  $name (type x) $body
00073     return $name
00074 }
00075 
00076 # evalRatio --
00077 #    Evaluate a rational function at a given coordinate
00078 #
00079 # Arguments:
00080 #    ratio        Rational function definition
00081 #    x            Coordinate
00082 # Result:
00083 #    Value at x
00084 #
00085 proc ::math::rationalfunctions::evalRatio {ratio x} {
00086     if { [lindex $ratio 0] != "RATIONAL_FUNCTION" } {
00087         return -code error "Not a rational function"
00088     }
00089     if { ! [string is double $x] } {
00090         return -code error "Coordinate must be a real number"
00091     }
00092 
00093      num =  0.0
00094     foreach c [lindex [lindex $ratio 1] 1] {
00095          num =  [expr {$num*$x+$c}]
00096     }
00097 
00098      den =  0.0
00099     foreach c [lindex [lindex $ratio 2] 1] {
00100          den =  [expr {$den*$x+$c}]
00101     }
00102     return [expr {$num/double($den)}]
00103 }
00104 
00105 /*  coeffsNumerator --*/
00106 /*     Return the coefficients of the numerator*/
00107 /* */
00108 /*  Arguments:*/
00109 /*     ratio        Rational function definition*/
00110 /*  Result:*/
00111 /*     The coefficients in ascending order*/
00112 /* */
00113 ret  ::math::rationalfunctions::coeffsNumerator (type ratio) {
00114     if { [lindex $ratio 0] != "RATIONAL_FUNCTION" } {
00115         return -code error "Not a rational function"
00116     }
00117     set polyn [lindex $ratio 1]
00118     return [allCoeffsPolyn $polyn]
00119 }
00120 
00121 /*  coeffsDenominator --*/
00122 /*     Return the coefficients of the denominator*/
00123 /* */
00124 /*  Arguments:*/
00125 /*     ratio        Rational function definition*/
00126 /*  Result:*/
00127 /*     The coefficients in ascending order*/
00128 /* */
00129 ret  ::math::rationalfunctions::coeffsDenominator (type ratio) {
00130     if { [lindex $ratio 0] != "RATIONAL_FUNCTION" } {
00131         return -code error "Not a rational function"
00132     }
00133     set polyn [lindex $ratio 2]
00134     return [allCoeffsPolyn $polyn]
00135 }
00136 
00137 /*  derivRatio --*/
00138 /*     Return the derivative of the rational function*/
00139 /* */
00140 /*  Arguments:*/
00141 /*     polyn        Polynomial definition*/
00142 /*  Result:*/
00143 /*     The new polynomial*/
00144 /* */
00145 ret  ::math::rationalfunctions::derivRatio (type ratio) {
00146     if { [lindex $ratio 0] != "RATIONAL_FUNCTION" } {
00147         return -code error "Not a rational function"
00148     }
00149     set num_polyn [lindex $ratio 1]
00150     set den_polyn [lindex $ratio 2]
00151     set num_deriv [derivPolyn $num_polyn]
00152     set den_deriv [derivPolyn $den_polyn]
00153     set num       [subPolyn [multPolyn $num_deriv $den_polyn] \
00154                             [multPolyn $den_deriv $num_polyn] ]
00155     set den       [multPolyn $den_polyn $den_polyn]
00156 
00157     return [list RATIONAL_FUNCTION $num $den]
00158 }
00159 
00160 /*  addRatio --*/
00161 /*     Add two rational functions and return the result*/
00162 /* */
00163 /*  Arguments:*/
00164 /*     ratio1       First rational function or a scalar*/
00165 /*     ratio2       Second rational function or a scalar*/
00166 /*  Result:*/
00167 /*     The sum of the two functions*/
00168 /*  Note:*/
00169 /*     TODO: Check for the same denominator*/
00170 /* */
00171 ret  ::math::rationalfunctions::addRatio (type ratio1 , type ratio2) {
00172     if { [llength $ratio1] == 1 && [string is double -strict $ratio1] } {
00173         set polyn1 [rationalFunction $ratio1 1.0]
00174     }
00175     if { [llength $ratio2] == 1 && [string is double -strict $ratio2] } {
00176         set ratio2 [rationalFunction $ratio1 1.0]
00177     }
00178     if { [lindex $ratio1 0] != "RATIONAL_FUNCTION" ||
00179          [lindex $ratio2 0] != "RATIONAL_FUNCTION" } {
00180         return -code error "Both arguments must be rational functions or a real number"
00181     }
00182 
00183     set num1    [lindex $ratio1 1]
00184     set den1    [lindex $ratio1 2]
00185     set num2    [lindex $ratio2 1]
00186     set den2    [lindex $ratio2 2]
00187 
00188     set newnum  [addPolyn [multPolyn $num1 $den2] \
00189                           [multPolyn $num2 $den1] ]
00190 
00191     set newden  [multPolyn $den1 $den2]
00192 
00193     return [list RATIONAL_FUNCTION $newnum $newden]
00194 }
00195 
00196 /*  subRatio --*/
00197 /*     Subtract two rational functions and return the result*/
00198 /* */
00199 /*  Arguments:*/
00200 /*     ratio1       First rational function or a scalar*/
00201 /*     ratio2       Second rational function or a scalar*/
00202 /*  Result:*/
00203 /*     The difference of the two functions*/
00204 /*  Note:*/
00205 /*     TODO: Check for the same denominator*/
00206 /* */
00207 ret  ::math::rationalfunctions::subRatio (type ratio1 , type ratio2) {
00208     if { [llength $ratio1] == 1 && [string is double -strict $ratio1] } {
00209         set polyn1 [rationalFunction $ratio1 1.0]
00210     }
00211     if { [llength $ratio2] == 1 && [string is double -strict $ratio2] } {
00212         set ratio2 [rationalFunction $ratio1 1.0]
00213     }
00214     if { [lindex $ratio1 0] != "RATIONAL_FUNCTION" ||
00215          [lindex $ratio2 0] != "RATIONAL_FUNCTION" } {
00216         return -code error "Both arguments must be rational functions or a real number"
00217     }
00218 
00219     set num1    [lindex $ratio1 1]
00220     set den1    [lindex $ratio1 2]
00221     set num2    [lindex $ratio2 1]
00222     set den2    [lindex $ratio2 2]
00223 
00224     set newnum  [subPolyn [multPolyn $num1 $den2] \
00225                           [multPolyn $num2 $den1] ]
00226 
00227     set newden  [multPolyn $den1 $den2]
00228 
00229     return [list RATIONAL_FUNCTION $newnum $newden]
00230 }
00231 
00232 /*  multRatio --*/
00233 /*     Multiply two rational functions and return the result*/
00234 /* */
00235 /*  Arguments:*/
00236 /*     ratio1       First rational function or a scalar*/
00237 /*     ratio2       Second rational function or a scalar*/
00238 /*  Result:*/
00239 /*     The product of the two functions*/
00240 /*  Note:*/
00241 /*     TODO: Check for the same denominator*/
00242 /* */
00243 ret  ::math::rationalfunctions::multRatio (type ratio1 , type ratio2) {
00244     if { [llength $ratio1] == 1 && [string is double -strict $ratio1] } {
00245         set polyn1 [rationalFunction $ratio1 1.0]
00246     }
00247     if { [llength $ratio2] == 1 && [string is double -strict $ratio2] } {
00248         set ratio2 [rationalFunction $ratio1 1.0]
00249     }
00250     if { [lindex $ratio1 0] != "RATIONAL_FUNCTION" ||
00251          [lindex $ratio2 0] != "RATIONAL_FUNCTION" } {
00252         return -code error "Both arguments must be rational functions or a real number"
00253     }
00254 
00255     set num1    [lindex $ratio1 1]
00256     set den1    [lindex $ratio1 2]
00257     set num2    [lindex $ratio2 1]
00258     set den2    [lindex $ratio2 2]
00259 
00260     set newnum  [multPolyn $num1 $num2]
00261     set newden  [multPolyn $den1 $den2]
00262 
00263     return [list RATIONAL_FUNCTION $newnum $newden]
00264 }
00265 
00266 /*  divRatio --*/
00267 /*     Divide two rational functions and return the result*/
00268 /* */
00269 /*  Arguments:*/
00270 /*     ratio1       First rational function or a scalar*/
00271 /*     ratio2       Second rational function or a scalar*/
00272 /*  Result:*/
00273 /*     The quotient of the two functions*/
00274 /*  Note:*/
00275 /*     TODO: Check for the same denominator*/
00276 /* */
00277 ret  ::math::rationalfunctions::divRatio (type ratio1 , type ratio2) {
00278     if { [llength $ratio1] == 1 && [string is double -strict $ratio1] } {
00279         set polyn1 [rationalFunction $ratio1 1.0]
00280     }
00281     if { [llength $ratio2] == 1 && [string is double -strict $ratio2] } {
00282         set ratio2 [rationalFunction $ratio1 1.0]
00283     }
00284     if { [lindex $ratio1 0] != "RATIONAL_FUNCTION" ||
00285          [lindex $ratio2 0] != "RATIONAL_FUNCTION" } {
00286         return -code error "Both arguments must be rational functions or a real number"
00287     }
00288 
00289     set num1    [lindex $ratio1 1]
00290     set den1    [lindex $ratio1 2]
00291     set num2    [lindex $ratio2 1]
00292     set den2    [lindex $ratio2 2]
00293 
00294     set newnum  [multPolyn $num1 $den2]
00295     set newden  [multPolyn $num2 $den1]
00296 
00297     return [list RATIONAL_FUNCTION $newnum $newden]
00298 }
00299 
00300 /* */
00301 /*  Announce our presence*/
00302 /* */
00303 package provide math::rationalfunctions 1.0.1
00304 
00305 /*  some tests --*/
00306 /* */
00307 if { 0 } {
00308  tcl = _precision 17
00309 
00310  f1 =     [::math::rationalfunctions::rationalFunction {1 2 3} {1 4}]
00311  f2 =     [::math::rationalfunctions::rationalFunction {1 2 3 0} {1 4}]
00312  f3 =     [::math::rationalfunctions::rationalFunction {0 0 0 0} {1}]
00313  f4 =     [::math::rationalfunctions::rationalFunction {5 7} {1}]
00314  cmdf1 =  [::math::rationalfunctions::ratioCmd {1 2 3} {1 4}]
00315 
00316 foreach x {0 1 2 3 4 5} {
00317     puts "[::math::rationalfunctions::evalRatio $f1 $x] -- \
00318 [expr {(1.0+2.0*$x+3.0*$x*$x)/double(1.0+4.0*$x)}] -- \
00319 [$cmdf1 $x] -- [::math::rationalfunctions::evalRatio $f3 $x]"
00320 }
00321 
00322 puts "All coefficients = [::math::rationalfunctions::coeffsNumerator $f2]"
00323 puts "                   [::math::rationalfunctions::coeffsDenominator $f2]"
00324 
00325 puts "Derivative = [::math::rationalfunctions::derivRatio $f1]"
00326 
00327 puts "Add:       [::math::rationalfunctions::addRatio $f1 $f4]"
00328 puts "Add:       [::math::rationalfunctions::addRatio $f4 $f1]"
00329 puts "Subtract:  [::math::rationalfunctions::subRatio $f1 $f4]"
00330 puts "Multiply:  [::math::rationalfunctions::multRatio $f1 $f4]"
00331 
00332  f1 =     [::math::rationalfunctions::rationalFunction {1 2 3} 1]
00333  f2 =     [::math::rationalfunctions::rationalFunction {0 1} 1]
00334 
00335 puts "Divide:    [::math::rationalfunctions::divRatio $f1 $f2]"
00336 
00337  f1 =     [::math::rationalfunctions::rationalFunction {1 2 3} 1]
00338  f2 =     [::math::rationalfunctions::rationalFunction {1 1} {1 2}]
00339 
00340 puts "Divide:    [::math::rationalfunctions::divRatio $f1 $f2]"
00341 
00342  f1 =  [::math::rationalfunctions::rationalFunction {1 2 3} 1]
00343  f2 =  [::math::rationalfunctions::rationalFunction {0 1} {0 0 1}]
00344  f3 =  [::math::rationalfunctions::divRatio $f2 $f1]
00345  coeffs =  [::math::rationalfunctions::coeffsNumerator $f3]
00346 puts "Coefficients: $coeffs"
00347  f3 =  [::math::rationalfunctions::divRatio $f1 $f2]
00348  coeffs =  [::math::rationalfunctions::coeffsNumerator $f3]
00349 puts "Coefficients: $coeffs"
00350  f1 =  [::math::rationalfunctions::rationalFunction {1 2 3} {1 2}]
00351  f2 =  [::math::rationalfunctions::rationalFunction {0} {1}]
00352  f3 =  [::math::rationalfunctions::divRatio $f2 $f1]
00353  coeffs =  [::math::rationalfunctions::coeffsNumerator $f3]
00354 puts "Coefficients: $coeffs"
00355 puts "Eval null function: [::math::rationalfunctions::evalRatio $f2 1]"
00356 }
00357 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1