diff tools/op.c @ 0:5242703e91d3 tip

Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author tomwalters
date Fri, 20 May 2011 15:19:45 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/op.c	Fri May 20 15:19:45 2011 +0100
@@ -0,0 +1,492 @@
+/*
+    op.c        Ordered sequence of operations on input stream.
+   ------
+
+    Operations on each input item are done in the order they appear on the
+    command line. Operations can be repeated as many times as needed on the
+    command line.
+
+    Input items may be binary numbers (short or float) or ascii lines
+    (terminated by CR) according to the type option.
+
+    The list of operations is as follows. Some operations take valued
+    arguments (which are real numbers), others are flags, as indicated:
+
+    operation           result for each input item x
+    -----------------   --------------------------------------------
+    add=<value>         x+<value>
+    negate=on           -x
+    multiply=<value>    x*<value>
+    divide=<value>      x/<value>
+    remainder=<value>   real remainder of x/<value>
+    inverse=on          1/x
+    round=on            x rounded to nearest integer
+    absolute=on         |x|
+    power=<value>       x^<value>
+    exponent=<value>    <value>^x
+    e-exponent=on       e^x
+    log=<value>         log(x) to base <value>
+    e-log=on            log(x) to base e.
+    sin=on              sin(x)
+    cos=on              cos(x)
+    tan=on              tan(x)
+    threshold=<value>   if ( x  <value> ) 0 else if ( x = <value> ) 1
+    diff1=on            first difference
+    diff2=on            second difference
+    diff3=on            third difference
+    cusum=on            cumulative sum
+    cumean=on           cumulative (recursive) mean an
+    cumin=on            cumulative min
+    cumax=on            cumulative max
+
+    The `type' option sets the data type for all input and output items.
+    Recognised data types are: short, float, ascii.
+
+
+    Ascii data is read in line-by-line, and comment lines are allowed.
+    The following operation apply only to ascii input items, enabling
+    comment lines to be stripped or echoed directly to the output.
+
+    strip=<value>       ignore lines beginning with <value> string
+    echo=<value>        echo lines beginning with <value> string
+    number=on           number output lines
+			If number=on then stripped lines are
+			not numbered; they simply dissappear.
+
+    If there are no operations, (other than comment stripping/echoing or line
+    numbering), then ascii lines are echoed.
+
+
+Examples:
+
+1. To specify the following ordered sequence of operations on each binary
+float in the input stream: invert (take reciprocal), scale up by 100,
+square (raise to power 2), invert (take reciprocal), square root (raise to
+power 0.5).
+
+op type=float inverse=on multiply=100 power=2 inverse=on power=.5  file
+
+
+2. To use as an interactive "desk calculator", eg to print out the result
+of log2(17/16):
+
+echo 17 | op type=ascii -div16 -log2
+
+3. To interactively operate on a list, eg add 1 to each of the list 1,2,3,
+(note how to put newlines into echo'd lists):
+
+echo "1\
+2\
+3" | op type=ascii -add1
+
+4. To read ascii data, echoing any comment lines beginning with the string
+"**", and for each number x in infile, o/p the number 149-x, do:
+
+op type=ascii echo="**" neg=on -add149  infile > outfile
+
+*/
+
+#include <stdio.h>
+#include <math.h>
+#include "options.h"
+#include "strmatch.h"
+
+char applic[] = "Ordered sequence of operations on each item in input stream.\n     (Input and output in binary shorts)." ;
+
+static char *helpstr, *debugstr,
+		*addstr ,
+		*negstr ,
+		*mulstr ,
+		*divstr ,
+		*remstr ,
+		*invstr ,
+		*rndstr ,
+		*absstr ,
+		*powstr ,
+		*expstr ,
+		*eexpstr,
+		*logstr ,
+		*elogstr,
+		*sinstr ,
+		*cosstr ,
+		*tanstr ,
+		*threshstr,
+		*diff1str  ,
+		*diff2str  ,
+		*diff3str  ,
+		*cusumstr   ,
+		*cumeanstr  ,
+		*cuminstr   ,
+		*cumaxstr   ,
+		*typestr ,
+		*stripstr ,
+		*echostr  ,
+		*numstr    ;
+
+static Options option[] = {
+    {   "help"      ,   "off"       ,  &helpstr     ,   "help"                                                  , DEBUG   },
+    {   "debug"     ,   "off"       ,  &debugstr    ,   "debugging switch"                                      , DEBUG   },
+    {   "add"       ,   "off"       ,  &addstr      ,   "Add                    x = x+value  "                  , VAL     },
+    {   "negate"    ,   "off"       ,  &negstr      ,   "Negate                 x = -x     "                    , SETFLAG },
+    {   "multiply"  ,   "off"       ,  &mulstr      ,   "Multiply               x = x*value  "                  , VAL     },
+    {   "divide"    ,   "off"       ,  &divstr      ,   "Divide                 x = x/value  "                  , VAL     },
+    {   "remainder" ,   "off"       ,  &remstr      ,   "Remainder              x = real remainder of x/value"  , VAL     },
+    {   "inverse"   ,   "off"       ,  &invstr      ,   "Inverse                x = 1/x    "                    , SETFLAG },
+    {   "round"     ,   "off"       ,  &rndstr      ,   "Round                  x = x, to nearest integer"      , SETFLAG },
+    {   "absolute"  ,   "off"       ,  &absstr      ,   "Absolute               x = |x|    "                    , SETFLAG },
+    {   "power"     ,   "off"       ,  &powstr      ,   "Power                  x = x^value  "                  , VAL     },
+    {   "exponent"  ,   "off"       ,  &expstr      ,   "Exponent               x = value^x  "                  , VAL     },
+    {   "e-exponent",   "off"       ,  &eexpstr     ,   "e-exponent             x = e^x    "                    , SETFLAG },
+    {   "log"       ,   "off"       ,  &logstr      ,   "Log                    x = log(x), base `value'."      , VAL     },
+    {   "e-log"     ,   "off"       ,  &elogstr     ,   "elog                   x = log(x), base e.    "        , SETFLAG },
+    {   "sin"       ,   "off"       ,  &sinstr      ,   "sin                    x = sin(x) "                    , SETFLAG },
+    {   "cos"       ,   "off"       ,  &cosstr      ,   "cos                    x = cos(x) "                    , SETFLAG },
+    {   "tan"       ,   "off"       ,  &tanstr      ,   "tan                    x = tan(x) "                    , SETFLAG },
+    {   "threshold" ,   "off"       ,  &threshstr   ,   "Threshold              x = 0 (x<value) or 1 (x>=value)", VAL     },
+    {   "diff1"     ,   "off"       ,  &diff1str    ,   "First difference "                                     , SETFLAG },
+    {   "diff2"     ,   "off"       ,  &diff1str    ,   "Second difference "                                    , SETFLAG },
+    {   "diff3"     ,   "off"       ,  &diff1str    ,   "Third difference "                                     , SETFLAG },
+    {   "cusum"     ,   "off"       ,  &cusumstr    ,   "Cumulative sum         x = current sum"                , SETFLAG },
+    {   "cumean"    ,   "off"       ,  &cumeanstr   ,   "Cumulative mean        x = current (recursive) mean"   , SETFLAG },
+    {   "cumin"     ,   "off"       ,  &cuminstr    ,   "Cumulative min         x = current min  "              , SETFLAG },
+    {   "cumax"     ,   "off"       ,  &cumaxstr    ,   "Cumulative max         x = current max  "              , SETFLAG },
+    {   "type"      ,   "short"     ,  &typestr     ,   "Data type (short, float, ascii)"                       , VAL     },
+    {   "strip"     ,   "off"       ,  &stripstr    ,   "Ignore lines beginning with value string"              , VAL     },
+    {   "echo"      ,   "off"       ,  &echostr     ,   "Echo lines beginning with value string"                , VAL     },
+    {   "number"    ,   "off"       ,  &numstr      ,   "Number output lines"                                   , SETFLAG },
+   ( char * ) 0 } ;
+
+
+#define SIZE        64  /* Max number of program command-line arguments */
+
+#define Add          2  /* Functions */
+#define Negate       3
+#define Multiply     4
+#define Divide       5
+#define Remainder    6
+#define Inverse      7
+#define Round        8
+#define Absolute     9
+#define Power       10
+#define Exp         11
+#define Eexp        12
+#define Log         13
+#define Elog        14
+#define Sin         15
+#define Cos         16
+#define Tan         17
+#define Threshold   18
+#define Diff1       19
+#define Diff2       20
+#define Diff3       21
+#define Sum         22
+#define Mean        23
+#define Min         24
+#define Max         25
+#define Ascii       26
+#define Strip       27
+#define Echo        28
+#define Number      29
+
+
+/* data types */
+
+#define SHORT        0
+#define FLOAT        1
+#define ASCII        2
+
+int     Type ;
+
+int     STRIP=0;
+char    Stripstr[]="*";         /* Default strip comment string */
+
+int     ECHO=0;
+char    Echostr[]="**";         /* Default echo comment string */
+
+int     NUMBER=0;               /* Flag for numbering ascii lines */
+int     n=0;
+
+/*
+ Rounding for both +ve and -ve numbers. Real numbers are truncated to ints in
+ the direction of zero (EG both 0.9 and -0.9 are truncated to 0). Using round,
+ 0.9 becomes 1 and -0.9 becomes -1. (Note also 0.5 becomes 1, -0.5 becomes -1.
+*/
+#define round(x)    ((x >= 0) ? ((int)(x+0.5)) : ((int)(x-0.5)))
+
+/* Remainder of real division for +ve and -ve numbers */
+#define rem(x,y)    ((x >= 0) ? (fabs((x) - (y)*(int)((x)/(y)))) : (fabs((x) - (y)*(int)((x)/(y)-0.5))))
+
+/* Threshold and convert to binary (0,1) value */
+#define threshold(x,T)  ((x >= T) ? 1 : 0)
+
+float diff1();
+float diff2();
+float diff3();
+float mean();
+float min();
+float max();
+float sum();
+
+struct opstr {      /* array of operations: functions and (optional) arg */
+    char  func;
+    float arg;
+} op[SIZE];
+
+int k=0;            /* number of operations stored in array */
+
+main(argc, argv)
+int   argc ;
+char *argv[] ;
+{
+    FILE *fp, *fopen();
+    float xf, ops();
+    short xs ;
+    char  s[256], stripcomment[32], echocomment[32];
+    char *prog, *val ;
+    int   i, index, span ;
+
+    strcpy(stripcomment, Stripstr);
+    strcpy(echocomment,  Echostr );
+
+    for (i=0 ; option[i].name != (char *)0 ; i++)
+	*(option[i].val) = option[i].dflt ;
+
+    prog = argv[0] ;
+    while ( --argc > 0 && ++argv ) {
+	if ( ( i = whichopt( option, *argv, &index, &span ) ) == UNKNOWN )
+	    break ;
+	if ( ( val = checksyntax( *argv, span, option[index].type ) ) == (char *)0 )
+	    break ;
+	if ( i == AMBIGUOUS ) {
+	    fprintf(stderr,"%s: ambiguous option [%s]\n", prog, *argv ) ;
+	    exit ( 1 ) ;
+	}
+	switch ( index ) {
+	    case  0 : operate( option, index,  val ) ;                      break;
+	    case  1 : operate( option, index,  val ) ;                      break;
+	    case  2 : op[k].func = Add;         op[k].arg = atof(val); k++; break;
+	    case  3 : op[k].func = Negate;                             k++; break;
+	    case  4 : op[k].func = Multiply;    op[k].arg = atof(val); k++; break;
+	    case  5 : op[k].func = Divide;      op[k].arg = atof(val); k++; break;
+	    case  6 : op[k].func = Remainder;   op[k].arg = atof(val); k++; break;
+	    case  7 : op[k].func = Inverse;                            k++; break;
+	    case  8 : op[k].func = Round;                              k++; break;
+	    case  9 : op[k].func = Absolute;                           k++; break;
+	    case 10 : op[k].func = Power;       op[k].arg = atof(val); k++; break;
+	    case 11 : op[k].func = Exp;         op[k].arg = atof(val); k++; break;
+	    case 12 : op[k].func = Eexp;                               k++; break;
+	    case 13 : op[k].func = Log;         op[k].arg = atof(val); k++; break;
+	    case 14 : op[k].func = Elog;                               k++; break;
+	    case 15 : op[k].func = Sin;                                k++; break;
+	    case 16 : op[k].func = Cos;                                k++; break;
+	    case 17 : op[k].func = Tan;                                k++; break;
+	    case 18 : op[k].func = Threshold;   op[k].arg = atof(val); k++; break;
+	    case 19 : op[k].func = Diff1;                              k++; break;
+	    case 20 : op[k].func = Diff2;                              k++; break;
+	    case 21 : op[k].func = Diff3;                              k++; break;
+	    case 22 : op[k].func = Sum;                                k++; break;
+	    case 23 : op[k].func = Mean;                               k++; break;
+	    case 24 : op[k].func = Min;                                k++; break;
+	    case 25 : op[k].func = Max;                                k++; break;
+	    case 26 : Type = checktype( val ) ;                             break;
+	    case 27 : STRIP++; strcpy(stripcomment, val);                   break;
+	    case 28 : ECHO++;  strcpy(echocomment,  val);                   break;
+	    case 29 : NUMBER++;                                             break;
+	}
+
+    }
+    if ( !isoff( helpstr ) )
+	helpopts( helpstr, prog, applic, option ) ;
+
+    if (argc <= 0) fp = stdin;
+    else if ((fp = fopen(*argv, "r")) == NULL) {
+	    fprintf(stderr,"can't open %s\n", *argv);
+	    exit(1);
+	}
+
+    switch ( Type ) {
+
+	case SHORT :
+	    while ( fread( &xs, sizeof(short), 1, fp ) ) {
+		xs = (short)ops( (float)xs ) ;
+		fwrite( &xs, sizeof(short), 1, stdout ) ;
+	    }
+	    break ;
+
+	case FLOAT :
+	    while ( fread( &xf, sizeof(float), 1, fp ) ) {
+		xf = ops( xf ) ;
+		fwrite( &xf, sizeof(float), 1, stdout ) ;
+	    }
+	    break ;
+
+	case ASCII :
+	    while (fgets(s, 256, fp)) {
+		if (STRIP && match(s,stripcomment)==0)
+		    ;                       /* strip comment (ie do nothing) */
+		else {
+		    if (NUMBER) printf("%d: ", ++n);
+		    if (ECHO && match(s,echocomment)==0)
+			fputs(s,stdout);        /* echo comment */
+		    else {
+			if ( k>0 ) {
+			    xf = ops( atof(s) ) ;
+			    printf("%.3f\n", xf ) ;
+			}
+			else fputs(s,stdout);   /* echo line (case of no ops) */
+		    }
+		}
+	    }
+	    break ;
+    }
+
+    fclose(fp);
+}
+
+
+checktype( s )
+char *s ;
+{
+    if ( iststr( s, "short" ) )  return SHORT ;
+    if ( iststr( s, "float" ) )  return FLOAT ;
+    if ( iststr( s, "ascii" ) )  return ASCII ;
+    fprintf( stderr,"unknown datatype [%s]\n", s ) ;
+    exit( 1 ) ;
+}
+
+
+float ops(x)
+float x;
+{
+    int i;
+
+    for (i=0 ; i<k ; i++)
+	switch (op[i].func) {
+	    case Add:           x = x+op[i].arg;            break;
+	    case Negate:        x = (-x);                   break;
+	    case Multiply:      x = x*op[i].arg;            break;
+	    case Divide:        x = x/op[i].arg;            break;
+	    case Remainder:     x = rem(x,op[i].arg);       break;
+	    case Inverse:       x = 1.0/x;                  break;
+	    case Round:         x = round(x);               break;
+	    case Absolute:      x = fabs(x);                break;
+	    case Power:         x = pow(x,op[i].arg);       break;
+	    case Exp:           x = pow(op[i].arg,x);       break;
+	    case Eexp:          x = exp(x);                 break;
+	    case Log:           x = log(x)/log(op[i].arg);  break;
+	    case Elog:          x = log(x);                 break;
+	    case Sin:           x = sin(x);                 break;
+	    case Cos:           x = cos(x);                 break;
+	    case Tan:           x = tan(x);                 break;
+	    case Threshold:     x = threshold(x,op[i].arg); break;
+	    case Diff1:         x = diff1(x);               break;
+	    case Diff2:         x = diff2(x);               break;
+	    case Diff3:         x = diff3(x);               break;
+	    case Sum:           x = sum(x);                 break;
+	    case Mean:          x = mean(x);                break;
+	    case Min:           x = min(x);                 break;
+	    case Max:           x = max(x);                 break;
+	}
+    return x;
+}
+
+
+match(s1,s2)
+char *s1, *s2;
+{
+    int  n1, n2;
+
+    if ((n1=strlen(s1)) < (n2=strlen(s2)))
+	return strncmp(s1,s2,n1);
+    else
+	return strncmp(s1,s2,n2);
+}
+
+
+/****************************************************************************
+ The past values used to compute differences are, (in the order they would
+ appear in an array, where x is the current value):
+	1st diffs           ... x11 x
+	2nd diffs       ... x22 x21 x
+	3rd diffs   ... x33 x32 x31 x
+*****************************************************************************/
+float diff1(x)
+float x;
+{
+    static float x11=0;
+    float  d;
+
+    d=fabs(x11-x);
+    x11=x;
+    return d;
+}
+
+float diff2(x)
+float x;
+{
+    static float x21=0, x22=0;
+    float  d;
+
+    d=fabs( fabs(x22-x21)-fabs(x21-x) );
+    x22=x21;
+    x21=x;
+    return d;
+}
+
+float diff3(x)
+float x;
+{
+    static float x31=0, x32=0, x33=0;
+    float  d;
+
+    d=fabs( fabs( fabs(x33-x32)-fabs(x32-x31) ) - fabs( fabs(x32-x31)-fabs(x31-x) ) );
+    x33=x32;
+    x32=x31;
+    x31=x;
+    return d;
+}
+
+/****************************************************************************
+ Recurisve estimation of the mean
+ (Ref: Young, eqn 2.14 (p14), eqn VI(2) (p63), eqn 5.17 (p65))
+****************************************************************************/
+float mean(x)
+float x;
+{
+    static float a = 0;         /* initial mean value */
+    static float p = 10000;     /* initial gain factor [Young p65] */
+
+    p = p/(1+p);                /* update p (the gain factor)   */
+    a = a - p*(a-x);            /* update a (the mean estimate) */
+    return a;
+}
+
+/****************************************************************************
+ Min, Max, and Sum
+****************************************************************************/
+float min(x)
+float x;
+{
+    static float MIN=1.0e30;
+
+    if (x < MIN) MIN = x;
+    return MIN;
+}
+
+float max(x)
+float x;
+{
+    static float MAX=0;
+
+    if (x > MAX) MAX = x;
+    return MAX;
+}
+
+float sum(x)
+float x;
+{
+    static float SUM=0;
+
+    SUM += x;
+    return SUM;
+}