/*****************************************************************************1*2* Elmer, A Finite Element Software for Multiphysical Problems3*4* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland5*6* This library is free software; you can redistribute it and/or7* modify it under the terms of the GNU Lesser General Public8* License as published by the Free Software Foundation; either9* version 2.1 of the License, or (at your option) any later version.10*11* This library is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU14* Lesser General Public License for more details.15*16* You should have received a copy of the GNU Lesser General Public17* License along with this library (in file ../LGPL-2.1); if not, write18* to the Free Software Foundation, Inc., 51 Franklin Street,19* Fifth Floor, Boston, MA 02110-1301 USA20*21*****************************************************************************/2223/*******************************************************************************24*25* Evaluate expression threes in format parsed by parser.c.26*27*******************************************************************************28*29* Author: Juha Ruokolainen30*31* Address: CSC - IT Center for Science Ltd.32* Keilaranta 14, P.O. BOX 40533* 02101 Espoo, Finland34* Tel. +358 0 457 272335* Telefax: +358 0 457 230236* EMail: [email protected]37*38* Date: 30 May 199639*40* Modified by:41*42* Date of modification:43*44******************************************************************************/45/***********************************************************************46|47| EVAL.C - Last Edited 6. 8. 198848|49***********************************************************************/50#include "../config.h"51/*======================================================================52|Syntax of the manual pages:53|54|FUNCTION NAME(...) params ...55|56$ usage of the function and type of the parameters57? explain the effects of the function58= return value and the type of value if not of type int59@ globals effected directly by this routine60! current known bugs or limitations61& functions called by this function62~ these functions may interest you as an alternative function or63| because they control this function somehow64^=====================================================================*/656667/*68* $Id: eval.c,v 1.5 2006/02/02 06:51:16 jpr Exp $69*70* $Log: eval.c,v $71* Revision 1.4 2005/08/25 13:44:22 vierinen72* windoze stuff73*74* Revision 1.3 2005/05/27 12:26:20 vierinen75* changed header install location76*77* Revision 1.2 2005/05/26 12:34:53 vierinen78* windows stuff79*80* Revision 1.1.1.1 2005/04/14 13:29:14 vierinen81* initial matc automake package82*83* Revision 1.2 1998/08/01 12:34:35 jpr84*85* Added Id, started Log.86*87*88*/8990#include "elmer/matc.h"9192VARIABLE *evaltree(TREE *root)93/*======================================================================94? Evaluate the equation tree (real hard). The tree might be a list of95| trees. If there is more than one tree in the list, the return value96| will be a single column vector, the result from each tree is97| concatenated to this vector. If there's only one tree, return98| value is tree's evaluated result.99|100& strlen(), fopen(), fclose(), var_temp_new(), var_temp_copy(),101| var_delete_temp(), com_check(), var_check(), fnc_check(),102| fnc_exec(), com_pointw(), com_source()103|104^=====================================================================*/105{106107VARIABLE *first, /* used to hold start address for */108/* temporary list of VARIABLES, the */109/* evaluated trees results */110*subs, /* indexes for tree elements */111*par, /* parameters for tree elements */112*res, /* result is returned in this var. */113/* probably used as a temporary too */114*leftptr, /* result from left leaf */115*rightptr, /* result from right leaf */116*tmp, /* can't manage without these */117*tmp1;118119FUNCTION *fnc; /* needed, if someone's using defined functions */120121COMMAND *com; /* needed, maybe */122123MATRIX *opres; /* don't know really */124125TREE *argptr; /* temporary */126127int i, /* there's always reason for these */128dim, /* the final dimension of the return value */129argcount; /* parameter count */130131char *resbeg; /* for memcpying */132133FILE *fp; /* used to check if a file exists */134135136if (root == NULL) return NULL;137138dim = 0; first = NULL;139140/*-------------------------------------------------------------------*/141142/*143while there's trees in the list.144*/145while(root)146{147148subs = par = tmp = NULL;149150/*151check if the result will be indexed152*/153argptr = SUBS(root);154if (argptr)155{156subs = tmp = evaltree(argptr);157argptr = NEXT(argptr);158while(argptr)159{160NEXT(tmp) = evaltree(argptr);161argptr = NEXT(argptr); tmp = NEXT(tmp);162}163}164165switch(ETYPE(root))166{167168/******************************************************169some kind of existing identifier.170*******************************************************/171case ETYPE_NAME:172/*173is there parameters for this one ?174and how many ?175*/176argptr = ARGS(root);177argcount = 0;178if (argptr)179{180par = tmp = evaltree(argptr);181argptr = NEXT(argptr);182argcount++;183while(argptr)184{185argcount++;186NEXT(tmp) = evaltree(argptr);187argptr = NEXT(argptr); tmp = NEXT(tmp);188}189}190191192/*193one of the builtin commands (sin, ones, help, ...)194*/195if ((com = com_check(SDATA(root))) != (COMMAND *)NULL)196{197198if (argcount < com->minp || argcount > com->maxp)199{200if (com->minp == com->maxp)201{202error( "Builtin function [%s] requires %d argument(s).\n", SDATA(root), com->minp);203}204else205{206error("Builtin function [%s] takes from %d to %d argument(s).\n",207SDATA(root), com->minp, com->maxp);208}209}210211212if (com->flags & CMDFLAG_PW)213{214tmp = com_pointw((double (*)())com->sub, par);215}216else217{218tmp = ((VARIABLE *(*)(VARIABLE *)) (com->sub))(par);219}220}221222223/*224a variable name225*/226else if ((tmp1 = var_check(SDATA(root))) != (VARIABLE *)NULL)227{228tmp = (VARIABLE *)ALLOCMEM(VARIABLESIZE);229tmp ->this = tmp1->this;230REFCNT(tmp)++;231if (par != NULL)232{233subs = par; par = NULL;234}235}236237/*238user defined function239*/240else if ((fnc = fnc_check(SDATA(root))) != (FUNCTION *)NULL)241{242tmp = fnc_exec(fnc, par); par = NULL;243}244245246/*247maybe a file name ?248*/249else if ((fp = fopen(SDATA(root),"r")) != (FILE *)NULL)250{251fclose(fp);252tmp = var_temp_new(TYPE_STRING, 1, strlen(SDATA(root)));253for(i = 0; i < strlen(SDATA(root)); i++)254{255M(tmp, 0, i) = SDATA(root)[i];256}257(*com_source)(tmp);258var_delete_temp(tmp);259tmp = NULL;260}261262/*263troubles!264*/265else266{267error("Undeclared identifier: [%s].\n", SDATA(root));268}269270break;271272273/******************************************************274single string constant275*******************************************************/276case ETYPE_STRING:277tmp = var_temp_new(TYPE_STRING, 1, strlen(SDATA(root)));278for(i = 0; i < strlen(SDATA(root)); i++)279{280M(tmp,0,i) = SDATA(root)[i];281}282break;283284/******************************************************285single numeric constant286*******************************************************/287case ETYPE_NUMBER:288tmp = var_temp_new(TYPE_DOUBLE, 1, 1);289M(tmp,0,0) = DDATA(root);290break;291292/******************************************************293constant matrix294*******************************************************/295case ETYPE_CONST:296tmp = (VARIABLE *)ALLOCMEM(VARIABLESIZE);297tmp->this = CDATA(root)->this;298REFCNT(tmp)++;299break;300301/******************************************************302huh ?303*******************************************************/304case ETYPE_EQUAT:305tmp = evaltree(LEFT(root));306break;307308/******************************************************309left oper [right]310oper = divide, multiply, transpose, power,...311*******************************************************/312case ETYPE_OPER:313/*314* evaluate both leafs.315*/316leftptr = rightptr = NULL; opres = NULL;317318leftptr = evaltree(LEFT(root));319rightptr = evaltree(RIGHT(root));320321if (leftptr && rightptr)322opres = ((MATRIX *(*)(MATRIX *, MATRIX *)) (VDATA(root)))(leftptr->this, rightptr->this);323else if (leftptr)324opres = ((MATRIX *(*)(MATRIX *, MATRIX *)) (VDATA(root)))(leftptr->this, NULL);325else if (rightptr)326opres = ((MATRIX *(*)(MATRIX *, MATRIX *)) (VDATA(root)))(rightptr->this, NULL);327328var_delete_temp(leftptr);329var_delete_temp(rightptr);330331if (opres != NULL)332{333tmp = (VARIABLE *)ALLOCMEM(VARIABLESIZE);334tmp->this = opres;335REFCNT(tmp) = 1;336}337338break;339}340341/*342if NULL result, don't really know what to do, so we try quitting.343*/344/*345if (tmp == (VARIABLE *)NULL)346{347if (subs) var_delete_temp(subs);348if (par) var_delete_temp(par);349if (first) var_delete_temp(first);350return (VARIABLE *)NULL;351}352*/353354/******************************************************355deleting temporaries, preparing for next loop356*******************************************************/357if (subs != NULL)358{359if (tmp != NULL)360{361tmp1 = tmp;362NEXT(tmp1) = subs;363tmp = com_el(tmp1);364var_delete_temp(tmp1);365}366else367{368var_delete_temp(subs);369}370tmp1 = subs = NULL;371}372373if (first == NULL)374{375first = res = tmp;376}377else if (tmp != NULL)378{379NEXT(res) = tmp; res = NEXT(res);380}381382if (subs) var_delete_temp(subs);383if (par) var_delete_temp(par);384385if (tmp != NULL) dim += NROW(tmp) * NCOL(tmp);/* count size of the result */386387root = LINK(root);388}389/*-------------------------------------------------------------------*/390391/*392there was only one tree, so return it's result.393*/394if (tmp == first) return first;395396/*397it was a list of trees, concatenate the results398*/399res = var_temp_new(TYPE(first), 1, dim);400401resbeg = (char *)MATR(res);402for(tmp = first; tmp; tmp = NEXT(tmp))403{404memcpy(resbeg, (char *)MATR(tmp), MATSIZE(tmp));405resbeg += MATSIZE(tmp);406}407/*408and delete rest of the temporaries.409*/410var_delete_temp(first);411412return res;413}414415VARIABLE *evalclause(CLAUSE *root)416/*======================================================================417? Evaluate the operations list. The list contains equations trees418| (actually lists of trees :-).419|420& ALLOCMEM, FREEMEM, STRCOPY, var_temp_new(), var_delete_temp(),421& var_check(), com_check(), fnc_check(), evaltree(),422^=====================================================================*/423{424VARIABLE *ptr = NULL,425*res, *par, *tmp; /* used for something magic */426427TREE *argptr; /* pointer to parameters */428429double *d;430431int i;432433/*-------------------------------------------------------------------*/434435while(root)436{437if (root->data == endsym) return ptr;438439switch(root->data)440{441/************************************************************442System call443************************************************************/444case systemcall:445{446#if defined(WIN32) || defined(MINGW32)447FILE *fp = _popen( SDATA(root->this), "r" );448#else449FILE *fp = popen( SDATA(root->this), "r" );450#endif451static char s[121];452#pragma omp threadprivate (s)453454if ( !fp ) error( "systemcall: open failure: [%s].\n", SDATA(root->this) );455456while( fgets( s, 120, fp ) ) PrintOut( s );457458#if defined(WIN32) || defined(MINGW32)459_pclose( fp );460#else461pclose( fp );462#endif463}464break;465/************************************************************466Function definition467************************************************************/468case funcsym:469{470471FUNCTION *fnc; /* pointer to created function */472TREE *tptr; /* function parameters */473char *name = SDATA(root->this); /* function name */474int i, n, argcount; /* well... */475476/*477check for name conflicts478*/479if (var_check(name) || com_check(name))480{481error( "Function not created [%s], identifier in use.\n",name);482}483484/*485* allocate mem for FUNCTION structure and add it486* to the the FUNCTIONS list487*/488if (fnc = fnc_check(name)) fnc_free_entry(fnc);489fnc = (FUNCTION *)ALLOCMEM(sizeof(FUNCTION));490NAME(fnc) = STRCOPY(name);491lst_add(FUNCTIONS, (LIST *)fnc);492493/*494* copy parameter names to the structure.495*/496argcount = 0;497for(tptr = ARGS(root->this); tptr; tptr = NEXT(tptr)) argcount++;498if (argcount > 0)499{500fnc -> parnames = (char **)ALLOCMEM(argcount * sizeof(char *));501for(i = 0, tptr = ARGS(root->this); tptr; tptr = NEXT(tptr))502fnc -> parnames[i++] = STRCOPY(SDATA(tptr));503}504fnc -> parcount = argcount;505506/*507* copy help text if any to the structure.508*/509argcount = n = 0;510for( tptr = SUBS(root->this); tptr; tptr = NEXT(tptr))511{512if ( SDATA(tptr) )513{514argcount++;515n += strlen( SDATA(tptr) );516}517}518if ( argcount > 0 && n > 0)519{520fnc->help = (char *)ALLOCMEM( (n+argcount+1)*sizeof(char) );521for( tptr = SUBS(root->this); tptr; tptr = NEXT(tptr) )522{523if ( SDATA(tptr) )524{525strcat( fnc->help, SDATA(tptr) );526strcat( fnc->help, "\n" );527}528}529}530531/*532* copy imported variable names to the structure.533*/534argcount = 0;535for(tptr = LEFT(root->this); tptr; tptr = NEXT(tptr)) argcount++;536if (argcount > 0)537{538fnc -> imports = (char **)ALLOCMEM((argcount+1) * sizeof(char *));539for(i = 0, tptr = LEFT(root->this); tptr; tptr = NEXT(tptr))540fnc -> imports[i++] = STRCOPY(SDATA(tptr));541fnc -> imports[i] = NULL;542}543else544fnc -> imports = NULL;545546/*547* copy exported variable names to the structure.548*/549argcount = 0;550for(tptr = RIGHT(root->this); tptr; tptr = NEXT(tptr)) argcount++;551if (argcount > 0)552{553fnc -> exports = (char **)ALLOCMEM((argcount+1) * sizeof(char *));554for(i = 0, tptr = RIGHT(root->this); tptr; tptr = NEXT(tptr))555fnc -> exports[i++] = STRCOPY(SDATA(tptr));556fnc -> exports[i] = NULL;557}558else559fnc -> exports = NULL;560561/*562and finally the function body563*/564fnc -> body = LINK(root); LINK(root) = NULL;565566/* PrintOut( "Function defined: [%s].\n", name); */567568return NULL;569}570571572/***************************************************************573statement574****************************************************************/575case assignsym:576{577578int iflg = FALSE, /* is the result indexed */579pflg = TRUE; /* should it be printed to */580/* output stream */581582char *r = "ans"; /* resulted VARIABLE name */583584par = NULL;585586/*587* there is an explicit assignment (ie. x = x + 1, not x + 1)588*/589if (root->this)590{591/*592* VARIABLE name593*/594r = SDATA( root->this );595596/*597* check for name conflicts598*/599if ( fnc_check(r) || com_check(r) || lst_find(CONSTANTS, r) )600{601error( "VARIABLE not created [%s], identifier in use.\n", r );602}603604/*605* is it indexed ?606*/607pflg = FALSE;608argptr = ARGS(root->this);609if (argptr)610{611iflg = TRUE;612if ((par = tmp = evaltree(argptr)) != NULL)613{614argptr = NEXT(argptr);615while(argptr)616{617if ((NEXT(tmp) = evaltree(argptr)) == NULL) break;618argptr = NEXT(argptr);619tmp = NEXT(tmp);620}621}622}623}624625/*626* evaluate the right side of the statement627* and put the result where it belongs628*/629ptr = evaltree( LINK(root)->this );630ptr = put_result( ptr, r, par, iflg, pflg );631632if ( par ) var_delete_temp( par );633root = LINK(root);634635break;636}637638/***************************************************************639if statement640****************************************************************/641case ifsym:642643if ((res = evaltree(root->this)) != NULL)644{645for(i = 0, d=MATR(res); i < NROW(res)*NCOL(res); i++)646if (*d++ == 0) break;647648/*649* condition false650*/651if (*--d == 0)652{653root = root->jmp;654if (root->data == elsesym)655{656ptr = evalclause(LINK(root));657root = root -> jmp;658}659}660661/*662* condition true663*/664else665{666ptr = evalclause(LINK(root));667root = root->jmp;668if (root->data == elsesym)669{670root = root->jmp;671}672}673var_delete_temp(res);674}675else676{677root = root -> jmp;678if (root->data == elsesym)679{680root = root->jmp;681}682}683break;684685/***************************************************************686while statement687****************************************************************/688case whilesym:689690while(TRUE)691{692if ((res = evaltree(root->this)) == NULL) break;693694for(i=0, d=MATR(res); i < NROW(res)*NCOL(res); i++)695if (*d++ == 0) break;696697/*698condition true, go for another loop699*/700if (*--d != 0)701{702ptr = evalclause(LINK(root));703var_delete_temp(res);704}705706/*707condition false, done with while-loop708*/709else710{711var_delete_temp(res);712break;713}714}715root = root->jmp;716break;717718/***************************************************************719for statement720****************************************************************/721case forsym:722{723VARIABLE *var;724char *r;725726/*727* VARIABLE name728*/729r = SDATA(root->this);730731/*732* check for name conflicts733*/734if (fnc_check(r) || com_check(r) || lst_find(CONSTANTS, r))735{736error( "VARIABLE not created [%s], identifier in use.\n ", r);737}738739if ((res = evaltree(LINK(root->this))) != NULL)740{741if ((var = var_check(r)) == NULL)742var = var_new(r,TYPE(res),1,1);743744d = MATR(res);745for(i = 0; i < NCOL(res)*NROW(res); i++)746{747*MATR(var) = *d++;748ptr = evalclause(LINK(root));749}750751var_delete_temp(res);752}753root = root->jmp;754break;755}756}757root = LINK(root);758}759return ptr;760}761762VARIABLE *put_values(VARIABLE *ptr, char *resname, VARIABLE *par)763/*======================================================================764? extract values from ptr, indexes in par, and put them to res765^=====================================================================*/766{767static double defind = 0.0;768#pragma omp threadprivate (defind)769770double *ind1,771*ind2,772*dtmp;773774int i, j, k,775rows, cols,776size1, size2,777imax1, imax2,778ind;779780VARIABLE *res;781782res = (VARIABLE *)lst_find(VARIABLES, resname);783784if (NEXT(par) == NULL)785{786if (787res != NULL && NROW(par) == NROW(res) && NCOL(par) == NCOL(res)788&& !(NROW(res) == 1 && NCOL(res) == 1)789)790{791int logical = TRUE,792csize = 0;793794dtmp = MATR(par);795for(i = 0; i < NROW(par)*NCOL(par); i++)796if (dtmp[i] != 0 && dtmp[i] != 1)797{798logical = FALSE;799break;800}801802if (logical)803{804imax1 = NROW(ptr) * NCOL(ptr);805dtmp = MATR(ptr);806for(i = 0, k = 0; i < NROW(res); i++)807for(j = 0,csize=0; j < NCOL(res); j++)808{809while(M(par,i,j)==1 && j+csize<NCOL(res) && k+csize<imax1) csize++;810if (csize > 0)811{812memcpy(&M(res,i,j),&dtmp[k],csize*sizeof(double));813j += csize-1;814k += csize;815csize = 0;816if (k >= imax1) k = 0;817}818}819var_delete_temp(ptr);820return res;821}822else823{824ind1 = &defind;825size1 = 1;826ind2 = MATR(par);827size2 = NCOL(par);828}829}830else831{832ind1 = &defind;833size1 = 1;834ind2 = MATR(par);835size2 = NCOL(par);836}837}838else839{840ind1 = MATR(par);841size1 = NCOL(par);842ind2 = MATR(NEXT(par));843size2 = NCOL(NEXT(par));844}845846imax1 = (int)ind1[0];847for(i = 1; i < size1; i++)848{849imax1 = max(imax1, (int)ind1[i]);850}851852imax2 = (int)ind2[0];853for(i = 1; i < size2; i++)854{855imax2 = max(imax2, (int)ind2[i]);856}857858if (res == NULL)859{860res = var_new(resname, TYPE(ptr), imax1+1, imax2+1);861}862else if (NROW(res) <= imax1 || NCOL(res) <= imax2)863{864int ir = NROW(res), jc = NCOL(res);865MATRIX *t;866867imax1 = max(ir, imax1 + 1);868imax2 = max(jc, imax2 + 1);869870t = mat_new(TYPE(res), imax1, imax2);871dtmp = t->data;872873for(i = 0; i < ir; i++)874{875memcpy(&dtmp[i*imax2],&M(res,i,0),jc*sizeof(double));876}877878if (--REFCNT(res) == 0)879{880mat_free(res->this);881}882res->this = t;883REFCNT(res) = 1;884}885else if (REFCNT(res) > 1)886{887--REFCNT(res);888res->this = mat_copy(res->this);889}890891imax1 = NROW(ptr) * NCOL(ptr);892dtmp = MATR(ptr);893for(i = 0, k = 0; i < size1; i++)894{895ind = (int)ind1[i];896for(j = 0; j < size2; j++)897{898memcpy(&M(res,ind,(int)ind2[j]),&dtmp[k++],sizeof(double));899if (k >= imax1) k = 0;900}901}902903var_delete_temp(ptr);904905return res;906}907908VARIABLE *put_result(VARIABLE *ptr, char *resname, VARIABLE *par,909int indexflag, int printflag)910/*======================================================================911? copy VARIABLE from one place to another912| and conditionally print the result913^=====================================================================*/914{915VARIABLE *res = NULL;916917var_delete( "ans" );918if (indexflag && par)919{920res = put_values(ptr, resname, par);921}922else923{924res = var_rename( ptr, resname );925}926927if ( res ) res->changed = 1;928if (printflag) var_print(res);929930return res;931}932933934