gambas-source-code/gb.gsl/src/c_vector.c
gambas 09a0573e61 Replace my old sourceforge mail address by the new one.
[CONFIGURATION]
Replace my old sourceforge mail address by the new one.
2018-02-12 02:53:46 +01:00

817 lines
17 KiB
C

/***************************************************************************
c_vector.c
gb.gsl component
(c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>
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 1, 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., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#define __C_VECTOR_C
#include "c_complex.h"
#include "c_polynomial.h"
#include "c_vector.h"
#define THIS ((CVECTOR *)_object)
#define COMPLEX(_v) ((_v)->complex)
//---- Utility functions ----------------------------------------------
/*int gsl_vector_has_zero(gsl_vector *a)
{
int i;
int size = (int)a->size;
for (i = 0; i < size; i++)
{
if (gsl_vector_get(a, i) == 0.0)
return TRUE;
}
return FALSE;
}
int gsl_vector_complex_has_zero(gsl_vector *a)
{
int i;
int size = (int)a->size;
gsl_complex *p:
for (i = 0; i < size; i++)
{
p = gsl_vector_complex_ptr((gsl_vector_complext *)a, i);
if (p->dat[0] == 0.0 && p->dat[1] == 0.0)
return TRUE;
}
return FALSE;
}
void gsl_vector_inverse(gsl_vector *a)
{
int i;
int size = (int)a->size;
double *p;
for (i = 0; i < size; i++)
{
p = gsl_vector_ptr(a, i);
*p = 1.0 / *p;
}
}
void gsl_vector_complex_inverse(gsl_vector *a)
{
int i;
int size = (int)a->size;
gsl_complex *p;
for (i = 0; i < size; i++)
{
p = gsl_vector_complex_ptr((gsl_vector_complex *)a, i);
*p = gsl_complex_inverse(*p);
}
}
void gsl_vector_negative(gsl_vector *a)
{
int i;
int size = (int)a->size;
double *p;
for (i = 0; i < size; i++)
{
p = gsl_vector_ptr(a, i);
*p = (- *p);
}
}
void gsl_vector_complex_negative(gsl_vector *a)
{
int i;
int size = (int)a->size;
gsl_complex *p;
for (i = 0; i < size; i++)
{
p = gsl_vector_complex_ptr((gsl_vector_complext *)a, i);
*p = gsl_complex_negative(*p);
}
}*/
//---- Vector creation ------------------------------------------------------
//static bool _do_not_init = FALSE;
CVECTOR *VECTOR_create(int size, bool complex, bool init)
{
CVECTOR *v = (CVECTOR *)GB.Create(CLASS_Vector, NULL, NULL);
v->complex = complex;
if (!complex)
v->vector = init ? gsl_vector_calloc(size) : gsl_vector_alloc(size);
else
v->vector = init ? gsl_vector_complex_calloc(size) : gsl_vector_complex_alloc(size);
//GB.Push(2, GB_T_INTEGER, size, GB_T_BOOLEAN, complex);
//return (CVECTOR *)GB.New(CLASS_Vector, NULL, (void *)(intptr_t)2);
return v;
}
/*CVECTOR *VECTOR_create_from(void *vector, bool complex)
{
int size = ((gsl_vector *)vector)->size;
CVECTOR *v = VECTOR_create(size, complex, FALSE);
if (complex)
gsl_vector_complex_free(CVEC(v));
else
gsl_vector_free(VEC(v));
v->vector = vector;
return v;
}*/
static CVECTOR *VECTOR_copy(CVECTOR *_object)
{
CVECTOR *copy = VECTOR_create(SIZE(THIS), COMPLEX(THIS), FALSE);
if (!COMPLEX(THIS))
gsl_vector_memcpy(VEC(copy), VEC(THIS));
else
gsl_vector_complex_memcpy(CVEC(copy), CVEC(THIS));
return copy;
}
#define VECTOR_make(_a) (((_a)->ob.ref <= 1) ? (_a) : VECTOR_copy(_a))
static CVECTOR *VECTOR_convert_to_complex(CVECTOR *_object)
{
CVECTOR *v = VECTOR_create(SIZE(THIS), TRUE, FALSE);
int i;
for (i = 0; i < SIZE(THIS); i++)
gsl_vector_complex_set((gsl_vector_complex *)v->vector, i, gsl_complex_rect(gsl_vector_get(VEC(THIS), i), 0));
return v;
}
void VECTOR_ensure_complex(CVECTOR *_object)
{
gsl_vector_complex *v;
int size = SIZE(THIS);
int i;
if (COMPLEX(THIS))
return;
v = gsl_vector_complex_alloc(size);
for (i = 0; i < size; i++)
gsl_vector_complex_set(v, i, gsl_complex_rect(gsl_vector_get(VEC(THIS), i), 0));
gsl_vector_free(VEC(THIS));
THIS->vector = v;
THIS->complex = TRUE;
}
bool VECTOR_ensure_not_complex(CVECTOR *_object)
{
gsl_vector *v;
int size = SIZE(THIS);
int i;
gsl_complex c;
if (!COMPLEX(THIS))
return FALSE;
for (i = 0; i < size; i++)
{
c = gsl_vector_complex_get(CVEC(THIS), i);
if (GSL_IMAG(c) != 0.0)
return TRUE;
}
v = gsl_vector_alloc(size);
for (i = 0; i < size; i++)
gsl_vector_set(v, i, GSL_REAL(gsl_vector_complex_get(CVEC(THIS), i)));
gsl_vector_complex_free(CVEC(THIS));
THIS->vector = v;
THIS->complex = FALSE;
return FALSE;
}
//---- Arithmetic operators -------------------------------------------------
static CVECTOR *_add(CVECTOR *a, CVECTOR *b, bool invert)
{
CVECTOR *v = VECTOR_make(a);
if (COMPLEX(v) || COMPLEX(b))
{
VECTOR_ensure_complex(v);
VECTOR_ensure_complex(b);
gsl_vector_complex_add(CVEC(v), CVEC(b));
}
else
gsl_vector_add(VEC(v), VEC(b));
return v;
}
static CVECTOR *_sub(CVECTOR *a, CVECTOR *b, bool invert)
{
CVECTOR *v = VECTOR_make(a);
if (COMPLEX(v) || COMPLEX(b))
{
VECTOR_ensure_complex(v);
VECTOR_ensure_complex(b);
gsl_vector_complex_sub(CVEC(v), CVEC(b));
}
else
gsl_vector_sub(VEC(v), VEC(b));
return v;
}
static CVECTOR *_mulf(CVECTOR *a, double f, bool invert)
{
CVECTOR *v = VECTOR_make(a);
if (COMPLEX(v))
gsl_vector_complex_scale(CVEC(v), gsl_complex_rect(f, 0));
else
gsl_vector_scale(VEC(v), f);
return v;
}
static CVECTOR *_mulo(CVECTOR *a, void *b, bool invert)
{
CVECTOR *v = VECTOR_make(a);
if (!GB.Is(b, CLASS_Complex))
return NULL;
VECTOR_ensure_complex(v);
gsl_vector_complex_scale(CVEC(v), ((CCOMPLEX *)b)->number);
return v;
}
static CVECTOR *_divf(CVECTOR *a, double f, bool invert)
{
if (invert)
return NULL;
if (f == 0.0)
{
GB.Error(GB_ERR_ZERO);
return NULL;
}
return _mulf(a, 1 / f, FALSE);
}
static CVECTOR *_divo(CVECTOR *a, void *b, bool invert)
{
if (!GB.Is(b, CLASS_Complex))
return NULL;
CCOMPLEX *c = (CCOMPLEX *)b;
if (invert)
return NULL;
if (GSL_REAL(c->number) == 0 && GSL_IMAG(c->number) == 0)
{
GB.Error(GB_ERR_ZERO);
return NULL;
}
CVECTOR *v = VECTOR_make(a);
VECTOR_ensure_complex(v);
gsl_vector_complex_scale(CVEC(v), gsl_complex_inverse(c->number));
return v;
}
static int _equal(CVECTOR *a, CVECTOR *b, bool invert)
{
if (COMPLEX(a) || COMPLEX(b))
{
VECTOR_ensure_complex(a);
VECTOR_ensure_complex(b);
return gsl_vector_complex_equal(CVEC(a), CVEC(b));
}
else
return gsl_vector_equal(VEC(a), VEC(b));
}
static CVECTOR *_neg(CVECTOR *a)
{
return _mulf(a, -1, FALSE);
}
static GB_OPERATOR_DESC _operator =
{
.equal = (void *)_equal,
.add = (void *)_add,
.sub = (void *)_sub,
.mulf = (void *)_mulf,
.mulo = (void *)_mulo,
.divf = (void *)_divf,
.divo = (void *)_divo,
.neg = (void *)_neg
};
//---- Conversions ----------------------------------------------------------
static char *_to_string(CVECTOR *_object, bool local)
{
char *result = NULL;
int i;
int size = SIZE(THIS);
char *str;
int len;
result = GB.AddChar(result, '[');
for (i = 0; i < size; i++)
{
if (i)
result = GB.AddChar(result, local ? ' ' : ',');
if (!COMPLEX(THIS))
{
GB.NumberToString(local, gsl_vector_get(VEC(THIS), i), NULL, &str, &len);
result = GB.AddString(result, str, len);
}
else
{
str = COMPLEX_to_string(gsl_vector_complex_get(CVEC(THIS), i), local);
result = GB.AddString(result, str, GB.StringLength(str));
GB.FreeString(&str);
}
}
result = GB.AddChar(result, ']');
return result;
}
static bool _convert(CVECTOR *_object, GB_TYPE type, GB_VALUE *conv)
{
if (THIS)
{
if (!COMPLEX(THIS))
{
switch (type)
{
case GB_T_FLOAT:
conv->_float.value = gsl_blas_dnrm2(VEC(THIS));
return FALSE;
case GB_T_SINGLE:
conv->_single.value = gsl_blas_dnrm2(VEC(THIS));
return FALSE;
case GB_T_INTEGER:
case GB_T_SHORT:
case GB_T_BYTE:
conv->_integer.value = gsl_blas_dnrm2(VEC(THIS));
return FALSE;
case GB_T_LONG:
conv->_long.value = gsl_blas_dnrm2(VEC(THIS));
return FALSE;
case GB_T_STRING:
case GB_T_CSTRING:
conv->_string.value.addr = _to_string(THIS, type == GB_T_CSTRING);
conv->_string.value.start = 0;
conv->_string.value.len = GB.StringLength(conv->_string.value.addr);
return FALSE;
default:
break;
}
}
else
{
switch (type)
{
case GB_T_FLOAT:
conv->_float.value = gsl_blas_dznrm2(CVEC(THIS));
return FALSE;
case GB_T_SINGLE:
conv->_single.value = gsl_blas_dznrm2(CVEC(THIS));
return FALSE;
case GB_T_INTEGER:
case GB_T_SHORT:
case GB_T_BYTE:
conv->_integer.value = gsl_blas_dznrm2(CVEC(THIS));
return FALSE;
case GB_T_LONG:
conv->_long.value = gsl_blas_dznrm2(CVEC(THIS));
return FALSE;
case GB_T_STRING:
case GB_T_CSTRING:
conv->_string.value.addr = _to_string(THIS, type == GB_T_CSTRING);
conv->_string.value.start = 0;
conv->_string.value.len = GB.StringLength(conv->_string.value.addr);
return FALSE;
default:
break;
}
}
// Vector ---> Float[]
if ((type == GB.FindClass("Float[]") || type == CLASS_Polynomial) && !COMPLEX(THIS))
{
GB_ARRAY a;
int i;
double *data;
GB.Array.New(&a, GB_T_FLOAT, SIZE(THIS));
data = (double *)GB.Array.Get(a, 0);
for(i = 0; i < SIZE(THIS); i++)
data[i] = gsl_vector_get(VEC(THIS), i);
conv->_object.value = a;
if (type != CLASS_Polynomial)
return FALSE;
}
// Vector ---> Complex[]
else if (type == GB.FindClass("Complex[]") || type == CLASS_Polynomial)
{
GB_ARRAY a;
int i;
void **data;
CCOMPLEX *c;
GB.Array.New(&a, CLASS_Complex, SIZE(THIS));
data = (void **)GB.Array.Get(a, 0);
for(i = 0; i < SIZE(THIS); i++)
{
c = COMPLEX_create(COMPLEX(THIS) ? gsl_vector_complex_get(CVEC(THIS), i) : gsl_complex_rect(gsl_vector_get(VEC(THIS), i), 0));
data[i] = c;
GB.Ref(c);
}
conv->_object.value = a;
if (type != CLASS_Polynomial)
return FALSE;
}
else
return TRUE;
// Vector ---> Polynomial
if (type == CLASS_Polynomial)
{
void *unref = conv->_object.value;
GB.Ref(unref); // Will be unref by the next GB.Conv()
POLYNOMIAL_convert(FALSE, type, conv);
GB.Unref(&unref); // Will be unref by the next GB.Conv()
//GB.Conv(conv, type);
//GB.UnrefKeep(&conv->_object.value, FALSE); // Will be ref again after the current GB.Conv()
return FALSE;
}
}
else if (type >= GB_T_OBJECT)
{
if (GB.Is(conv->_object.value, CLASS_Array))
{
GB_ARRAY array = (GB_ARRAY)conv->_object.value;
int size = GB.Array.Count(array);
CVECTOR *v;
int i;
GB_VALUE temp;
void *data;
GB_TYPE atype = GB.Array.Type(array);
// Float[] Integer[] ... ---> Vector
if (atype > GB_T_BOOLEAN && atype <= GB_T_FLOAT)
{
v = VECTOR_create(size, FALSE, FALSE);
for (i = 0; i < size; i++)
{
data = GB.Array.Get(array, i);
GB.ReadValue(&temp, data, atype);
GB.Conv(&temp, GB_T_FLOAT);
gsl_vector_set(VEC(v), i, temp._float.value);
}
conv->_object.value = v;
return FALSE;
}
// Variant[] ---> Vector
else if (atype == GB_T_VARIANT)
{
CCOMPLEX *c;
v = VECTOR_create(size, TRUE, FALSE);
for (i = 0; i < size; i++)
{
GB.ReadValue(&temp, GB.Array.Get(array, i), atype);
GB.BorrowValue(&temp);
GB.Conv(&temp, CLASS_Complex);
c = temp._object.value;
if (c)
gsl_vector_complex_set(CVEC(v), i, c->number);
else
gsl_vector_complex_set(CVEC(v), i, COMPLEX_zero);
GB.ReleaseValue(&temp);
}
conv->_object.value = v;
return FALSE;
}
// Complex[] ---> Vector
else if (atype == CLASS_Complex)
{
CCOMPLEX *c;
v = VECTOR_create(size, TRUE, FALSE);
for (i = 0; i < size; i++)
{
c = *((CCOMPLEX **)GB.Array.Get(array, i));
if (c)
gsl_vector_complex_set(CVEC(v), i, c->number);
else
gsl_vector_complex_set(CVEC(v), i, COMPLEX_zero);
}
conv->_object.value = v;
return FALSE;
}
}
// Float Integer... ---> Vector
else if (type > GB_T_BOOLEAN && type <= GB_T_FLOAT)
{
CVECTOR *v = VECTOR_create(1, FALSE, FALSE);
if (type == GB_T_FLOAT)
gsl_vector_set(VEC(v), 0, conv->_float.value);
else if (type == GB_T_SINGLE)
gsl_vector_set(VEC(v), 0, conv->_single.value);
else
gsl_vector_set(VEC(v), 0, conv->_integer.value);
conv->_object.value = v;
return FALSE;
}
// Complex ---> Vector
else if (type == CLASS_Complex)
{
CCOMPLEX *c = (CCOMPLEX *)conv->_object.value;
CVECTOR *v = VECTOR_create(1, TRUE, FALSE);
gsl_vector_complex_set(CVEC(v), 0, c->number);
conv->_object.value = v;
return FALSE;
}
}
return TRUE;
}
//---------------------------------------------------------------------------
BEGIN_METHOD(Vector_new, GB_INTEGER size; GB_BOOLEAN complex)
bool complex = VARGOPT(complex, FALSE);
int size = VARGOPT(size, 1);
if (size < 1) size = 1;
THIS->complex = complex;
if (!complex)
THIS->vector = gsl_vector_calloc(size);
else
THIS->vector = gsl_vector_complex_calloc(size);
END_METHOD
BEGIN_METHOD_VOID(Vector_free)
if (!COMPLEX(THIS))
gsl_vector_free(VEC(THIS));
else
gsl_vector_complex_free(CVEC(THIS));
END_METHOD
BEGIN_PROPERTY(Vector_Count)
GB.ReturnInteger(SIZE(THIS));
END_PROPERTY
BEGIN_METHOD_VOID(Vector_Copy)
GB.ReturnObject(VECTOR_copy(THIS));
END_METHOD
BEGIN_METHOD(Vector_get, GB_INTEGER index)
int size = SIZE(THIS);
int index = VARG(index);
if (index < 0 || index >= size)
{
GB.Error(GB_ERR_BOUND);
return;
}
if (!COMPLEX(THIS))
GB.ReturnFloat(gsl_vector_get(VEC(THIS), index));
else
GB.ReturnObject(COMPLEX_create(gsl_vector_complex_get(CVEC(THIS), index)));
GB.ReturnConvVariant();
END_METHOD
BEGIN_METHOD(Vector_put, GB_VARIANT value; GB_INTEGER index)
int index = VARG(index);
int size = SIZE(THIS);
GB_VALUE *value = (GB_VALUE *)ARG(value);
int type;
COMPLEX_VALUE cv;
if (index < 0 || index > size)
{
GB.Error(GB_ERR_BOUND);
return;
}
type = COMPLEX_get_value(value, &cv);
if (type == CGV_ERR)
return;
if (type == CGV_COMPLEX)
{
VECTOR_ensure_complex(THIS);
gsl_vector_complex_set(CVEC(THIS), index, cv.z);
}
else
{
if (COMPLEX(THIS))
gsl_vector_complex_set(CVEC(THIS), index, cv.z);
else
gsl_vector_set(VEC(THIS), index, cv.x);
}
END_METHOD
static void do_dot(CVECTOR *_object, CVECTOR *v, bool conj)
{
bool ca, cb;
if (GB.CheckObject(v))
return;
ca = !COMPLEX(THIS);
cb = !COMPLEX(v);
if (ca && cb)
{
double result;
gsl_blas_ddot(VEC(THIS), v->vector, &result);
GB.ReturnFloat(result);
}
else
{
CVECTOR *a, *b;
gsl_complex result;
if (ca)
a = VECTOR_convert_to_complex(THIS);
else
a = THIS;
if (cb)
b = VECTOR_convert_to_complex(v);
else
b = v;
if (conj)
gsl_blas_zdotc(CVEC(a), CVEC(b), &result);
else
gsl_blas_zdotu(CVEC(a), CVEC(b), &result);
GB.ReturnObject(COMPLEX_create(result));
if (ca) GB.Unref(POINTER(&a));
if (cb) GB.Unref(POINTER(&b));
}
GB.ReturnConvVariant();
}
BEGIN_METHOD(Vector_Dot, GB_OBJECT vector)
do_dot(THIS, VARG(vector), FALSE);
END_METHOD
BEGIN_METHOD(Vector_ConjDot, GB_OBJECT vector)
do_dot(THIS, VARG(vector), TRUE);
END_METHOD
BEGIN_METHOD_VOID(Vector_Norm)
if (!COMPLEX(THIS))
GB.ReturnFloat(gsl_blas_dnrm2(VEC(THIS)));
else
GB.ReturnFloat(gsl_blas_dznrm2(CVEC(THIS)));
END_METHOD
BEGIN_PROPERTY(Vector_Handle)
GB.ReturnPointer(THIS->vector);
END_PROPERTY
BEGIN_METHOD(Vector_ToString, GB_BOOLEAN local)
GB.ReturnString(GB.FreeStringLater(_to_string(THIS, VARGOPT(local, FALSE))));
END_METHOD
//---------------------------------------------------------------------
GB_DESC VectorDesc[] =
{
GB_DECLARE("Vector", sizeof(CVECTOR)),
GB_METHOD("_new", NULL, Vector_new, "[(Size)i(Complex)b]"),
GB_METHOD("_free", NULL, Vector_free, NULL),
//GB_STATIC_METHOD("_call", "Vector", Vector_call, "(Value)f."),
GB_METHOD("Copy", "Vector", Vector_Copy, NULL),
GB_METHOD("ToString", "s", Vector_ToString, "[(Local)b]"),
GB_PROPERTY_READ("Count", "i", Vector_Count),
GB_PROPERTY_READ("Handle", "p", Vector_Handle),
GB_METHOD("_get", "v", Vector_get, "(Index)i"),
GB_METHOD("_put", NULL, Vector_put, "(Value)v(Index)i"),
//GB_METHOD("Scale", "Vector", Vector_Scale, "(Value)v"),
GB_METHOD("Dot", "v", Vector_Dot, "(Vector)Vector"),
GB_METHOD("ConjDot", "v", Vector_ConjDot, "(Vector)Vector"),
GB_METHOD("Norm", "f", Vector_Norm, NULL),
//GB_METHOD("Equal", "b", Vector_Equal, "(Vector)Vector;"),
GB_INTERFACE("_convert", &_convert),
GB_INTERFACE("_operator", &_operator),
GB_END_DECLARE
};