/*
* Copyright (c) 2002-2006 Samit Basu
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "Core.hpp"
#include "Exception.hpp"
#include "Array.hpp"
#include "Malloc.hpp"
#include "Utils.hpp"
#include <math.h>
#include "IEEEFP.hpp"
//!
//@Module LOG1P Natural Logarithm of 1+P Function
//@@Section MATHFUNCTIONS
//@@Usage
//Computes the @|log| function for one plus its argument. The general
//syntax for its use is
//@[
// y = log1p(x)
//@]
//where @|x| is an @|n|-dimensional array of numerical type.
//!
ArrayVector Log1PFunction(int nargout, const ArrayVector& arg) {
if (arg.size() != 1)
throw Exception("Log1p function takes exactly one argument");
Array input(arg[0]);
Array output;
Class argType(input.dataClass());
if (argType < FM_FLOAT) {
input.promoteType(FM_DOUBLE);
argType = FM_DOUBLE;
}
if (argType > FM_DCOMPLEX)
throw Exception("argument to log must be numeric");
switch (argType) {
case FM_FLOAT: {
if (input.isPositive()) {
const float *dp=((const float *)input.getDataPointer());
int len(input.getLength());
float *op = (float *)Malloc(len*sizeof(float));
for (int i=0;i<len;i++)
op[i] = log1p(dp[i]);
output = Array(FM_FLOAT,input.dimensions(),op);
} else {
const float *dp=((const float *)input.getDataPointer());
int len(input.getLength());
float *op = (float *)Malloc(2*len*sizeof(float));
for (int i=0;i<len;i++)
if (dp[i] >= -1.0)
op[2*i] = log1p(dp[i]);
else {
op[2*i] = log1p(fabs(dp[i]));
op[2*i+1] = M_PI;
}
output = Array(FM_COMPLEX,input.dimensions(),op);
}
break;
}
case FM_DOUBLE: {
if (input.isPositive()) {
const double *dp=((const double *)input.getDataPointer());
int len(input.getLength());
double *op = (double *)Malloc(len*sizeof(double));
for (int i=0;i<len;i++)
op[i] = log1p(dp[i]);
output = Array(FM_DOUBLE,input.dimensions(),op);
} else {
const double *dp=((const double *)input.getDataPointer());
int len(input.getLength());
double *op = (double *)Malloc(2*len*sizeof(double));
for (int i=0;i<len;i++)
if (dp[i] >= -1.0)
op[2*i] = log1p(dp[i]);
else {
op[2*i] = log1p(fabs(dp[i]));
op[2*i+1] = M_PI;
}
output = Array(FM_DCOMPLEX,input.dimensions(),op);
}
break;
}
case FM_COMPLEX: {
const float *dp=((const float *)input.getDataPointer());
int len(input.getLength());
float *op = (float *)Malloc(len*sizeof(float)*2);
for (int i=0;i<2*len;i+=2) {
op[i] = log1p(complex_abs(dp[i],dp[i+1]));
op[i+1] = atan2(dp[i+1],dp[i]);
}
output = Array(FM_COMPLEX,input.dimensions(),op);
break;
}
case FM_DCOMPLEX: {
const double *dp=((const double *)input.getDataPointer());
int len(input.getLength());
double *op = (double *)Malloc(len*sizeof(double)*2);
for (int i=0;i<2*len;i+=2) {
op[i] = log1p(complex_abs(dp[i],dp[i+1]));
op[i+1] = atan2(dp[i+1],dp[i]);
}
output = Array(FM_DCOMPLEX,input.dimensions(),op);
break;
}
}
ArrayVector retval;
retval.push_back(output);
return retval;
}
//!
//@Module LOG Natural Logarithm Function
//@@Section MATHFUNCTIONS
//@@Usage
//Computes the @|log| function for its argument. The general
//syntax for its use is
//@[
// y = log(x)
//@]
//where @|x| is an @|n|-dimensional array of numerical type.
//Integer types are promoted to the @|double| type prior to
//calculation of the @|log| function. Output @|y| is of the
//same size as the input @|x|. For strictly positive, real inputs,
//the output type is the same as the input.
//For negative and complex arguments, the output is complex.
//@@Function Internals
//Mathematically, the @|log| function is defined for all real
//valued arguments @|x| by the integral
//\[
// \log x \equiv \int_1^{x} \frac{d\,t}{t}.
//\]
//For complex-valued arguments, @|z|, the complex logarithm is
//defined as
//\[
// \log z \equiv \log |z| + i \arg z,
//\]
//where @|arg| is the complex argument of @|z|.
//@@Example
//The following piece of code plots the real-valued @|log|
//function over the interval @|[1,100]|:
//@<
//x = linspace(1,100);
//plot(x,log(x))
//xlabel('x');
//ylabel('log(x)');
//mprint('logplot');
//@>
//@figure logplot
//!
ArrayVector LogFunction(int nargout, const ArrayVector& arg) {
if (arg.size() != 1)
throw Exception("Log function takes exactly one argument");
Array input(arg[0]);
Array output;
Class argType(input.dataClass());
if (argType < FM_FLOAT) {
input.promoteType(FM_DOUBLE);
argType = FM_DOUBLE;
}
if (argType > FM_DCOMPLEX)
throw Exception("argument to log must be numeric");
switch (argType) {
case FM_FLOAT: {
if (input.isPositive()) {
const float *dp=((const float *)input.getDataPointer());
int len(input.getLength());
float *op = (float *)Malloc(len*sizeof(float));
for (int i=0;i<len;i++)
op[i] = log(dp[i]);
output = Array(FM_FLOAT,input.dimensions(),op);
} else {
const float *dp=((const float *)input.getDataPointer());
int len(input.getLength());
float *op = (float *)Malloc(2*len*sizeof(float));
for (int i=0;i<len;i++)
if (dp[i] >= 0.0)
op[2*i] = log(dp[i]);
else {
op[2*i] = log(fabs(dp[i]));
op[2*i+1] = M_PI;
}
output = Array(FM_COMPLEX,input.dimensions(),op);
}
break;
}
case FM_DOUBLE: {
if (input.isPositive()) {
const double *dp=((const double *)input.getDataPointer());
int len(input.getLength());
double *op = (double *)Malloc(len*sizeof(double));
for (int i=0;i<len;i++)
op[i] = log(dp[i]);
output = Array(FM_DOUBLE,input.dimensions(),op);
} else {
const double *dp=((const double *)input.getDataPointer());
int len(input.getLength());
double *op = (double *)Malloc(2*len*sizeof(double));
for (int i=0;i<len;i++)
if (dp[i] >= 0.0)
op[2*i] = log(dp[i]);
else {
op[2*i] = log(fabs(dp[i]));
op[2*i+1] = M_PI;
}
output = Array(FM_DCOMPLEX,input.dimensions(),op);
}
break;
}
case FM_COMPLEX: {
const float *dp=((const float *)input.getDataPointer());
int len(input.getLength());
float *op = (float *)Malloc(len*sizeof(float)*2);
for (int i=0;i<2*len;i+=2) {
op[i] = log(complex_abs(dp[i],dp[i+1]));
op[i+1] = atan2(dp[i+1],dp[i]);
}
output = Array(FM_COMPLEX,input.dimensions(),op);
break;
}
case FM_DCOMPLEX: {
const double *dp=((const double *)input.getDataPointer());
int len(input.getLength());
double *op = (double *)Malloc(len*sizeof(double)*2);
for (int i=0;i<2*len;i+=2) {
op[i] = log(complex_abs(dp[i],dp[i+1]));
op[i+1] = atan2(dp[i+1],dp[i]);
}
output = Array(FM_DCOMPLEX,input.dimensions(),op);
break;
}
}
ArrayVector retval;
retval.push_back(output);
return retval;
}
//!
//@Module EXP Exponential Function
//@@Section MATHFUNCTIONS
//@@Usage
//Computes the @|exp| function for its argument. The general
//syntax for its use is
//@[
// y = exp(x)
//@]
//where @|x| is an @|n|-dimensional array of numerical type.
//Integer types are promoted to the @|double| type prior to
//calculation of the @|exp| function. Output @|y| is of the
//same size and type as the input @|x|, (unless @|x| is an
//integer, in which case @|y| is a @|double| type).
//@@Function Internals
//Mathematically, the @|exp| function is defined for all real
//valued arguments @|x| as
//\[
// \exp x \equiv e^{x},
//\]
//where
//\[
// e = \sum_{0}^{\infty} \frac{1}{k!}
//\]
//and is approximately @|2.718281828459045| (returned by the function
//@|e|). For complex values
//@|z|, the famous Euler formula is used to calculate the
//exponential
//\[
// e^{z} = e^{|z|} \left[ \cos \Re z + i \sin \Re z \right]
//\]
//@@Example
//The following piece of code plots the real-valued @|exp|
//function over the interval @|[-1,1]|:
//@<
//x = linspace(-1,1);
//plot(x,exp(x))
//mprint('expplot1');
//@>
//@figure expplot1
//In the second example, we plot the unit circle in the
//complex plane @|e^{i 2 pi x}| for @|x in [-1,1]|.
//@<
//x = linspace(-1,1);
//plot(exp(-i*x*2*pi))
//mprint('expplot2');
//@>
//@figure expplot2
//!
ArrayVector ExpFunction(int nargout, const ArrayVector& arg) {
if (arg.size() != 1)
throw Exception("Exp function takes exactly one argument");
Array input(arg[0]);
Array output;
Class argType(input.dataClass());
if (argType < FM_FLOAT) {
input.promoteType(FM_DOUBLE);
argType = FM_DOUBLE;
}
if (argType > FM_DCOMPLEX)
throw Exception("argument to exp must be numeric");
switch (argType) {
case FM_FLOAT: {
const float *dp=((const float *)input.getDataPointer());
int len(input.getLength());
float *op = (float *)Malloc(len*sizeof(float));
for (int i=0;i<len;i++)
op[i] = exp(dp[i]);
output = Array(FM_FLOAT,input.dimensions(),op);
break;
}
case FM_DOUBLE: {
const double *dp=((const double *)input.getDataPointer());
int len(input.getLength());
double *op = (double *)Malloc(len*sizeof(double));
for (int i=0;i<len;i++)
op[i] = exp(dp[i]);
output = Array(FM_DOUBLE,input.dimensions(),op);
break;
}
case FM_COMPLEX: {
const float *dp=((const float *)input.getDataPointer());
int len(input.getLength());
float *op = (float *)Malloc(len*sizeof(float)*2);
for (int i=0;i<2*len;i+=2) {
double t = exp(dp[i]);
op[i] = t*cos(dp[i+1]);
op[i+1] = t*sin(dp[i+1]);
}
output = Array(FM_COMPLEX,input.dimensions(),op);
break;
}
case FM_DCOMPLEX: {
const double *dp=((const double *)input.getDataPointer());
int len(input.getLength());
double *op = (double *)Malloc(len*sizeof(double)*2);
for (int i=0;i<2*len;i+=2) {
double t = exp(dp[i]);
op[i] = t*cos(dp[i+1]);
op[i+1] = t*sin(dp[i+1]);
}
output = Array(FM_DCOMPLEX,input.dimensions(),op);
break;
}
}
ArrayVector retval;
retval.push_back(output);
return retval;
}
//!
//@Module EXPM1 Exponential Minus One Function
//@@Section MATHFUNCTIONS
//@@Usage
//Computes @|exp(x)-1| function accurately for @|x|
//small. The syntax for its use is
//@[
// y = expm1(x)
//@]
//where @|x| is an @|n|-dimensional array of numerical type.
//!
ArrayVector ExpM1Function(int nargout, const ArrayVector& arg) {
if (arg.size() != 1)
throw Exception("ExpM1 function takes exactly one argument");
Array input(arg[0]);
Array output;
Class argType(input.dataClass());
if (argType < FM_FLOAT) {
input.promoteType(FM_DOUBLE);
argType = FM_DOUBLE;
}
if (argType > FM_DCOMPLEX)
throw Exception("argument to expm1 must be numeric");
switch (argType) {
case FM_FLOAT: {
const float *dp=((const float *)input.getDataPointer());
int len(input.getLength());
float *op = (float *)Malloc(len*sizeof(float));
for (int i=0;i<len;i++)
op[i] = expm1(dp[i]);
output = Array(FM_FLOAT,input.dimensions(),op);
break;
}
case FM_DOUBLE: {
const double *dp=((const double *)input.getDataPointer());
int len(input.getLength());
double *op = (double *)Malloc(len*sizeof(double));
for (int i=0;i<len;i++)
op[i] = expm1(dp[i]);
output = Array(FM_DOUBLE,input.dimensions(),op);
break;
}
case FM_COMPLEX: {
const float *dp=((const float *)input.getDataPointer());
int len(input.getLength());
float *op = (float *)Malloc(len*sizeof(float)*2);
for (int i=0;i<2*len;i+=2) {
double t = expm1(dp[i]);
op[i] = t*cos(dp[i+1]);
op[i+1] = t*sin(dp[i+1]);
}
output = Array(FM_COMPLEX,input.dimensions(),op);
break;
}
case FM_DCOMPLEX: {
const double *dp=((const double *)input.getDataPointer());
int len(input.getLength());
double *op = (double *)Malloc(len*sizeof(double)*2);
for (int i=0;i<2*len;i+=2) {
double t = expm1(dp[i]);
op[i] = t*cos(dp[i+1]);
op[i+1] = t*sin(dp[i+1]);
}
output = Array(FM_DCOMPLEX,input.dimensions(),op);
break;
}
}
ArrayVector retval;
retval.push_back(output);
return retval;
}
syntax highlighted by Code2HTML, v. 0.9.1