001/* UnitExpr that will contain UnitTerms.
002
003 Copyright (c) 2003-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_3
025 COPYRIGHTENDKEY
026 */
027package ptolemy.moml.unit;
028
029import java.util.Iterator;
030import java.util.Vector;
031
032import ptolemy.actor.IOPort;
033
034///////////////////////////////////////////////////////////////////
035//// UnitExpr
036
037/** A UnitExpr contains UnitTerms.
038 @author Rowland R Johnson
039 @version $Id$
040 @since Ptolemy II 8.0
041 @Pt.ProposedRating Red (rowland)
042 @Pt.AcceptedRating Red (rowland)
043 */
044public class UnitExpr implements UnitPresentation {
045    /** Construct an empty (i.e. no UnitTerms) UnitExpr.
046     *
047     */
048    public UnitExpr() {
049    }
050
051    /** Construct a UnitTerm from an IOPort.
052     * The constructed UnitExpr will have one UnitTerm and it will be
053     * a variable with the name being that of the port.
054     * @param ioPort The IOPort.
055     */
056    public UnitExpr(IOPort ioPort) {
057        UnitTerm uTerm = new UnitTerm();
058        uTerm.setVariable(
059                ioPort.getContainer().getName() + "." + ioPort.getName());
060        _uTerms.add(uTerm);
061    }
062
063    ///////////////////////////////////////////////////////////////////
064    ////                         public methods                    ////
065
066    /** Add a UnitTerm to the expression.
067     * @param uTerm The UnitTerm.
068     */
069    public void addUnitTerm(UnitTerm uTerm) {
070        _uTerms.add(uTerm);
071    }
072
073    /** Create a copy of this UnitExpr.
074     * @return The new UnitExpr.
075     */
076    public UnitExpr copy() {
077        UnitExpr retv = new UnitExpr();
078        Vector newUTerms = new Vector();
079
080        for (int i = 0; i < _uTerms.size(); i++) {
081            UnitTerm term = (UnitTerm) _uTerms.elementAt(i);
082            newUTerms.add(term.copy());
083        }
084
085        retv._setUTerms(newUTerms);
086        return retv;
087    }
088
089    /** The expression of the UnitExpr that is commonly used by humans.
090     * @see ptolemy.moml.unit.UnitPresentation#descriptiveForm()
091     */
092    @Override
093    public String descriptiveForm() {
094        Iterator iter = _uTerms.iterator();
095        StringBuffer retv = new StringBuffer();
096        if (iter.hasNext()) {
097            String descriptiveForm = ((UnitTerm) iter.next()).descriptiveForm();
098            // Coverity: UnitTerm.descriptiveForm() could return null.
099            if (descriptiveForm != null) {
100                retv.append(descriptiveForm);
101            }
102        }
103
104        while (iter.hasNext()) {
105            retv.append(" " + ((UnitTerm) iter.next()).descriptiveForm());
106        }
107
108        return retv.toString();
109    }
110
111    /** If this UnitExpr has one term and it is a Unit then return that Unit.
112     * @return The Unit if there is a single UnitTerm, and it is a Unit, null
113     * otherwise.
114     */
115    public Unit getSingleUnit() {
116        if (_uTerms.size() == 1 && ((UnitTerm) _uTerms.elementAt(0)).isUnit()) {
117            return ((UnitTerm) _uTerms.elementAt(0)).getUnit();
118        }
119
120        return null;
121    }
122
123    /** Get the UnitTerms in this UnitExpr.
124     * @return The UnitTerms.
125     */
126    public Vector getUTerms() {
127        return _uTerms;
128    }
129
130    /** Create a new UnitExpr that is the inverse of this UnitExpr.
131     * @return The inverse of this UnitExpr.
132     */
133    public UnitExpr invert() {
134        UnitExpr retv = new UnitExpr();
135        Vector myUTerms = new Vector();
136
137        for (int i = 0; i < _uTerms.size(); i++) {
138            myUTerms.add(((UnitTerm) _uTerms.elementAt(i)).invert());
139        }
140
141        retv._setUTerms(myUTerms);
142        return retv;
143    }
144
145    /**
146     * Reduce a UnitExpr to produce a UnitExpr that has at most one Unit. Any
147     * embedded UnitExpr is first transformed so that all embedded UnitExprs
148     * are replaced with Units. This intermediate result is a mixture of Units
149     * and variables. The Units are then replaced with their product. The
150     * result is a single Unit and all of the original variables.
151     * @return The reduced UnitExpr.
152     */
153    public UnitExpr reduce() {
154        _flatten();
155
156        Unit reductionUnit = UnitLibrary.Identity.copy();
157        Vector newUTerms = new Vector();
158
159        for (int i = 0; i < _uTerms.size(); i++) {
160            UnitTerm unitTerm = (UnitTerm) _uTerms.elementAt(i);
161
162            if (unitTerm.isUnit()) {
163                reductionUnit = reductionUnit.multiplyBy(
164                        unitTerm.getUnit().pow(unitTerm.getExponent()));
165            } else {
166                newUTerms.add(unitTerm);
167            }
168        }
169
170        newUTerms.add(new UnitTerm(reductionUnit));
171
172        UnitExpr retv = new UnitExpr();
173        retv._setUTerms(newUTerms);
174        return retv;
175    }
176
177    @Override
178    public String toString() {
179        StringBuffer retv = new StringBuffer("UnitExpr:[");
180
181        if (_uTerms.size() > 0) {
182            retv.append(((UnitTerm) _uTerms.elementAt(0)).toString());
183
184            for (int i = 1; i < _uTerms.size(); i++) {
185                retv.append(" " + ((UnitTerm) _uTerms.elementAt(i)).toString());
186            }
187        }
188
189        retv.append("]");
190        return retv.toString();
191    }
192
193    ///////////////////////////////////////////////////////////////////
194    ////                         protected methods                 ////
195    protected void _setUTerms(Vector uTerms) {
196        _uTerms = uTerms;
197    }
198
199    ///////////////////////////////////////////////////////////////////
200    ////                         private methods                   ////
201    private void _flatten() {
202        if (_isFlat) {
203            return;
204        }
205
206        Vector newUTerms = new Vector();
207
208        for (int i = 0; i < _uTerms.size(); i++) {
209            UnitTerm unitTerm = (UnitTerm) _uTerms.elementAt(i);
210
211            if (unitTerm.isUnitExpr()) {
212                UnitExpr uExpr = unitTerm.getUnitExpr();
213
214                if (uExpr != null) {
215                    uExpr._flatten();
216                    newUTerms.addAll(uExpr.getUTerms());
217                }
218            } else {
219                newUTerms.add(unitTerm);
220            }
221        }
222
223        _isFlat = true;
224        _setUTerms(newUTerms);
225    }
226
227    ///////////////////////////////////////////////////////////////////
228    ////                         private variables                 ////
229    boolean _isFlat = false;
230
231    Vector _uTerms = new Vector();
232}