PageRenderTime 61ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 1ms

/branches/adinetz02/efi/efi/EfiLocalTransforms.cs

#
C# | 308 lines | 208 code | 13 blank | 87 comment | 72 complexity | 553964bc383e728786388b662d3e82d9 MD5 | raw file
Possible License(s): AGPL-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Wintellect.PowerCollections;
  5. namespace CBucks.Efi {
  6. /// <summary>
  7. /// A local EFI transform delegate
  8. /// </summary>
  9. /// <param name="target"> The target of the transform </param>
  10. /// <param name="data"> Additional transform data </param>
  11. /// <returns> The new node which is the result of the transform and
  12. /// replaces <paramref name="target"/>, or null if no transform has
  13. /// been performed. </returns>
  14. /// <remarks> Actual replacement shall be done inside the delegate,
  15. /// while root replacement and iterator replacement is actually done
  16. /// outside this method. The graph is deduced as a property of target. </remarks>
  17. public delegate EfiNode LocalTransform(EfiNode target, object data);
  18. /// <summary>
  19. /// Contains local EFI transforms (i.e. transforms based in a single vertex)
  20. /// </summary>
  21. public static class EfiLocalTransforms {
  22. /// <summary>
  23. /// Replaces the constant at the target node. Does the actual replacement.
  24. /// </summary>
  25. /// <param name="target"> The target, at which to perform the replacement </param>
  26. /// <param name="data"> Ignored </param>
  27. /// <returns> The new node or none if no replacement have taken place </returns>
  28. public static EfiNode replaceConstant(EfiNode target, object data) {
  29. EfiFdag efi = target.efi;
  30. // check node type
  31. if(target.nodeType != EfiNodeType.Apply)
  32. return null;
  33. // check simplicity
  34. EfiNode applied = target.child(0);
  35. if(applied.nodeType != EfiNodeType.Function)
  36. return null;
  37. if(!applied.isSimpleFunc && !applied.isArray)
  38. return null;
  39. // check constantness
  40. int nchild = target.childCount;
  41. for(int i = 1; i < nchild; i++) {
  42. if(target.child(i).nodeType != EfiNodeType.Value)
  43. return null;
  44. }
  45. // evaluate the result
  46. object res;
  47. IPureFunction f = (IPureFunction)applied.element;
  48. int narg = nchild - 1;
  49. object[] args = new object[narg];
  50. for(int i = 1; i < nchild; i++)
  51. args[i - 1] = target.child(i).element;
  52. res = f.eval(args);
  53. // define node type
  54. EfiNodeType nt = PureFunc.isFunction(res) ? EfiNodeType.Function :
  55. EfiNodeType.Value;
  56. // create and replace
  57. efi.suspendLayout();
  58. EfiNode newNode = efi.createNode(nt, null, res);
  59. efi["unboundType", newNode] = PureFunc.isFunction(res) ?
  60. TypeOps.getFuncType((IPureFunction)res) : TypeOps.funcCreate(res.GetType(),
  61. typeof(Tuple00));
  62. efi["remBoundVars", newNode] = new List<object>();
  63. #if DEBUG
  64. efi["name", newNode] = null == res ? "null" : res.ToString();
  65. #endif
  66. efi.replaceVertex(target, newNode, true);
  67. efi.resumeLayout();
  68. return newNode;
  69. } // end of replaceConstant()
  70. /// <summary>
  71. /// Replaces the f(a, ..., a) => a at the target node. Does the actual replacement.
  72. /// </summary>
  73. /// <param name="target"> The target, at which to perform the replacement </param>
  74. /// <param name="data"> Ignored </param>
  75. /// <returns> The new node or none if no replacement have taken place </returns>
  76. public static EfiNode replaceIdempotent(EfiNode target, object data) {
  77. EfiFdag efi = target.efi;
  78. // check node type
  79. if(target.nodeType != EfiNodeType.Apply)
  80. return null;
  81. // check simplicity
  82. EfiNode applied = target.child(0);
  83. if(applied.nodeType != EfiNodeType.Function)
  84. return null;
  85. if(!applied.isIdempotentFunc)
  86. return null;
  87. int nchild = target.childCount;
  88. if(nchild <= 2)
  89. return null;
  90. // check that children are the same
  91. EfiNode arg = target.child(1);
  92. for(int i = 2; i < nchild; i++)
  93. if(arg != target.child(i))
  94. return null;
  95. // replace
  96. efi.suspendLayout();
  97. efi.replaceVertex(target, arg, true);
  98. efi.resumeLayout();
  99. return arg;
  100. }
  101. /// <summary>
  102. /// Removes the unnecessary unit elements from the node specified
  103. /// </summary>
  104. /// <param name="target"> The target node of the transformation </param>
  105. /// <param name="data"> Ignored </param>
  106. /// <returns> The new node or null if no transformations applied </returns>
  107. /// <remarks> Performs transformations such as a * 1 => a, 0 + a => a, etc.
  108. /// </remarks>
  109. public static EfiNode removeUnitElements(EfiNode target, object data) {
  110. EfiFdag efi = target.efi;
  111. if(target.nodeType != EfiNodeType.Apply)
  112. return null;
  113. EfiNode applied = target.child(0);
  114. if(!applied.hasFuncUnit)
  115. return null;
  116. int nchild = target.childCount;
  117. if(nchild != 3)
  118. return null;
  119. // get the unit element and sides
  120. UnitElementAttribute uea = applied.unitAttr;
  121. object unit = uea.unit;
  122. ExprSide side = uea.side;
  123. EfiNode newNode = null;
  124. if((side & ExprSide.Right) != ExprSide.None &&
  125. isValueNode(target.child(2), unit)) {
  126. newNode = target.child(1);
  127. }
  128. if((side & ExprSide.Left) != ExprSide.None &&
  129. isValueNode(target.child(1), unit)) {
  130. newNode = target.child(2);
  131. }
  132. if(null == newNode)
  133. return null;
  134. efi.suspendLayout();
  135. efi.replaceVertex(target, newNode, true);
  136. efi.resumeLayout();
  137. return newNode;
  138. }
  139. /// <summary>
  140. /// Replaces constant array-creation node indexing with the actual
  141. /// array being referred
  142. /// </summary>
  143. /// <param name="target"> The node at which to apply the transform </param>
  144. /// <param name="data"> Ignored </param>
  145. /// <returns> The new node if transformed and null if not </returns>
  146. public static EfiNode replaceArray(EfiNode target, object data) {
  147. if(target.nodeType != EfiNodeType.Apply)
  148. return null;
  149. EfiNode applied = target.child(0);
  150. if(applied.nodeType != EfiNodeType.Array)
  151. return null;
  152. int nchild = target.childCount;
  153. if(nchild < 2)
  154. return null;
  155. EfiNode value = target.child(1);
  156. if(value.nodeType != EfiNodeType.Value)
  157. return null;
  158. int ind = (int)value.element;
  159. if(-1 >= ind || ind >= applied.childCount)
  160. return null;
  161. EfiNode src = applied.child(ind);
  162. // check the domains
  163. IPureFunction domApplied = applied.domain, domSrc = src.domain;
  164. if(null == domApplied || null == domSrc)
  165. return null;
  166. if(PureFunc.returnRank(domApplied) != PureFunc.returnRank(domSrc) + 1)
  167. return null;
  168. // projection dimensions
  169. int pjc = PureFunc.returnRank(domApplied) - 1;
  170. int[] pjd = new int[pjc];
  171. for(int i = 0; i < applied.boundVars.Length - 1; i++)
  172. pjd[i] = i;
  173. for(int i = 0; i < TypeOps.funcParamRank(applied.ubtype) - 1; i++)
  174. pjd[i + applied.boundVars.Length] =
  175. i + applied.boundVars.Length + 1;
  176. if(!domSrc.Equals(domApplied.project(pjd)))
  177. return null;
  178. // perform the transformation
  179. EfiFdag efi = target.efi;
  180. efi.suspendLayout();
  181. EfiNode newNode = efi.createNode(EfiNodeType.Apply, null, null);
  182. efi.AddEdge(new EfiEdge(newNode, src));
  183. for(int i = 2; i < nchild; i++)
  184. efi.AddEdge(new EfiEdge(newNode, target.child(i)));
  185. efi["remBoundVars", newNode] = null;
  186. efi.replaceVertex(target, newNode, true);
  187. efi.resumeLayout();
  188. return newNode;
  189. }
  190. /// <summary>
  191. /// Aggregate constants using the distributivity property
  192. /// </summary>
  193. /// <param name="target"> The node at which to apply the transform </param>
  194. /// <param name="data"> Ignored </param>
  195. /// <returns> The new node if transformed and null if not </returns>
  196. public static EfiNode replaceDistrib(EfiNode target, object data) {
  197. if(target.nodeType != EfiNodeType.Apply) return null;
  198. EfiNode applied = target.child(0);
  199. if(applied.nodeType != EfiNodeType.Function) return null;
  200. IPureFunction f = (IPureFunction)applied.element;
  201. Pair<IPureFunction, DistributiveAttribute>[] dats =
  202. MemberCache.instance.getDistrRefs(f);
  203. if(dats.Length == 0) return null;
  204. // get the "out-of-brackets" node
  205. EfiNode node = null;
  206. ExprSide side1 = ExprSide.None, side2 = ExprSide.None;
  207. object cnst1 = null, cnst2 = null;
  208. if(node.child(1) == node.child(2)) {
  209. node = node.child(1);
  210. side1 = side2 = ExprSide.None;
  211. // TODO: initialize constants
  212. } else {
  213. }
  214. throw new NotImplementedException();
  215. }
  216. /// <summary>
  217. /// Replaces values in special nodes (e.g., limit, apply special and tuple nodes)
  218. /// </summary>
  219. /// <param name="target"> The node to be transformed </param>
  220. /// <param name="data"> Ignored </param>
  221. /// <returns> The new node if transformed and null if not </returns>
  222. public static EfiNode replaceSpecial(EfiNode target, object data) {
  223. switch(target.nodeType) {
  224. case EfiNodeType.LimitFunc: case EfiNodeType.LimitVar:
  225. return replaceSpecialLimit(target);
  226. case EfiNodeType.Apply: case EfiNodeType.ApplySpecial:
  227. return replaceSpecialApply(target);
  228. default:
  229. return null;
  230. }
  231. }
  232. /// <summary>
  233. /// Performs special replacement on apply nodes
  234. /// </summary>
  235. /// <param name="target"> The target node </param>
  236. /// <returns> The new node if transformed and null if not </returns>
  237. private static EfiNode replaceSpecialApply(EfiNode target) {
  238. EfiNode applied = target.child(0);
  239. EfiFdag efi = target.efi;
  240. if(applied.nodeType != EfiNodeType.Function)
  241. return null;
  242. IPureFunction f = (IPureFunction)applied.element;
  243. if(MemberOps.isDomAccess(f)) {
  244. IPureFunction dom = target.child(1).domain;
  245. if(null == dom)
  246. return null;
  247. efi.suspendLayout();
  248. EfiNode newNode = efi.createNode(EfiNodeType.Function, null, dom);
  249. efi["remBoundVars", newNode] = null;
  250. efi["unboundType", newNode] = TypeOps.getFuncType(dom);
  251. #if DEBUG
  252. efi["name", newNode] = dom.ToString();
  253. #endif
  254. efi.replaceVertex(target, newNode, true);
  255. efi.resumeLayout();
  256. return newNode;
  257. }
  258. return null;
  259. }
  260. /// <summary>
  261. /// Replaces special limit nodes
  262. /// </summary>
  263. /// <param name="target"> The target node </param>
  264. /// <returns> The new node if transformed and null if not </returns>
  265. private static EfiNode replaceSpecialLimit(EfiNode target) {
  266. IPureFunction leftdom = target.child(0).domain;
  267. IPureFunction trgdom = target.domain;
  268. if(null == leftdom || null == trgdom)
  269. return null;
  270. if(!leftdom.Equals(trgdom))
  271. return null;
  272. EfiFdag efi = target.efi;
  273. efi.suspendLayout();
  274. EfiNode newNode = target.child(0);
  275. efi.replaceVertex(target, newNode, true);
  276. efi.resumeLayout();
  277. return newNode;
  278. }
  279. /// <summary>
  280. /// Checks whether the specified node is a value node and holds a specific
  281. /// value
  282. /// </summary>
  283. /// <param name="node"> The node to check </param>
  284. /// <param name="val"> The value to check </param>
  285. /// <returns> True iff the node is a value node and holds the value
  286. /// specified </returns>
  287. private static bool isValueNode(EfiNode node, object val) {
  288. if(node.nodeType != EfiNodeType.Value)
  289. return false;
  290. if(!object.Equals(val, node.element))
  291. return false;
  292. return true;
  293. }
  294. }
  295. }