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