Mercurial > libavcodec.hg
comparison eval.c @ 4081:cedb63307f3d libavcodec
new optimized eval method, by seperating parsing and runtime
| author | ods15 |
|---|---|
| date | Fri, 27 Oct 2006 16:42:16 +0000 |
| parents | 0f2bb0baf6f0 |
| children | 16b88d6b3546 |
comparison
equal
deleted
inserted
replaced
| 4080:f426c81afc9e | 4081:cedb63307f3d |
|---|---|
| 28 * see http://joe.hotchkiss.com/programming/eval/eval.html | 28 * see http://joe.hotchkiss.com/programming/eval/eval.html |
| 29 */ | 29 */ |
| 30 | 30 |
| 31 #include "avcodec.h" | 31 #include "avcodec.h" |
| 32 #include "mpegvideo.h" | 32 #include "mpegvideo.h" |
| 33 #include "eval.h" | |
| 33 | 34 |
| 34 #include <stdio.h> | 35 #include <stdio.h> |
| 35 #include <stdlib.h> | 36 #include <stdlib.h> |
| 36 #include <string.h> | 37 #include <string.h> |
| 37 #include <math.h> | 38 #include <math.h> |
| 54 double (**func2)(void *, double a, double b); // NULL terminated | 55 double (**func2)(void *, double a, double b); // NULL terminated |
| 55 char **func2_name; // NULL terminated | 56 char **func2_name; // NULL terminated |
| 56 void *opaque; | 57 void *opaque; |
| 57 char **error; | 58 char **error; |
| 58 } Parser; | 59 } Parser; |
| 59 | |
| 60 static double evalExpression(Parser *p); | |
| 61 | 60 |
| 62 static int8_t si_prefixes['z' - 'E' + 1]={ | 61 static int8_t si_prefixes['z' - 'E' + 1]={ |
| 63 ['y'-'E']= -24, | 62 ['y'-'E']= -24, |
| 64 ['z'-'E']= -21, | 63 ['z'-'E']= -21, |
| 65 ['a'-'E']= -18, | 64 ['a'-'E']= -18, |
| 124 if(prefix[i] != s[i]) return 0; | 123 if(prefix[i] != s[i]) return 0; |
| 125 } | 124 } |
| 126 return 1; | 125 return 1; |
| 127 } | 126 } |
| 128 | 127 |
| 129 static double evalPrimary(Parser *p){ | 128 struct ff_expr_s { |
| 130 double d, d2=NAN; | 129 enum { |
| 130 e_value, e_const, e_func0, e_func1, e_func2, | |
| 131 e_squish, e_gauss, | |
| 132 e_mod, e_max, e_min, e_eq, e_gt, e_gte, | |
| 133 e_pow, e_mul, e_div, e_add, | |
| 134 } type; | |
| 135 double value; // is sign in other types | |
| 136 union { | |
| 137 int const_index; | |
| 138 double (*func0)(double); | |
| 139 double (*func1)(void *, double); | |
| 140 double (*func2)(void *, double, double); | |
| 141 } a; | |
| 142 AVEvalExpr * param[2]; | |
| 143 }; | |
| 144 | |
| 145 static double eval_expr(Parser * p, AVEvalExpr * e) { | |
| 146 switch (e->type) { | |
| 147 case e_value: return e->value; | |
| 148 case e_const: return e->value * p->const_value[e->a.const_index]; | |
| 149 case e_func0: return e->value * e->a.func0(eval_expr(p, e->param[0])); | |
| 150 case e_func1: return e->value * e->a.func1(p->opaque, eval_expr(p, e->param[0])); | |
| 151 case e_func2: return e->value * e->a.func2(p->opaque, eval_expr(p, e->param[0]), eval_expr(p, e->param[1])); | |
| 152 case e_squish: return 1/(1+exp(4*eval_expr(p, e->param[0]))); | |
| 153 case e_gauss: { double d = eval_expr(p, e->param[0]); return exp(-d*d/2)/sqrt(2*M_PI); } | |
| 154 default: { | |
| 155 double d = eval_expr(p, e->param[0]); | |
| 156 double d2 = eval_expr(p, e->param[1]); | |
| 157 switch (e->type) { | |
| 158 case e_mod: return e->value * (d - floor(d/d2)*d2); | |
| 159 case e_max: return e->value * (d > d2 ? d : d2); | |
| 160 case e_min: return e->value * (d < d2 ? d : d2); | |
| 161 case e_eq: return e->value * (d == d2 ? 1.0 : 0.0); | |
| 162 case e_gt: return e->value * (d > d2 ? 1.0 : 0.0); | |
| 163 case e_gte: return e->value * (d >= d2 ? 1.0 : 0.0); | |
| 164 case e_pow: return e->value * pow(d, d2); | |
| 165 case e_mul: return e->value * (d * d2); | |
| 166 case e_div: return e->value * (d / d2); | |
| 167 case e_add: return e->value * (d + d2); | |
| 168 } | |
| 169 } | |
| 170 } | |
| 171 return NAN; | |
| 172 } | |
| 173 | |
| 174 static AVEvalExpr * parse_expr(Parser *p); | |
| 175 | |
| 176 void ff_eval_free(AVEvalExpr * e) { | |
| 177 if (!e) return; | |
| 178 ff_eval_free(e->param[0]); | |
| 179 ff_eval_free(e->param[1]); | |
| 180 av_freep(&e); | |
| 181 } | |
| 182 | |
| 183 static AVEvalExpr * parse_primary(Parser *p) { | |
| 184 AVEvalExpr * d = av_mallocz(sizeof(AVEvalExpr)); | |
| 131 char *next= p->s; | 185 char *next= p->s; |
| 132 int i; | 186 int i; |
| 133 | 187 |
| 134 /* number */ | 188 /* number */ |
| 135 d= av_strtod(p->s, &next); | 189 d->value = av_strtod(p->s, &next); |
| 136 if(next != p->s){ | 190 if(next != p->s){ |
| 191 d->type = e_value; | |
| 137 p->s= next; | 192 p->s= next; |
| 138 return d; | 193 return d; |
| 139 } | 194 } |
| 195 d->value = 1; | |
| 140 | 196 |
| 141 /* named constants */ | 197 /* named constants */ |
| 142 for(i=0; p->const_name && p->const_name[i]; i++){ | 198 for(i=0; p->const_name && p->const_name[i]; i++){ |
| 143 if(strmatch(p->s, p->const_name[i])){ | 199 if(strmatch(p->s, p->const_name[i])){ |
| 144 p->s+= strlen(p->const_name[i]); | 200 p->s+= strlen(p->const_name[i]); |
| 145 return p->const_value[i]; | 201 d->type = e_const; |
| 202 d->a.const_index = i; | |
| 203 return d; | |
| 146 } | 204 } |
| 147 } | 205 } |
| 148 | 206 |
| 149 p->s= strchr(p->s, '('); | 207 p->s= strchr(p->s, '('); |
| 150 if(p->s==NULL){ | 208 if(p->s==NULL){ |
| 151 *p->error = "missing ("; | 209 *p->error = "missing ("; |
| 152 p->s= next; | 210 p->s= next; |
| 153 return NAN; | 211 ff_eval_free(d); |
| 212 return NULL; | |
| 154 } | 213 } |
| 155 p->s++; // "(" | 214 p->s++; // "(" |
| 156 d= evalExpression(p); | 215 if (*next == '(') { // special case do-nothing |
| 216 av_freep(&d); | |
| 217 d = parse_expr(p); | |
| 218 if(p->s[0] != ')'){ | |
| 219 *p->error = "missing )"; | |
| 220 ff_eval_free(d); | |
| 221 return NULL; | |
| 222 } | |
| 223 p->s++; // ")" | |
| 224 return d; | |
| 225 } | |
| 226 d->param[0] = parse_expr(p); | |
| 157 if(p->s[0]== ','){ | 227 if(p->s[0]== ','){ |
| 158 p->s++; // "," | 228 p->s++; // "," |
| 159 d2= evalExpression(p); | 229 d->param[1] = parse_expr(p); |
| 160 } | 230 } |
| 161 if(p->s[0] != ')'){ | 231 if(p->s[0] != ')'){ |
| 162 *p->error = "missing )"; | 232 *p->error = "missing )"; |
| 163 return NAN; | 233 ff_eval_free(d); |
| 234 return NULL; | |
| 164 } | 235 } |
| 165 p->s++; // ")" | 236 p->s++; // ")" |
| 166 | 237 |
| 167 if( strmatch(next, "sinh" ) ) d= sinh(d); | 238 d->type = e_func0; |
| 168 else if( strmatch(next, "cosh" ) ) d= cosh(d); | 239 if( strmatch(next, "sinh" ) ) d->a.func0 = sinh; |
| 169 else if( strmatch(next, "tanh" ) ) d= tanh(d); | 240 else if( strmatch(next, "cosh" ) ) d->a.func0 = cosh; |
| 170 else if( strmatch(next, "sin" ) ) d= sin(d); | 241 else if( strmatch(next, "tanh" ) ) d->a.func0 = tanh; |
| 171 else if( strmatch(next, "cos" ) ) d= cos(d); | 242 else if( strmatch(next, "sin" ) ) d->a.func0 = sin; |
| 172 else if( strmatch(next, "tan" ) ) d= tan(d); | 243 else if( strmatch(next, "cos" ) ) d->a.func0 = cos; |
| 173 else if( strmatch(next, "atan" ) ) d= atan(d); | 244 else if( strmatch(next, "tan" ) ) d->a.func0 = tan; |
| 174 else if( strmatch(next, "asin" ) ) d= asin(d); | 245 else if( strmatch(next, "atan" ) ) d->a.func0 = atan; |
| 175 else if( strmatch(next, "acos" ) ) d= acos(d); | 246 else if( strmatch(next, "asin" ) ) d->a.func0 = asin; |
| 176 else if( strmatch(next, "exp" ) ) d= exp(d); | 247 else if( strmatch(next, "acos" ) ) d->a.func0 = acos; |
| 177 else if( strmatch(next, "log" ) ) d= log(d); | 248 else if( strmatch(next, "exp" ) ) d->a.func0 = exp; |
| 178 else if( strmatch(next, "squish") ) d= 1/(1+exp(4*d)); | 249 else if( strmatch(next, "log" ) ) d->a.func0 = log; |
| 179 else if( strmatch(next, "gauss" ) ) d= exp(-d*d/2)/sqrt(2*M_PI); | 250 else if( strmatch(next, "abs" ) ) d->a.func0 = fabs; |
| 180 else if( strmatch(next, "abs" ) ) d= fabs(d); | 251 else if( strmatch(next, "squish") ) d->type = e_squish; |
| 181 else if( strmatch(next, "mod" ) ) d-= floor(d/d2)*d2; | 252 else if( strmatch(next, "gauss" ) ) d->type = e_gauss; |
| 182 else if( strmatch(next, "max" ) ) d= d > d2 ? d : d2; | 253 else if( strmatch(next, "mod" ) ) d->type = e_mod; |
| 183 else if( strmatch(next, "min" ) ) d= d < d2 ? d : d2; | 254 else if( strmatch(next, "max" ) ) d->type = e_max; |
| 184 else if( strmatch(next, "gt" ) ) d= d > d2 ? 1.0 : 0.0; | 255 else if( strmatch(next, "min" ) ) d->type = e_min; |
| 185 else if( strmatch(next, "gte" ) ) d= d >= d2 ? 1.0 : 0.0; | 256 else if( strmatch(next, "eq" ) ) d->type = e_eq; |
| 186 else if( strmatch(next, "lt" ) ) d= d > d2 ? 0.0 : 1.0; | 257 else if( strmatch(next, "gt" ) ) d->type = e_gt; |
| 187 else if( strmatch(next, "lte" ) ) d= d >= d2 ? 0.0 : 1.0; | 258 else if( strmatch(next, "gte" ) ) d->type = e_gte; |
| 188 else if( strmatch(next, "eq" ) ) d= d == d2 ? 1.0 : 0.0; | 259 else if( strmatch(next, "lt" ) ) { AVEvalExpr * tmp = d->param[1]; d->param[1] = d->param[0]; d->param[0] = tmp; d->type = e_gte; } |
| 189 else if( strmatch(next, "(" ) ) d= d; | 260 else if( strmatch(next, "lte" ) ) { AVEvalExpr * tmp = d->param[1]; d->param[1] = d->param[0]; d->param[0] = tmp; d->type = e_gt; } |
| 190 // else if( strmatch(next, "l1" ) ) d= 1 + d2*(d - 1); | 261 else { |
| 191 // else if( strmatch(next, "sq01" ) ) d= (d >= 0.0 && d <=1.0) ? 1.0 : 0.0; | |
| 192 else{ | |
| 193 for(i=0; p->func1_name && p->func1_name[i]; i++){ | 262 for(i=0; p->func1_name && p->func1_name[i]; i++){ |
| 194 if(strmatch(next, p->func1_name[i])){ | 263 if(strmatch(next, p->func1_name[i])){ |
| 195 return p->func1[i](p->opaque, d); | 264 d->a.func1 = p->func1[i]; |
| 265 d->type = e_func1; | |
| 266 return d; | |
| 196 } | 267 } |
| 197 } | 268 } |
| 198 | 269 |
| 199 for(i=0; p->func2_name && p->func2_name[i]; i++){ | 270 for(i=0; p->func2_name && p->func2_name[i]; i++){ |
| 200 if(strmatch(next, p->func2_name[i])){ | 271 if(strmatch(next, p->func2_name[i])){ |
| 201 return p->func2[i](p->opaque, d, d2); | 272 d->a.func2 = p->func2[i]; |
| 273 d->type = e_func2; | |
| 274 return d; | |
| 202 } | 275 } |
| 203 } | 276 } |
| 204 | 277 |
| 205 *p->error = "unknown function"; | 278 *p->error = "unknown function"; |
| 206 return NAN; | 279 ff_eval_free(d); |
| 280 return NULL; | |
| 207 } | 281 } |
| 208 | 282 |
| 209 return d; | 283 return d; |
| 210 } | 284 } |
| 211 | 285 |
| 212 static double evalPow(Parser *p, int *sign){ | 286 static AVEvalExpr * parse_pow(Parser *p, int *sign){ |
| 213 *sign= (*p->s == '+') - (*p->s == '-'); | 287 *sign= (*p->s == '+') - (*p->s == '-'); |
| 214 p->s += *sign&1; | 288 p->s += *sign&1; |
| 215 return evalPrimary(p); | 289 return parse_primary(p); |
| 216 } | 290 } |
| 217 | 291 |
| 218 static double evalFactor(Parser *p){ | 292 static AVEvalExpr * parse_factor(Parser *p){ |
| 219 int sign, sign2; | 293 int sign, sign2; |
| 220 double ret, e; | 294 AVEvalExpr * e = parse_pow(p, &sign); |
| 221 ret= evalPow(p, &sign); | |
| 222 while(p->s[0]=='^'){ | 295 while(p->s[0]=='^'){ |
| 296 AVEvalExpr * tmp = av_mallocz(sizeof(AVEvalExpr)); | |
| 297 | |
| 223 p->s++; | 298 p->s++; |
| 224 e= evalPow(p, &sign2); | 299 |
| 225 ret= pow(ret, (sign2|1) * e); | 300 tmp->type = e_pow; |
| 226 } | 301 tmp->value = 1.; |
| 227 return (sign|1) * ret; | 302 tmp->param[0] = e; |
| 228 } | 303 tmp->param[1] = parse_pow(p, &sign2); |
| 229 | 304 if (tmp->param[1]) tmp->param[1]->value *= (sign2|1); |
| 230 static double evalTerm(Parser *p){ | 305 e = tmp; |
| 231 double ret= evalFactor(p); | 306 } |
| 307 if (e) e->value *= (sign|1); | |
| 308 return e; | |
| 309 } | |
| 310 | |
| 311 static AVEvalExpr * parse_term(Parser *p){ | |
| 312 AVEvalExpr * e = parse_factor(p); | |
| 232 while(p->s[0]=='*' || p->s[0]=='/'){ | 313 while(p->s[0]=='*' || p->s[0]=='/'){ |
| 233 if(*p->s++ == '*') ret*= evalFactor(p); | 314 AVEvalExpr * tmp = av_mallocz(sizeof(AVEvalExpr)); |
| 234 else ret/= evalFactor(p); | 315 if(*p->s++ == '*') tmp->type = e_mul; |
| 235 } | 316 else tmp->type = e_div; |
| 236 return ret; | 317 tmp->value = 1.; |
| 237 } | 318 tmp->param[0] = e; |
| 238 | 319 tmp->param[1] = parse_factor(p); |
| 239 static double evalExpression(Parser *p){ | 320 e = tmp; |
| 240 double ret= 0; | 321 } |
| 322 return e; | |
| 323 } | |
| 324 | |
| 325 static AVEvalExpr * parse_expr(Parser *p) { | |
| 326 AVEvalExpr * e; | |
| 241 | 327 |
| 242 if(p->stack_index <= 0) //protect against stack overflows | 328 if(p->stack_index <= 0) //protect against stack overflows |
| 243 return NAN; | 329 return NULL; |
| 244 p->stack_index--; | 330 p->stack_index--; |
| 245 | 331 |
| 246 do{ | 332 e = parse_term(p); |
| 247 ret += evalTerm(p); | 333 |
| 248 }while(*p->s == '+' || *p->s == '-'); | 334 while(*p->s == '+' || *p->s == '-') { |
| 335 AVEvalExpr * tmp = av_mallocz(sizeof(AVEvalExpr)); | |
| 336 tmp->type = e_add; | |
| 337 tmp->value = 1.; | |
| 338 tmp->param[0] = e; | |
| 339 tmp->param[1] = parse_term(p); | |
| 340 e = tmp; | |
| 341 }; | |
| 249 | 342 |
| 250 p->stack_index++; | 343 p->stack_index++; |
| 251 | 344 |
| 252 return ret; | 345 return e; |
| 253 } | 346 } |
| 254 | 347 |
| 255 double ff_eval2(char *s, double *const_value, const char **const_name, | 348 static int verify_expr(AVEvalExpr * e) { |
| 349 if (!e) return 0; | |
| 350 switch (e->type) { | |
| 351 case e_value: | |
| 352 case e_const: return 1; | |
| 353 case e_func0: | |
| 354 case e_func1: | |
| 355 case e_squish: | |
| 356 case e_gauss: return verify_expr(e->param[0]); | |
| 357 default: return verify_expr(e->param[0]) && verify_expr(e->param[1]); | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 AVEvalExpr * ff_parse(char *s, const char **const_name, | |
| 256 double (**func1)(void *, double), const char **func1_name, | 362 double (**func1)(void *, double), const char **func1_name, |
| 257 double (**func2)(void *, double, double), char **func2_name, | 363 double (**func2)(void *, double, double), char **func2_name, |
| 258 void *opaque, char **error){ | 364 char **error){ |
| 259 Parser p; | 365 Parser p; |
| 366 AVEvalExpr * e; | |
| 260 | 367 |
| 261 p.stack_index=100; | 368 p.stack_index=100; |
| 262 p.s= s; | 369 p.s= s; |
| 263 p.const_value= const_value; | |
| 264 p.const_name = const_name; | 370 p.const_name = const_name; |
| 265 p.func1 = func1; | 371 p.func1 = func1; |
| 266 p.func1_name = func1_name; | 372 p.func1_name = func1_name; |
| 267 p.func2 = func2; | 373 p.func2 = func2; |
| 268 p.func2_name = func2_name; | 374 p.func2_name = func2_name; |
| 375 p.error= error; | |
| 376 | |
| 377 e = parse_expr(&p); | |
| 378 if (!verify_expr(e)) { | |
| 379 ff_eval_free(e); | |
| 380 return NULL; | |
| 381 } | |
| 382 return e; | |
| 383 } | |
| 384 | |
| 385 double ff_parse_eval(AVEvalExpr * e, double *const_value, void *opaque) { | |
| 386 Parser p; | |
| 387 | |
| 388 p.const_value= const_value; | |
| 269 p.opaque = opaque; | 389 p.opaque = opaque; |
| 270 p.error= error; | 390 return eval_expr(&p, e); |
| 271 | 391 } |
| 272 return evalExpression(&p); | 392 |
| 393 double ff_eval2(char *s, double *const_value, const char **const_name, | |
| 394 double (**func1)(void *, double), const char **func1_name, | |
| 395 double (**func2)(void *, double, double), char **func2_name, | |
| 396 void *opaque, char **error){ | |
| 397 AVEvalExpr * e = ff_parse(s, const_name, func1, func1_name, func2, func2_name, error); | |
| 398 double d; | |
| 399 if (!e) return NAN; | |
| 400 d = ff_parse_eval(e, const_value, opaque); | |
| 401 ff_eval_free(e); | |
| 402 return d; | |
| 273 } | 403 } |
| 274 | 404 |
| 275 #if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) | 405 #if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) |
| 276 attribute_deprecated double ff_eval(char *s, double *const_value, const char **const_name, | 406 attribute_deprecated double ff_eval(char *s, double *const_value, const char **const_name, |
| 277 double (**func1)(void *, double), const char **func1_name, | 407 double (**func1)(void *, double), const char **func1_name, |
