/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: ExprEval.java * * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. * * Electric(tm) 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 3 of the License, or * (at your option) any later version. * * Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.simulation.interval; import com.sun.electric.util.math.MutableInterval; import java.util.LinkedList; /** * This class contains a set of equation. They can be evaluated in different * ways - as point value, as interval, gradients will be added also. * If-then-else expression can be used to represent piecewise smooth functions, * which are defined in different regions by different analitical expressions. */ public class ExprEval { private LinkedList<Expr> el = new LinkedList<Expr>(); private boolean printDetailed = false; boolean hasBoth = false; public void printAll( boolean detailed ) { printDetailed = detailed; for(Expr e : el) { //if (bp->_opref <= 0 || !detailed && (bp->_opref <= 1 || bp->isConst())) continue; System.out.println(/*"[" + e._opref + "] " +*/ (e.name != null ? e.name : "_") + "." + e.id + " = " + e); } printDetailed = false; } public void calcAll() { for (Expr e : el) { //if (bp->_opref == 0) continue; e.calcVal(); if (false) { System.out.println(/*"[" + e._opref + "] " +*/ (e.name != null ? e.name : "_") + "." + e.id + " = " + e + " = " + e.valString()); } } } public boolean calcIntervalAll() { hasBoth = false; //setFpu( true ); for (Expr e : el) { //if (bp->_opref == 0) continue; e.calcInterval(); if (false) { System.out.println(/*"[" + e._opref + "] " +*/ (e.name != null ? e.name : "_") + "." + e.id + " = " + e + " = " + e.intervalString()); } } //setFpu( false ); return hasBoth; } abstract class Expr { private String name; private int id; Expr() { id = el.size();; el.add(this); } String name() { return name; }; public void setName(String name) { this.name = name; } public String toString() { return toString(0); } abstract String toString(int prio); String refString(int prio) { return (name != null ? name : "_") + "." + id; } abstract void calcVal(); abstract void calcInterval(); abstract String valString(); abstract String intervalString(); } public abstract class DoubleExpr extends Expr { private double v; MutableInterval iv; DoubleExpr() { v = 0.0; iv = new MutableInterval(); } public double v() { return v; } public void setV(double v) { this.v = v; } final MutableInterval iv() { return iv; } public double inf() { return iv.inf(); } public double sup() { return iv.sup(); } public DoubleExpr add(DoubleExpr augend ) { return new DoubleBinopExpr(this, DoubleBinopExpr.BOP_PLUS, augend); } public DoubleExpr subtract(DoubleExpr subtrahend ) { return new DoubleBinopExpr(this, DoubleBinopExpr.BOP_MINUS, subtrahend); } public DoubleExpr multiply(DoubleExpr multiplicand ) { return new DoubleBinopExpr(this, DoubleBinopExpr.BOP_TIMES, multiplicand); } public DoubleExpr divide(DoubleExpr divisor ) { return new DoubleBinopExpr(this, DoubleBinopExpr.BOP_SLASH, divisor); } public DoubleExpr negate() { return new DoubleUnopExpr(DoubleUnopExpr.UOP_NEG, this); } public DoubleExpr exp() { return new DoubleFunExpr(DoubleFunExpr.FUN1_EXP, this); } public DoubleExpr log() { return new DoubleFunExpr(DoubleFunExpr.FUN1_LOG, this); } public DoubleExpr abs() { return new DoubleFunExpr(DoubleFunExpr.FUN1_ABS, this); } public BooleanExpr lt(DoubleExpr e) { return new BooleanCompExpr(this, BooleanCompExpr.BOP_LT, e); } public BooleanExpr gt(DoubleExpr e) { return new BooleanCompExpr(this, BooleanCompExpr.BOP_GT, e); } public BooleanExpr le(DoubleExpr e) { return new BooleanCompExpr(this, BooleanCompExpr.BOP_LE, e); } public BooleanExpr ge(DoubleExpr e) { return new BooleanCompExpr(this, BooleanCompExpr.BOP_GE, e); } String valString() { return "" + v(); // ??? } String intervalString() { return iv().toString(); } } public class DoubleConstExpr extends DoubleExpr { DoubleConstExpr(double v) { setV(v); this.iv.assign(v); } public void setInterval(double lo, double hi) { this.iv.assign(lo, hi); } String toString(int prio) { return "" + v(); // ??? } void calcVal() {} void calcInterval() {} } class DoubleBinopExpr extends DoubleExpr { static final int BOP_PLUS = 1; static final int BOP_MINUS = 2; static final int BOP_TIMES = 3; static final int BOP_SLASH = 4; private DoubleExpr e1; private int bop; private DoubleExpr e2; DoubleBinopExpr(DoubleExpr e1, int bop, DoubleExpr e2) { this.e1 = e1; this.bop = bop; this.e2 = e2; calcVal(); } String toString(int prio) { String s = null; int pr = 0; switch( bop ) { case BOP_PLUS: s = " + "; pr = 3; break; case BOP_MINUS: s = " - "; pr = 3; break; case BOP_TIMES: s = " * "; pr = 4; break; case BOP_SLASH: s = " / "; pr = 4; break; } s = e1.refString(pr) + s + e2.refString(pr+1); if (prio > pr) s = "( " + s + " )"; return s; } void calcVal() { switch( bop ) { case BOP_PLUS: setV( e1.v() + e2.v() ); break; case BOP_MINUS: setV( e1.v() - e2.v() ); break; case BOP_TIMES: setV( e1.v() * e2.v() ); break; case BOP_SLASH: setV( e1.v() / e2.v() ); break; } } void calcInterval() { switch (bop) { case BOP_PLUS: this.iv.assign(e1.iv()).add( e2.iv() ); break; case BOP_MINUS: this.iv.assign(e1.iv()).sub( e2.iv() ); break; case BOP_TIMES: this.iv.assign(e1.iv()).mul( e2.iv() ); break; case BOP_SLASH: this.iv.assign(e1.iv()).div( e2.iv() ); break; } } } class DoubleUnopExpr extends DoubleExpr { static final int UOP_NEG = 1; private int uop; private DoubleExpr e1; DoubleUnopExpr(int uop, DoubleExpr e1) { this.uop = uop; this.e1 = e1; calcVal(); } String toString(int prio) { String s = null; switch( uop ) { case UOP_NEG: s = "- "; break; } s = s + e1.refString(4); if (prio > 3) s = "( " + s + " )"; return s; } void calcVal() { switch( uop ) { case UOP_NEG: setV( - e1.v() ); break; } } void calcInterval() { switch (uop) { case UOP_NEG: this.iv.assign(e1.iv()).negate(); break; } } } class DoubleFunExpr extends DoubleExpr { static final int FUN1_EXP = 1; static final int FUN1_LOG = 2; static final int FUN1_ABS = 3; private int fun; private DoubleExpr e1; DoubleFunExpr(int fun, DoubleExpr e1) { this.fun = fun; this.e1 = e1; calcVal(); } String toString(int prio) { String s = null; switch( fun ) { case FUN1_EXP: s = "exp( "; break; case FUN1_LOG: s = "log( "; break; case FUN1_ABS: s = "abs( "; break; } s = s + e1.refString(0) + " )"; return s; } void calcVal() { switch( fun ) { case FUN1_EXP: setV( Math.exp( e1.v() ) ); break; case FUN1_LOG: setV( Math.log( e1.v() ) ); break; case FUN1_ABS: setV( Math.abs( e1.v() ) ); break; } } void calcInterval() { MutableInterval a = e1.iv(); switch (fun) { case FUN1_EXP: this.iv.assign(a).exp(); break; case FUN1_LOG: this.iv.assign(a).log(); break; case FUN1_ABS: this.iv.assign(a).abs(); break; } } } class DoubleIteExpr extends DoubleExpr { private BooleanExpr cond; private DoubleExpr th; private DoubleExpr el; DoubleIteExpr(BooleanExpr cond, DoubleExpr th, DoubleExpr el) { this.cond = cond; this.th = th; this.el = el; calcVal(); } String toString(int prio) { String s = null; s = cond.refString(1) + " ? " + th.refString(1) + " : " + el.refString(0); if (prio > 0) s = "( " + s + " )"; return s; } void calcVal() { setV (cond.v() ? th.v() : el.v() ); } void calcInterval() { MutableInterval t = th.iv(); MutableInterval e = el.iv(); if (cond.iboth()) { this.iv.assign(t).interval_hull(e); hasBoth = true; } else if (cond.v()) this.iv.assign(t); else this.iv.assign(e); } } public abstract class BooleanExpr extends Expr { private boolean v; private boolean iboth; final boolean v() { return v; } final void setV(boolean v) { this.v = v; } final boolean iboth() { return iboth; } final void setIBoth(boolean v) { this.iboth = v; } public DoubleExpr ite(DoubleExpr th, DoubleExpr el) { return new DoubleIteExpr(this, th, el); } BooleanExpr or(BooleanExpr be) { return new BooleanBinopExpr(this, BooleanBinopExpr.BOP_OR, be); } BooleanBinopExpr and(BooleanExpr be) { return new BooleanBinopExpr(this, BooleanBinopExpr.BOP_AND, be); } String valString() { return "" + v(); // ??? } String intervalString() { return (iboth() ? "both" : valString()); } } class BooleanBinopExpr extends BooleanExpr { static final int BOP_AND = 1; static final int BOP_OR = 2; private BooleanExpr e1; private int bop; private BooleanExpr e2; BooleanBinopExpr(BooleanExpr e1, int bop, BooleanExpr e2) { this.e1 = e1; this.bop = bop; this.e2 = e2; calcVal(); } String toString(int prio) { String s = null; switch( bop ) { case BOP_AND: s = " && "; break; case BOP_OR : s = " || "; break; } s = e1.refString(2) + s + e2.refString(2); if (prio > 1) s = "( " + s + ") "; return s; } void calcVal() { switch( bop ) { case BOP_AND: setV( e1.v() && e2.v() ); break; case BOP_OR: setV( e1.v() || e2.v() ); break; } } void calcInterval() { switch( bop ) { case BOP_AND: if (e1.iboth() && e2.iboth() || e1.iboth() && e2.v() || e2.iboth() && e1.v()) { setIBoth( true ); } else { setIBoth( false ); setV( e1.v() && e2.v() ); } break; case BOP_OR: if (e1.iboth() && e2.iboth() || e1.iboth() && !e2.v() || e2.iboth() && !e1.v()) { setIBoth( true ); } else { setIBoth( false ); setV( e1.v() || e2.v() ); } break; } } } class BooleanCompExpr extends BooleanExpr { static final int BOP_LT = 1; static final int BOP_GT = 2; static final int BOP_LE = 3; static final int BOP_GE = 4; private DoubleExpr e1; private int bop; private DoubleExpr e2; BooleanCompExpr(DoubleExpr e1, int bop, DoubleExpr e2) { this.e1 = e1; this.bop = bop; this.e2 = e2; calcVal(); } String toString(int prio) { String s = null; switch( bop ) { case BOP_LT: s = " < "; break; case BOP_GT: s = " > "; break; case BOP_LE: s = " <= "; break; case BOP_GE: s = " >= "; break; } s = e1.refString(3) + s + e2.refString(3); if (prio > 2) s = "( " + s + ") "; return s; } void calcVal() { switch( bop ) { case BOP_LT: setV( e1.v() < e2.v() ); break; case BOP_GT: setV( e1.v() > e2.v() ); break; case BOP_LE: setV( e1.v() <= e2.v() ); break; case BOP_GE: setV( e1.v() >= e2.v() ); break; } } void calcInterval() { boolean c = false; /* certainly */ boolean p = false; /* possibly */ MutableInterval l = e1.iv(); MutableInterval r = e2.iv(); switch( bop ) { case BOP_LT: c = l.clt(r); p = l.plt(r); break; case BOP_GT: c = l.cgt(r); p = l.pgt(r); break; case BOP_LE: c = l.cle(r); p = l.ple(r); break; case BOP_GE: c = l.cge(r); p = l.pge(r); break; } setIBoth( c != p ); setV( c ); } } /* Static methods, creating expressions */ public DoubleConstExpr newConst() { return new DoubleConstExpr(0.0); } public DoubleConstExpr newConst( double v ) { return new DoubleConstExpr(v); } }