Giac es una librería en C++ con tipos para manipulaciones algebraicas. Xcas es una GUI (Interface Gráfica) unida a Giac que permite las funcionalidades de un Sistema de Algebra Computerizada (CAS).
Si quieres usar xcas/giac
como cualquier otro CAS y tu Sistema Operativo es
Intel x86 GNU/Linux o Intel StrongARM GNU/Linux o Windows 9x, entonces
no te tienes que preocupar de la compilación. En vez de ello, puedes instalar
binarios precompilados:
Descomprime el archivo con
tar xvfz xcas_user.tgz
después
cd xcas
y
./xcas
/
Ejecuta xcas
desde el directorio donde descomprimiste xcas
.
Necesitas un compilador de C++ que entienda la norma C++ ANSI 3. Por
ejemplo gcc
versión 2.95 o superior, funcionará. Además, debes
comprobar que tienes instalada la librería GMP GNU Math Precision.
Si no está instalada, debes compilar e instalar la fuente:
está disponible en cualquier mirror ftp de GNU, mira en
http://www.gnu.org para mas detalles. Si estás usando GNU/Linux,
la librería GMP es muy probable que esté instalada, pero las cabeceras
puede que no, busca un paquete llamado algo así como gmp-devel
.
make clean ./configure NTL_GMP_LIP=on NTL_STD_CXX=on make make install
src/basemath/polarit2.c
: quita la palabra
static
de la declaración:
static GEN combine_factors(...)
src/headers/paridecl.h
: Añade la línea
GEN combine_factors(GEN a, GEN famod, GEN p, long klim, long hint);
en la sección * polarit2.c
make all
) y reinstala PARI (make install
)
y comprueba que la librería libpari.a
ha sido actualizada o copiala explicitamente
desde el directorio O<your_os>
/usr/local/include/pari/pariinl.h
labs
por std::abs
si no podrías tener errores con el compilador.
long pari_mem_size=10000000;
xcas
no funciona con FLTK 1.1.
Para el editor de matrices / hoja de cálculo, necesitarás además FLVW
http://flvw.sourceforge.net/
El script del shell ./configure
reconoce las siguientes opciones:
Estas opciones pueden ser desactivadas usando --disable-option-name
en lugar de
--enable-option-name
. Por defecto configure
usará estas opciones
si las librerías están disponibles en tu sistema.
Para binarios de gran velocidad, antes de ejecutar configure
haz (con bash
como shell)
$ export CXXFLAGS="-O3 -fexpensive-optimizations -malign-loops=2 -malign-jumps=2 -malign-functions=2"
o (con tcsh como shell)
$ setenv CXXFLAGS "-O3 -fexpensive-optimizations -malign-loops=2 -malign-jumps=2 -malign-functions=2"
Como con cualquier software GNU autoconfigurable, puedes teclear:
./configure
[añade opciones necesarias: prueba ./configure -help
para obtener mas información]
make
make check
[pasa a ser root si es necesario]
make install
Trucos:
/usr/local/
,
FLTK y GSL instalados y no quieres capacidad de depuración, puedes teclear
./inst
./setup
[hazte root]
make install
CXXFLAGS
a -g
antes de ejecutar configure, con tcsh
setenv CXXFLAGS -g
, con bash export CXXFLAGS=-g
.
config.h
define HAVE_LIBFLTK y no define
HAVE_LIBGSL y HAVE_LIBGSLCBLAS a menos que tengas estas librerías también, entonces
make -f Makefile.ipaq
Nótese que nunca he conseguido construirlo con optimización para el iPaq.
./configure --disable-gui
make
Puedes compilar la versión librería de giac bajo Unix.
O asumiendo que tengas las herramientas cygwin, gmp y FLTK instaladas (mira en
http://sources.redhat.com/cygwin para cygwin, ejecuta cygwin,
vete al directorio src
y ejecuta
make -f Makefile.win
Después de esto, puedes ejecutar xcas.exe
de forma independiente,
/usr/bin/cygwin1.dll
proporcionada ha sido copiada en el path (p.e. en el mismo
directorio que xcas.exe
)
make check
,
por favor nota que la respuesta asume que PARI y NTL no están permitidos (enabled).
Si no obtendrás algunos errores porque la factorización no
devolverá los factores en el mismo orden.
src/Makefile
y si es necesario cambia la línea :
CXXFLAGS = -g -O2
por :
CXXFLAGS = -g
autoheader: Symbol 'CONSTANT_DEBUG_SUPPORT' is not covered by ...
ejecuta
autoheader --localdir=.
modpoly.cc
, es casi seguro
porque compilaste sin NTL namespaces. Recompílalo (vease sección)
modfactor.o
será porque no modificaste PARI correctamente u
olvidaste reinstalar las librerías de PARI (vease sección)
cp libpari.a /usr/local/lib mkdir /usr/local/include/pari cp src/headers/*.h /usr/local/include/pari cp Ocygwin/*.h /usr/local/include/pariEntonces obtuve un error compilando
pari.cc
que desapareción comentando
la línea causante en la cabecera /usr/local/include/pari/paricom.h
Después de esto todo fué correctamente.
xcas
es una interface de usuario con giac que es similar a una calculadora.
Una interface de línea de comandos llamada cas
también está disponible.
Puedes usar, pero no lo necesitas, un teclado puesto que esta interface está diseñada para ser usada también en PDA. Usa el botón verde cambio para obtener los botones del teclado.
La ventana está compuesta de izquierda a derecha y de arriba a abajo por:
La interface se asemeja a las avanzadas calculadoras gráficas (TI89, TI92,
HP49G en modo algebraico): escribes un comando en la línea de comandos
con la ayuda del teclado y/o los botones, ayuda en línea y menús.
Entonces pulsando Enter se evaluará tu expresión y devolverá el
resultado al área del historial. Si un comando devuelve un objeto gráfico
la ventana historial será reemplazada por la ventana gráfica. Puedes
cambiar de ventana historial a gráfica usando el botón Geo
en la barra de menús por teclas.
La ayuda en línea da una breve descripción de todos los comandos del CAS
con ejemplos que pueden ser pegados en la línea de comandos. Está disponible
por defecto en xcas
o con el comando aide
desde shell.
Imprimir requiere una instalación operativa de LaTeX
con pstricks
.
Una lista de comandos del CAS.
Los comandos gcd
y lcm
se aplican a ambos tipos de argumentos:
devuelven el máximo común divisor o el mínimo común múltiplo.
Otros comandos aritméticos deben comenzar con la letra i
si quieres usarlos
con enteros, si no los argumentos serán considerados como polinómios constantes.
Dados dos enteros a
y b
, la división euclídea entera
está definida por la igualdad :
a=b*q+rdonde normalmente
r
se coge entre 0 y b-1
, o
en la representación simétrica , entre -b/2
y b/2
.
Las funciones iquo(a,b)
y irem(a,b)
devuelven respectivamente
q
y r
, o iquorem(a,b)
devueltas ambas como un vector.
La función smod(a,b)
devolverá r
usando el convenio de resto
simétrico.
la función gcd(a,b)
devuelve el máximo común divisor (Mcd)
d
de dos enteros a
y b
. Si necesitas dos enteros
u
y v
tales que:
a*u+b*v=dpuedes usar en su lugar
egcd(a,b)
, devolverá [u,v,d]
.
El comando ichinrem([a,n],[b,m])
donde n
y m
son primos devolverá un vector [c,n*m]
tal que
c=a (mod n)
y c=b (mod m)
.
La función is_prime(a)
devolverá 0 si a
no es primo.
Devolverá 2 si a
es seguro primo, y 1 si a
es pseudo-primo. Si has compilado xcas
con soporte PARI,
obtendrás un certificado de primo en su lugar (véase documentación de PARI
para más información).
Los comandos nextprime(a)
y prevprime(a)
devolverán
el siguiente o anterior (pseudo-)primo, de un entero a
dado.
La función ifactor(a)
devuelve la factorización de a
.
Es una buena idea compilar con soporte PARI si tienes planeado factorizar
enteros relativamente grandes (con factores primos de mas de 20 dígitos).
Funciones de enteras adicionales provistas por xcas
son
jacobi(a,b)
y legendre(a,b)
, véase la documentación de GMP para más detalles.
pa2b2(p)
devuelve [a,b]
tal que p=a*a+b*b
si p=1 (mod 4)
es primo.
Los polinómios tienen dos representaciones: representación simbólica o
por un vector de coeficientes. En la representación simbólica puedes
añadir el nombre de la variable como parámetro adicional a las funciones
que uses, si no la variable por defecto será la usada. Para la representación
por vector, es recomendable usar el delimitador correcto poly1[
en lugar de [
con lo que las operaciones habituales (suma,..)
se comportarán correctamente (no como si fuesen vectores o matrices).
quo(a,b)
rem(a,b)
y quorem(a,b)
devuelven respectivamente los polinómios q
, r
y [q,r]
tales que a=b*q+r
y degree(r)<degree(b)
gcd(a,b)
devuelve el máximo común divisor de dos polinómios
egcd(a,b)
es el algorítmo Mcd eclídeo extendido, al igual que para
enteros devuelve una lista de 3 polinómomios u,v,d
tales que au+bv=d
.
chinrem
devuelve el resto chino para polinómios escritos como listas.
Los 2 argumentos son dos listas hechas de polinómios módulo otro polinomio
(donde los polinómios módulo son primos entre ellos).
La respuesta es el polinómio módulo producto de los polinómios módulo
que reduce a los originales polinómios módulo los originales polinómios módulo
cyclotomic
toma un entero n como argumento y devuelve el polinómio
ciclotómico n-ésimo.
El comando normal
reescribe una fracción racional como una relación
entre dos polinómios coprimos. Si una expresión no es racional, primero es
racionalizada sustituyendo las expresiones transcendentales (p.e.
sin(x)
) por un identificador temporal. Expresiones algebraicas
(p.e. sqrt(x)
) también son normalizadas.
El comando factor
factoriza polinómios. Como antes, expresiones
no polinómicas son racionalizadas primero. Puedes elegir la variable
básica respecto a la cual el polinómio será factorizado añadiendola como
segundo argumento a factor
.
La función texpand
es usada para expandir expresiones
transcendentales como exp(x+y)=exp(x)*exp(y)
o reglas similares
para funciones trigonométricas. La función tlin
realiza
la operación inversa para funciones trigonométricas , tal y como la función
lin
lo hace para las exponenciales.
La función halftan
reescribe expresiones trigonométricas
en términos de la tangente del ángulo mitad. La función hyp2exp
reescribe funciones hiperbólicas en términos exponenciales.
La instrucción para diferenciación es diff(expression,variable)
.
La antiderivada indefinida se obtiene usando
integrate(expression,variable)
. Si necesitas integración definida
entre los límites a
y b
, escoge
integrate(expression,variable,a,b)
para integración exacta
o romberg(expression,variable,a,b)
para integración numérica.
Un ejemplo de integración definida son los coeficientes de Fourier de funciones
periódicas. Son obtenidos usando fourier_an
y fourier_bn
para coeficientes trigonométricos o usando fourier_cn
para
coeficientes exponenciales complejos.
Algunas antiderivadas discretas pueden ser obtenidas usando
sum(variable,expression)
.
Para un límite la sintásis es
limit(expression,variable,limitpoint[,direction])
.
Para un desarrollo en serie
series(expression,variable,limitpoint,order[,direction])
.
La implementación en giac
de limit
y series
está
basada en el algorítmo mrv.
Usando solve(expression,variable)
se busca la solución exacta
de ecuaciones polinómicas. Usa newton
para soulciones
numéricas (de un mayor rango de ecuaciones).
Las operacions aritméticas sobre matrices y vectorse se hacen usando los operadores
habituales. El producto escalar de 2 vectores se obtiene usando el operador *
.
La eliminación Gaussiana sobre una matriz (Gauss-Bareiss) se desarrolla
usando rref(m)
. El núcleo de una aplicación lineal de matriz m
se obtiene con ker(m)
. Un sistema de ecuaciones lineales (escrito
simbólicamente como un vector) puede ser resuelto con
linsolve([equations],[variables])
.
El determinante de una matriz puede ser obtenido usando dos algorítmos,
o bien Gauss-Bareiss usando det(m)
, o calculando los menores
det_minor(m)
. Realmente, un último método está disponible usando
el cálculo de los coeficientes constantes del polinómio característico usando
el algorítmo Fadeev-Leverrier.
El polinómio característico de una matriz puede ser calculado por el algorítmo de
Fadeev-Leverrier usando pcar(m)
. Para matrices con los coeficientes en
un campo finito, pcar_hessenberg(m)
es una mejor opción (complejidad
O(n^3)
donde n
es el tamaño de la matriz).
Los valores propios y los vectores propios son calculados usando respectivamente
egvl(m)
y egv(m)
. La forma normal de Jordan se obtiene usando
jordan(m)
.
La formas cuadráticas (escritas simbólicamente) pueden ser reducidas a sumas
y diferencias de cuadrados usando gauss(expression,[variables])
.
Hay algún soporte para isometrías: mkisom
puede ser usado para
hacer una isometría desde sus propios elementos y isom(m)
devuelve
los elementos propios de una isometría.
Como cualquier otro objeto, puedes crear objetos geométricos usando la
línea de comandos. Adicionalmente, si la ventana gráfica está activa (clicka
en el botón Geo
si es necesario), puedes crear puntos y
segmentos con el ratón (o el lápiz apuntador) o mover un objeto geométrico.
Para crear un punto,simplemente clicka. Para crear una línea, pulsa cualquier botón
del ratón, mueve el ratón y suelta el botón en el segundo punto.
Para mover un objeto, primero selecciónalo clickando cerca de él. La línea de comandos
deberá mostrar el nombre del objeto. Puedes moverlo pulsando el ratón
cerca del objeto y moviéndolo. Suelta el botón del ratón en la posición
final. Puedes cancelar un movimiento soltando el ratón fuera de la ventana
gráfica. Como en cualquier paquete de geometría dinámica. todos los objetos dependientes
de un objeto, se moverán cuando muevas dicho objeto.
Para imprimir el gráfico actual, puedes usar la instrucción graph2tex()
o bien, sin argumentos (entonces el código LaTeX
será insertado en su lugar
en el historial) o con una cadena de texto conteniendo el nombre
del fichero donde se guardará una versión aislada del gráfico, por ejemplo
graph2tex("figure.tex")
creará un fichero llamado figure.tex
que podrás compilar con latex figure.tex
.
Xcas y el programa cas proveen un lenguaje interpretado similar a
otros populares lenguajes de programación de CAS. Este lenguaje scrip está
disponible en 3 formas: sintáxis similar a C (por defecto) o en modo compatibilidad
para programas simples de Maple o Mupad. Describiremos sólo la sintáxis similar a C.
Las instrucciones deben acabar con punto y coma ;
. Los grupos de
instrucciones pueden ser combinados usando llaves, como en C.
El comando maple_mode(0)
o maple_mode(1)
o
maple_mode(2)
puede ser usado para cambiar la forma del lenguaje
respectivamente entre modo similar-C a similar-Maple o similar-Mupad. Nótese que este
comando tiene efecto sólo cuando la sesión actual del interprete finaliza
lo que significa cuando el siguiente comando sea procesado en modo interactivo o
al finalizar el fichero de proceso por lotes actual, por lo tanto no deberías comenzar un script
con este comando. En modo de proceso por lotes puedes cambiar el modo activando la
variable de entorno MAPLE_MODE
, por ejemplo con
tcsh: setenv MAPLE_MODE 1
o con bash export MAPLE_MODE=1
cambiará a lenguaje similar a Maple. O puedes ejecutar maplec
o
mupadc
en vez de cas
. Adicionalmente puedes introducir
el comando maple_mode(1)
en el .xcasrc
de tu directorio raíz
para cambiar el comportamiento por defecto. O dentro de xcas
puedes ejecutar
el comando Import
del menú File
y seleccionar la forma.
El comando Export
puede ser usado para traducir el nivel actual
del historial dentro de xcas
a un fichero, o el comando View as
del menú Edit
para traducirlo a la ventana de salida de la ayuda.
El lenguaje acepta variables locales y globales, variables no son tecleadas.
Las variables globales no necesitan ser declaradas, las locales deben ser declaradas
al principio de una función por la palabra clave local
seguido de
los nombres de las variables locales separados por comas ,
con punto y coma
final ;
El signo de asiganción es :=
como en CAS populares y distinto a C.
Otras operaciones (p.e. {+ - * /}) y llamadas a funciones son hechos como en C
o como en una sesión interactiva.
Como en C, para comprobar igualdad se usa ==
. El signo de igual simple =
se usa para devolver una ecuación (esta ecuación será comprobada como un test
sólo en algunas situaciones donde una ecuación no es esperada).
Las otras cláusulas de test son !=
para distinto, < <= > >=
para
comparaciones de valores relaes. Puedes combinar tests con &&
o and
,
y ||
o or
. La negación booleana es !
o not
.
La palabra clave para bucles es como en C
for (inicializacion;mientras_condition;incremento){ bloque_bucle }
Puedes romper un bucle dentro de la iteración con break;
.
Puedes saltar immediatamente a la siguiente iteración con continue;
.
Las palabras clave para condicionales son como en C
if (condicion) { bloque_si_cierto } [ else { bloque_si_falso } ]
Adicionalmente, la selección múltiple es traducida como en C
swith (variable){ case (valor_1): ... break; default: ... ; }
Las funciones son declaradas e implementadas juntas de esta manera
nombre_funcion(parametros):={ definicion }
Los parámetros son como variables locales con una inicialización adicional de los valores de los parámetros dentro de la función.
El return(valor_retorno)
debe ser usado pra devolver el valor
de la función.
No es posible pasar argumentos por referencia, sólo por valor.
Una vez que una función es definida, un fichero llamado nombre_funcion.cas
es generado en el directorio actual. Una buena idea es agrupar
definiciones de funciones correspondientes con el mismo tema en un fichero
llamado con una extensión .cc
(de esta manera la identación similar a C
ocurre automáticamente cuando editas el fichero con tu editor favorito) y
"compila" este fichero con
cas ccnombrefichero.cc
o dentro de xcas
con el comando Run file
del menú Files
.
Una vez que una función está definida, si modificas el correspondiente fichero .cas
,
no afectará a la definición de la función correspondiente durante la
sesión actual.
En este capítulo primero describiremos el tipo de dato genérico de giac,
la clase gen
. Después describiremos los tipos de datos más importantes
que gen
cubre (polinómios, vectores, objetos simbólicos
y funciones unarias de gen). En este punto, el lector debería ser
capaz de programar usando giac
, por lo tanto describimos como integrar
código a giac
por inclusión en la librería o como una librería
ejecutable separada (llamada módulo). el último punto describe
como puedes añadir nuevos objetos matemáticos, p.e. quaternas,
dentro del tipo gen
.
Giac usa el lenguaje C++ porque es más fácil escribir operaciones
algebraicas usando operadores habituales, por ejemplo a+b*x
es más fácil
de entender y modificar que add(a,mul(b,x))
, pero no es necesario
que aprendas programación orientada a objetos. De hecho, es más una
librería de C usando características de C++ que facilitan la programación easier (como las
secuencias I/O y la librería de plantillas estandard). De todos modos necesitarás
un compilador de C++ reciente, p.e. gcc
versión 2.95 o posterior.
gen
es la clase usada para representar objetos matemáticos
(#include <giac/gen.h>
). Es una unión en C, hecha bien de obejtos "directos"
como int
o double
o de punteros al montón de objetos afectados que están referenciados.
La reserva de memoria la realiza la propia librería (salvo
tipos de objetos definidos por el usuario). Puedes comprobar
el tipo actual de una variable de tipo gen
, p.e. gen e;
,
usando su campo type
(p.e. if (e.type==...)
). Este
campo type
de un gen
es un int
.
El gen
podría ser~:
e.type==_INT_
)
e.type==_REAL
)
e.type==_ZINT
)
e.type==_CINT
), un puntero a
dos objetos de tipo gen
la parte real y la parte imaginaria
e.type==_IDNT
), con un puntero a un
tipo identificateur
e.type==_SYMB
), con un puntero a
tipo symbolic
e.type==_VECT
),
con un puntero a un tipo vecteur
e.type==_FUNC
),
con un puntero a un tipo unary_function_ptr
Otros tipos están disponibles (p.e. un puntero a un objeto gen_user
que puedes derivar para hacer tus propias clases, o números de coma flotante
con precision arbitraria que serán implementados más tarde), para una descripción
completa mira en giac/gen.h
(si tienes instalado giac
la ruta a los ficheros incluidos es /usr/local/include/giac
a menos que
invalide la que está por defecto, si no lo instalas, la ruta es la ruta al
directorio src
de la distribución del código fuente).
Si quieres acceder al tipo subyacente, despues de comprobar que el tipo es correcto, puedes hacer lo siguiente:
int i=e.val;
double d=e._DOUBLE_val;
mpz_t * m=e._ZINTptr;
gen realpart=*e._CINTptr;
identificateur i=*e._IDNTptr;
symbolic s=*e._SYMBptr;
vecteur v=*e._VECTptr;
unary_function_ptr u=*e._FUNCptr
Además del type
principal, cada gen
tiene subtype
(subtipo).
Este subtipo se usa algunas veces para seleccionar diferentes comportamientos, p.e.
añadiendo una constante a un vector podría añadir la constante a todos los términos
para algunos obejtos geométricos representados usando vectores, sólo a los términos
de la diagonal de la matriz cuadrada, o al último término de polinómios densos.
Mira en giac/dispatch.h
la descripción de los subtipos.
Polinómios están disponibles como:
polynome
, los
ficheros de cabecera son gausspol.h
y poly.h
poly1
o alias modpoly
usado para polinómios univariables modulares. El tipo usado es el mismo
que para vectores y matrices.
Los ficheros de cabecera son giac/polygauss.h
y giac/modpoly.h
.
Un gen
puede ser un polinómio si su campo type
es
respectivamente _POLY
(escaso) o _VECT
(denso).
Las funciones de conversión a y de la representación simbólica
respecto a nombres globales son declaradas en giac/sym2poly.cc
.
El tipo usado para vectores y matrices es el mismo, es un
std::vector<gen>
(a menos que lo tengas configurado con
--enable-debug
). El fichero cabecera es giac/vecteur.h
.
Un gen
puede ser un vector si su campo type
es
_VECT
.
Los objetos simbólicos son árboles. El sommet
es una unary_function_ptr
(una clase apuntando a una función). El feuille
es también
un gen
atómico (para un función con un argumento) o un compuesto
(feuille.type==_VECT
) para una función con más de un argumento
(estas funciones aparecen por lo tanto como una función con un argumento el cual
es la lista de todos sus argumentos).
En la librería giac, cada función es vista como un función que coge un argumento y devuelve un argumento. Si una función debiese tener más de un argumento, metemos estos argumentos en un vector.
Los ficheros usual.cc/.h
dan ejemplos de declaraciones p.ej. para
funciones exponenciales y trigonométricas. Las funciones unarias tienen
los siguientes miembros~:
gen
y devuelve un gen
que hace todo el trabajo
taylor_asin
).
Éste es siempre el caso si tu función está definida en infinito.
Notese que esta función
es ejecutada al inicio así que puedes incluir código en ella por
ejemplo para añadir tu función al paso de preproceso simbólico del
algorítmo limit/series
.
input_lexer.ll
(mira por ejemplo "sin"
) o debes registrarla (mira más abajo).
unaria_funcion_unaria
está definida, debes construtir
un unaria_funcion_ptr
para poder usar lo simbólicos internos.
Podrías dar un argumento opcional para especificar un comportamiento para la evaluación
de argumentos (citando). En este caso, podrías dar un segundo argumento opcional
para registrar tu función dinámicamente en la lista de nombre de funciones
reconozidas por el intérprete. Asegúrate de unir el fichero objeto de forma
que la inicialización occurre despues de inicializarse input_lexer.ll
,
esto significa que debes poner tu fichero objeto antes de input_lexer.o
cuando unas (mira por ejemplo la posición de moyal.o
en
el fichero Makefile.am
, moyal
es un ejemplo de registro dinámico).
Tienes, por supuesto, la opción de declarar el nombre de la función
estáticamente en el fichero input_lexer.ll
.
Siempre debes declarar una función estáticamente si no sigue la sintáxis estándar para una función.
Aquí está un ejemplo de una función unible dinámicamente llamada
example
que requiere 2 argumentos y devuelve la suma dividida
por el producto si los argumentos son enteros o se devuelve a si misma en otro caso.
La cabecera en C++ de example.h
sería algo así
#ifndef __EXAMPLE_H #define __EXAMPLE_H #include <giac/gen.h> #include <giac/unary.h> #ifndef NO_NAMESPACE_GIAC namespace giac { #endif // ndef NO_NAMESPACE_GIAC gen example(const gen & a,const gen & b); gen _example(const gen & args); extern unary_function_ptr at_example ; #ifndef NO_NAMESPACE_GIAC } // namespace giac #endif // ndef NO_NAMESPACE_GIAC #endif // __EXAMPLE_H
El código en C++ sería algo como:
using namespace std; #include <giac/giac.h> #include "example.h" #ifndef NO_NAMESPACE_GIAC namespace giac { #endif // ndef NO_NAMESPACE_GIAC gen example(const gen & a,const gen & b){ if (is_integer(a) && is_integer(b)) return (a+b)/(a*b); return symbolic(at_example,makevecteur(a,b)); } gen _example(const gen & args){ if ( (args.type!=_VECT) || (args._VECTptr->size()!=2) ) setsizeerr(); // type checking : args must be a vector of size 2 vecteur & v=*args._VECTptr; return example(v[0],v[1]); } const string _example_s("example"); unary_function_unary __example(&_example,_example_s); unary_function_ptr at_example (&__example,0,true); #ifndef NO_NAMESPACE_GIAC } #endif // ndef NO_NAMESPACE_GIAC
Compílalo con
c++ -g -c example.cc
Para probar tu código, podrías escribir el siguiente test.cc
programa
#include "example.h" using namespace std; using namespace giac; int main(){ gen args; cout << "Enter argument of example function"; cin >> args; cout << "Result: " << _example(args) << endl; }Compílalo con el comando
c++ -g example.o test.cc -lgiac -lgmpPodrías necesitar unirlo a otras librerías p.ej.
-lreadline -lhistory -lcurses
dependiendo de tu instalación.
Entonces ejecuta a.out
. En este punto probarías con p.ej. [1,2]
.
Puedes depurar tu programa como siempre, p.ej. con
gdb a.out
, es recomendable crear un fichero .gdbinit
en el directorio actual de forma que puedas usar el comando v
para imprimir datos de giac, el fichero .gdbinit
podría contener :
echo Defining v as print command for giac types\n define v print ($arg0).dbgprint() end
Cuando tu función esté comprobada, puedes añadirla a la librería. Edita
el fichero Makefile.am
del subdirectorio src
de giac
: simplemente añade example.cc
antes de input_lexer.cc
en la línea libgiac_la_SOURCES
y añade example.h
en la línea
giacinclude_HEADERS
.
Para reconstruir la librería vete al directorio giac
y escribe
automake; make
Si quieres compartir tu función(es) con otras personas, debes
ponerle licencia GPL (porque estará unida a código GPL).
Añade la cabecera GPL a los ficheros, y envíalos al e-mail de contribuciones de giac
,
actualmente mailto:bernard.parisse@univ-grenoble-alpes.fr
/* * Copyright (C) 2002 Your name * * 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 */
Otra forma de compartir tu código podría ser construir una librería dinámica
que puede ser cargada en tiempo de ejecución usando las facilidades de <dlfcns.h>
.
ATENCION: los módulos no funcionan con binarios estáticos. Asegúrate
de tener binarios dinámicos (situación por defecto cuando compilas giac,
pero el paquete xcas
distribuido como binario está construido estático para
evitar librerías incompatibles).
Definamos una función llamada mydll
en el fichero mydll.cc
como
este :
#include <giac/giac.h> #ifndef NO_NAMESPACE_GIAC namespace giac { #endif // ndef NO_NAMESPACE_GIAC const string _mydll_s("mydll"); gen _mydll(const gen & args){ return sin(ln(args)); } unary_function_unary __mydll(&giac::_mydll,_mydll_s); unary_function_ptr at_mydll (&__mydll,0,true); // auto-register #ifndef NO_NAMESPACE_GIAC } // namespace giac #endif // ndef NO_NAMESPACE_GIAC
Compílalo como esto
c++ -fPIC -DPIC -g -c mydll.cc -o mydll.lo cc -shared mydll.lo -lc -Wl,-soname -Wl,libmydll.so.0 -o libmydll.so.0.0.0 rm -f libmydll.so.0 && ln -s libmydll.so.0.0.0 libmydll.so.0 rm -f libmydll.so && ln -s libmydll.so.0.0.0 libmydll.so
La librería es cargable en tiempo de ejecución de una seseión usando el comando
insmod("libmydll.so")
asumiendo que está guardada en un directorio disponible
desde LD_LIBRARY_PATH
o en /etc/ld.so.conf
si no
debes poner la ruta al fichero librería (comenzando con ./
si
está en el directorio actual).
Una forma de comprobar tu código es añadir la línea siguiente en tu
fichero ~/.xcasrc
:
insmod("ruta_a_libmydll/libmydll.so");donde cambias
ruta_a_libmydll.so
por la ruta real a
libmydll.so
por ejemplo /home/joe
si tu nombre de conexión (login) es
joe
y mydll
está en tu directorio home.
Entonces si estás usando como editor emacs
, pon como primera línea del
fichero mydll.cc
// -*- mode:C++ ; compile-command: "g++ -I.. -fPIC -DPIC -g -c mydll.cc -o mydll.lo && ln -sf mydll.lo mydll.o && gcc -shared mydll.lo -lc -Wl,-soname -Wl,libmydll.so.0 -o libmydll.so.0.0.0 && ln -sf libmydll.so.0.0.0 libmydll.so.0 && ln -sf libmydll.so.0.0.0 libmydll.so" -*-Ahora puedes compilarlo con
Compile
del menú Tools
y el código resultante es cargado automaticamente cuando comienzas una nueva
sesión con xcas
o cas
que hace que comprobar sea más ligero.
La clase gen_user
puede ser derivada de forma que puedes incluir
tus propios datos en gen
. Mira la declaración de gen_user
en el fichero gen.h
y en el ejemplo de las quaternas
en los ficheros quater.h
y quater.cc
.
Teclea el texto siguiente con tu editor favorito
#include <giac/giac.h> using namespace std; using namespace giac; int main(){ gen e(string("x^2-1")); cout << factor(e) << endl; }
guárdalo como p.ej. tryit.cc
y compílalo con
c++ -g tryit.cc -lgiac -lgmp
Si obitenes símbolos sin resolver, entonces puede que readline
esté activada
y debas compilarlo como
c++ -g tryit.cc -lgiac -lgmp -lreadline -lcurses
Ahora puedes ejecutar a.out
que imprimirá la factorización de
x^2-1
.
También puedes ejecutar el programa paso a paso usando gdb.
Recomendamos que copies el fichero .gdbinit
del directorio src
de la distribución giac, porque permite usar
v nombrevar
para imprimir la variable nombrevar
de tipo gen
.
Algunas explicaciones del código:
#include <giac/giac.h>
incluye todas las cabeceras de giac (lo que incluye algunas cabeceras
de STL como string
o vector
).
using namespace
no es obligatoria, si no la usas, necesitas modificar
algo del código, p.ej. usa std::string
en vez de string
o giac::gen
en lugar de gen
.
gen
pueden ser construidas a partir de cadenas (usando el intérprete), a partir de algunos tipos de C
(como int
o double
), a partir de tipos de STL
std::complex<double>
o a partir de secuencias (usando el intérprete).
+, -, *
están definidas en el tipo gen
pero la división no está redefinida para evitar confusión entre enteros
(usa iquo
) y división de double (reales) en C (usa rdiv
). Para potencias,
usa pow
como de constumbre.