]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling/src/org/simantics/modeling/InvertBasicExpressionVisitor.java
Fixed InvertBasicExpressionVisitor.invert to keep inverted value type
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / InvertBasicExpressionVisitor.java
1 package org.simantics.modeling;
2
3 import java.util.Stack;
4
5 import org.simantics.basicexpression.Expressions;
6 import org.simantics.basicexpression.analysis.DepthFirstAdapter;
7 import org.simantics.basicexpression.node.AConstantValue;
8 import org.simantics.basicexpression.node.ADivMultiplicative;
9 import org.simantics.basicexpression.node.AMultMultiplicative;
10 import org.simantics.basicexpression.node.APlusExpression;
11 import org.simantics.basicexpression.node.AVariablePrimary;
12 import org.simantics.db.ReadGraph;
13 import org.simantics.db.Resource;
14 import org.simantics.db.WriteGraph;
15 import org.simantics.db.exception.DatabaseException;
16 import org.simantics.db.layer0.variable.Variable;
17 import org.simantics.scl.compiler.types.Type;
18 import org.simantics.structural.stubs.StructuralResource2;
19 import org.simantics.utils.datastructures.Pair;
20 import org.simantics.utils.datastructures.Triple;
21
22 public class InvertBasicExpressionVisitor extends DepthFirstAdapter {
23
24         Stack<Object> stack = new Stack<Object>();
25
26         public Object getResult() {
27                 if(stack.size() != 1) return null; 
28                 return stack.pop();
29         }
30
31         public void outAConstantValue(AConstantValue node) {
32                 stack.push(Double.valueOf(node.toString()));
33         }
34
35         @Override
36         public void outAVariablePrimary(AVariablePrimary node) {
37         String value = node.toString().trim();
38         stack.push(Triple.make(1.0, 0.0, value));
39         }
40         
41         @SuppressWarnings("unchecked")
42     public void outAPlusExpression(APlusExpression node) {
43                 
44                 final Object o1 = stack.pop();
45                 final Object o2 = stack.pop();
46                 
47                 if(o1 instanceof Double && o2 instanceof Triple) {
48                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;
49                         stack.push(Triple.make(p.first, p.second + (Double)o1, p.third));
50                 } else if (o2 instanceof Double && o1 instanceof Triple) {
51                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;
52                         stack.push(Triple.make(p.first, p.second + (Double)o2, p.third));
53                 } else if (o2 instanceof Double && o1 instanceof Double) {
54                         stack.push((Double)o1 + (Double)o2);
55                 } else {
56                         stack.push(Double.NaN);
57                 }
58                 
59         }
60
61         @SuppressWarnings("unchecked")
62     public void outAMinusExpression(APlusExpression node) {
63                 
64                 final Object o1 = stack.pop();
65                 final Object o2 = stack.pop();
66                 
67                 if(o1 instanceof Double && o2 instanceof Triple) {
68                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;
69                         stack.push(Triple.make(-p.first, (Double)o1 - p.second, p.third ));
70                 } else if (o2 instanceof Double && o1 instanceof Triple) {
71                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;
72                         stack.push(Triple.make(p.first, p.second - (Double)o2, p.third));
73                 } else if (o2 instanceof Double && o1 instanceof Double) {
74                         stack.push((Double)o1 - (Double)o2);
75                 } else {
76                         stack.push(Double.NaN);
77                 }
78                 
79         }
80
81         @SuppressWarnings("unchecked")
82     public void outAMultMultiplicative(AMultMultiplicative node) {
83                 
84                 final Object o1 = stack.pop();
85                 final Object o2 = stack.pop();
86                 
87                 if(o1 instanceof Double && o2 instanceof Triple) {
88                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;
89                         stack.push(Triple.make(p.first * (Double)o1, p.second * (Double)o1, p.third));
90                 } else if (o2 instanceof Double && o1 instanceof Triple) {
91                         Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;
92                         stack.push(Triple.make(p.first * (Double)o2, p.second * (Double)o2, p.third));
93                 } else if (o2 instanceof Double && o1 instanceof Double) {
94                         stack.push((Double)o1 * (Double)o2);
95                 } else {
96                         stack.push(Double.NaN);
97                 }
98                 
99         }
100
101         @SuppressWarnings("unchecked")
102     public void outADivMultiplicative(ADivMultiplicative node) {
103                 
104                 final Object o1 = stack.pop();
105                 final Object o2 = stack.pop();
106                 
107                 if(o1 instanceof Double && o2 instanceof Triple) {
108                         stack.push(Double.NaN);
109                 } else if (o2 instanceof Double && o1 instanceof Triple) {
110                         Triple<Double, Double, String> p = (Triple<Double,Double, String>)o1;
111                         stack.push(Triple.make(p.first / (Double)o2, p.second / (Double)o2, p.third));
112                 } else if (o2 instanceof Double && o1 instanceof Double) {
113                         stack.push((Double)o1 / (Double)o2);
114                 } else {
115                         stack.push(Double.NaN);
116                 }
117                 
118         }
119
120         private static final String MAGIC = "_111_";
121         
122         private static String replaced(String expression) {
123             return expression.replaceAll("\\.([A-Za-z])", MAGIC + "$1");
124         }
125         
126     public static void invert(WriteGraph graph, Variable base, String expression, Object value) throws DatabaseException {
127         InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();
128         Expressions.evaluate(replaced(expression), visitor);
129         Object result = visitor.getResult();
130         if(result == null) return;
131         if(result instanceof Triple) {
132             @SuppressWarnings("unchecked")
133             Triple<Double, Double, String> data = (Triple<Double, Double, String>)result;
134             String key = data.third.replace(MAGIC, ".");
135             String path = getVariablePath(graph, base, key);
136             Variable targetVariable = base.browse(graph, path);
137             if(value instanceof Number) {
138                 if(Math.abs(data.first) > 1e-9) {
139                     double inverted = (double) (((Number)value).doubleValue() - data.second) / data.first;
140                     Object invertedValue = numericValueInType(inverted, value.getClass());
141                     targetVariable.setValue(graph, invertedValue);
142                 }
143             } else if (value instanceof Boolean) {
144                 // TODO: support 'not'
145                 targetVariable.setValue(graph, value);
146             }
147         }
148         
149     }
150
151     private static Object numericValueInType(double value, Class<?> type) {
152         if (type == Integer.class) {
153             return (int) value;
154         } else if (type == Long.class) {
155             return (long) value;
156         } else if (type == Byte.class) {
157             return (byte) value;
158         } else if (type == Float.class) {
159             return (float) value;
160         }
161         return value;
162     }
163
164     private static String getVariablePath(ReadGraph graph, Variable base, String key) throws DatabaseException {
165         StructuralResource2 STR = StructuralResource2.getInstance(graph);
166         Resource type = base.getPossibleType(graph);
167         if(type == null)
168             return null;
169         boolean procedural = graph.isInstanceOf(type, STR.ProceduralComponentType);
170         Pair<String, Type> pair;
171         if(procedural)
172             pair = graph.sync(new ProceduralSubstructureMapRequest(base)).get(key);
173         else
174             pair = ComponentTypeSubstructure.forType(graph, type).possibleTypedRVI(key);
175         if(pair == null)
176             return null;
177         return pair.first;
178     }
179
180     /**
181      * @param graph
182      * @param base
183      * @param expression the expression to check for invertibility. An empty is expression is not invertible.
184      * @return
185      * @throws DatabaseException
186      * @throws NullPointerException for null expression
187      */
188     public static boolean isInvertible(ReadGraph graph, Variable base, String expression) throws DatabaseException {
189         if (expression == null)
190             throw new NullPointerException("null expression for variable " + base.getURI(graph));
191         if (expression.isEmpty())
192             return false;
193
194         Resource type = base.getPossibleType(graph);
195         if(type == null) return false;
196
197         InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();
198         Expressions.evaluate(replaced(expression), visitor);
199         Object pair = visitor.getResult();
200         if(pair == null) return false;
201         if(pair instanceof Triple) {
202             @SuppressWarnings("unchecked")
203             Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;
204             String key = data.third.replace(MAGIC,".");
205             return getVariablePath(graph, base, key) != null;
206         }
207         return false;
208         
209     }
210
211     public static Variable possibleInvertibleExpressionReferencedProperty(ReadGraph graph, Variable base, String expression) throws DatabaseException {
212         if (base == null || expression == null || expression.isEmpty())
213             return null;
214         InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();
215         //System.out.println("invert : " + expression + " -> " + replaced(expression) + " for " + base.getURI(graph));
216         Expressions.evaluate(replaced(expression), visitor);
217         Object pair = visitor.getResult();
218         if(pair == null)
219             return null;
220         if(pair instanceof Triple) {
221             @SuppressWarnings("unchecked")
222             Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;
223             String key = data.third.replace(MAGIC,".");
224             String path = getVariablePath(graph, base, key);
225             if (path == null)
226                 return null;
227             Variable targetVariable = base.browsePossible(graph, path);
228             return targetVariable;
229         }
230         return null;
231     }
232
233 }