/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
- using System;
- using System.Collections.Generic;
- using System.Text;
- using Wintellect.PowerCollections;
-
- namespace CBucks.Efi {
-
- /// <summary>
- /// A local EFI transform delegate
- /// </summary>
- /// <param name="target"> The target of the transform </param>
- /// <param name="data"> Additional transform data </param>
- /// <returns> The new node which is the result of the transform and
- /// replaces <paramref name="target"/>, or null if no transform has
- /// been performed. </returns>
- /// <remarks> Actual replacement shall be done inside the delegate,
- /// while root replacement and iterator replacement is actually done
- /// outside this method. The graph is deduced as a property of target. </remarks>
- public delegate EfiNode LocalTransform(EfiNode target, object data);
-
- /// <summary>
- /// Contains local EFI transforms (i.e. transforms based in a single vertex)
- /// </summary>
- public static class EfiLocalTransforms {
-
- /// <summary>
- /// Replaces the constant at the target node. Does the actual replacement.
- /// </summary>
- /// <param name="target"> The target, at which to perform the replacement </param>
- /// <param name="data"> Ignored </param>
- /// <returns> The new node or none if no replacement have taken place </returns>
- public static EfiNode replaceConstant(EfiNode target, object data) {
- EfiFdag efi = target.efi;
- // check node type
- if(target.nodeType != EfiNodeType.Apply)
- return null;
- // check simplicity
- EfiNode applied = target.child(0);
- if(applied.nodeType != EfiNodeType.Function)
- return null;
- if(!applied.isSimpleFunc && !applied.isArray)
- return null;
- // check constantness
- int nchild = target.childCount;
- for(int i = 1; i < nchild; i++) {
- if(target.child(i).nodeType != EfiNodeType.Value)
- return null;
- }
- // evaluate the result
- object res;
- IPureFunction f = (IPureFunction)applied.element;
- int narg = nchild - 1;
- object[] args = new object[narg];
- for(int i = 1; i < nchild; i++)
- args[i - 1] = target.child(i).element;
- res = f.eval(args);
- // define node type
- EfiNodeType nt = PureFunc.isFunction(res) ? EfiNodeType.Function :
- EfiNodeType.Value;
- // create and replace
- efi.suspendLayout();
- EfiNode newNode = efi.createNode(nt, null, res);
- efi["unboundType", newNode] = PureFunc.isFunction(res) ?
- TypeOps.getFuncType((IPureFunction)res) : TypeOps.funcCreate(res.GetType(),
- typeof(Tuple00));
- efi["remBoundVars", newNode] = new List<object>();
- #if DEBUG
- efi["name", newNode] = null == res ? "null" : res.ToString();
- #endif
- efi.replaceVertex(target, newNode, true);
- efi.resumeLayout();
- return newNode;
- } // end of replaceConstant()
-
- /// <summary>
- /// Replaces the f(a, ..., a) => a at the target node. Does the actual replacement.
- /// </summary>
- /// <param name="target"> The target, at which to perform the replacement </param>
- /// <param name="data"> Ignored </param>
- /// <returns> The new node or none if no replacement have taken place </returns>
- public static EfiNode replaceIdempotent(EfiNode target, object data) {
- EfiFdag efi = target.efi;
- // check node type
- if(target.nodeType != EfiNodeType.Apply)
- return null;
- // check simplicity
- EfiNode applied = target.child(0);
- if(applied.nodeType != EfiNodeType.Function)
- return null;
- if(!applied.isIdempotentFunc)
- return null;
- int nchild = target.childCount;
- if(nchild <= 2)
- return null;
- // check that children are the same
- EfiNode arg = target.child(1);
- for(int i = 2; i < nchild; i++)
- if(arg != target.child(i))
- return null;
- // replace
- efi.suspendLayout();
- efi.replaceVertex(target, arg, true);
- efi.resumeLayout();
- return arg;
- }
-
- /// <summary>
- /// Removes the unnecessary unit elements from the node specified
- /// </summary>
- /// <param name="target"> The target node of the transformation </param>
- /// <param name="data"> Ignored </param>
- /// <returns> The new node or null if no transformations applied </returns>
- /// <remarks> Performs transformations such as a * 1 => a, 0 + a => a, etc.
- /// </remarks>
- public static EfiNode removeUnitElements(EfiNode target, object data) {
- EfiFdag efi = target.efi;
- if(target.nodeType != EfiNodeType.Apply)
- return null;
- EfiNode applied = target.child(0);
- if(!applied.hasFuncUnit)
- return null;
- int nchild = target.childCount;
- if(nchild != 3)
- return null;
- // get the unit element and sides
- UnitElementAttribute uea = applied.unitAttr;
- object unit = uea.unit;
- ExprSide side = uea.side;
- EfiNode newNode = null;
- if((side & ExprSide.Right) != ExprSide.None &&
- isValueNode(target.child(2), unit)) {
- newNode = target.child(1);
- }
- if((side & ExprSide.Left) != ExprSide.None &&
- isValueNode(target.child(1), unit)) {
- newNode = target.child(2);
- }
- if(null == newNode)
- return null;
- efi.suspendLayout();
- efi.replaceVertex(target, newNode, true);
- efi.resumeLayout();
- return newNode;
- }
-
- /// <summary>
- /// Replaces constant array-creation node indexing with the actual
- /// array being referred
- /// </summary>
- /// <param name="target"> The node at which to apply the transform </param>
- /// <param name="data"> Ignored </param>
- /// <returns> The new node if transformed and null if not </returns>
- public static EfiNode replaceArray(EfiNode target, object data) {
- if(target.nodeType != EfiNodeType.Apply)
- return null;
- EfiNode applied = target.child(0);
- if(applied.nodeType != EfiNodeType.Array)
- return null;
- int nchild = target.childCount;
- if(nchild < 2)
- return null;
- EfiNode value = target.child(1);
- if(value.nodeType != EfiNodeType.Value)
- return null;
- int ind = (int)value.element;
- if(-1 >= ind || ind >= applied.childCount)
- return null;
- EfiNode src = applied.child(ind);
- // check the domains
- IPureFunction domApplied = applied.domain, domSrc = src.domain;
- if(null == domApplied || null == domSrc)
- return null;
- if(PureFunc.returnRank(domApplied) != PureFunc.returnRank(domSrc) + 1)
- return null;
- // projection dimensions
- int pjc = PureFunc.returnRank(domApplied) - 1;
- int[] pjd = new int[pjc];
- for(int i = 0; i < applied.boundVars.Length - 1; i++)
- pjd[i] = i;
- for(int i = 0; i < TypeOps.funcParamRank(applied.ubtype) - 1; i++)
- pjd[i + applied.boundVars.Length] =
- i + applied.boundVars.Length + 1;
- if(!domSrc.Equals(domApplied.project(pjd)))
- return null;
- // perform the transformation
- EfiFdag efi = target.efi;
- efi.suspendLayout();
- EfiNode newNode = efi.createNode(EfiNodeType.Apply, null, null);
- efi.AddEdge(new EfiEdge(newNode, src));
- for(int i = 2; i < nchild; i++)
- efi.AddEdge(new EfiEdge(newNode, target.child(i)));
- efi["remBoundVars", newNode] = null;
- efi.replaceVertex(target, newNode, true);
- efi.resumeLayout();
- return newNode;
- }
-
- /// <summary>
- /// Aggregate constants using the distributivity property
- /// </summary>
- /// <param name="target"> The node at which to apply the transform </param>
- /// <param name="data"> Ignored </param>
- /// <returns> The new node if transformed and null if not </returns>
- public static EfiNode replaceDistrib(EfiNode target, object data) {
- if(target.nodeType != EfiNodeType.Apply) return null;
- EfiNode applied = target.child(0);
- if(applied.nodeType != EfiNodeType.Function) return null;
- IPureFunction f = (IPureFunction)applied.element;
- Pair<IPureFunction, DistributiveAttribute>[] dats =
- MemberCache.instance.getDistrRefs(f);
- if(dats.Length == 0) return null;
- // get the "out-of-brackets" node
- EfiNode node = null;
- ExprSide side1 = ExprSide.None, side2 = ExprSide.None;
- object cnst1 = null, cnst2 = null;
- if(node.child(1) == node.child(2)) {
- node = node.child(1);
- side1 = side2 = ExprSide.None;
- // TODO: initialize constants
- } else {
- }
- throw new NotImplementedException();
- }
-
- /// <summary>
- /// Replaces values in special nodes (e.g., limit, apply special and tuple nodes)
- /// </summary>
- /// <param name="target"> The node to be transformed </param>
- /// <param name="data"> Ignored </param>
- /// <returns> The new node if transformed and null if not </returns>
- public static EfiNode replaceSpecial(EfiNode target, object data) {
- switch(target.nodeType) {
- case EfiNodeType.LimitFunc: case EfiNodeType.LimitVar:
- return replaceSpecialLimit(target);
- case EfiNodeType.Apply: case EfiNodeType.ApplySpecial:
- return replaceSpecialApply(target);
- default:
- return null;
- }
- }
-
- /// <summary>
- /// Performs special replacement on apply nodes
- /// </summary>
- /// <param name="target"> The target node </param>
- /// <returns> The new node if transformed and null if not </returns>
- private static EfiNode replaceSpecialApply(EfiNode target) {
- EfiNode applied = target.child(0);
- EfiFdag efi = target.efi;
- if(applied.nodeType != EfiNodeType.Function)
- return null;
- IPureFunction f = (IPureFunction)applied.element;
- if(MemberOps.isDomAccess(f)) {
- IPureFunction dom = target.child(1).domain;
- if(null == dom)
- return null;
- efi.suspendLayout();
- EfiNode newNode = efi.createNode(EfiNodeType.Function, null, dom);
- efi["remBoundVars", newNode] = null;
- efi["unboundType", newNode] = TypeOps.getFuncType(dom);
- #if DEBUG
- efi["name", newNode] = dom.ToString();
- #endif
- efi.replaceVertex(target, newNode, true);
- efi.resumeLayout();
- return newNode;
- }
- return null;
- }
-
- /// <summary>
- /// Replaces special limit nodes
- /// </summary>
- /// <param name="target"> The target node </param>
- /// <returns> The new node if transformed and null if not </returns>
- private static EfiNode replaceSpecialLimit(EfiNode target) {
- IPureFunction leftdom = target.child(0).domain;
- IPureFunction trgdom = target.domain;
- if(null == leftdom || null == trgdom)
- return null;
- if(!leftdom.Equals(trgdom))
- return null;
- EfiFdag efi = target.efi;
- efi.suspendLayout();
- EfiNode newNode = target.child(0);
- efi.replaceVertex(target, newNode, true);
- efi.resumeLayout();
- return newNode;
- }
-
- /// <summary>
- /// Checks whether the specified node is a value node and holds a specific
- /// value
- /// </summary>
- /// <param name="node"> The node to check </param>
- /// <param name="val"> The value to check </param>
- /// <returns> True iff the node is a value node and holds the value
- /// specified </returns>
- private static bool isValueNode(EfiNode node, object val) {
- if(node.nodeType != EfiNodeType.Value)
- return false;
- if(!object.Equals(val, node.element))
- return false;
- return true;
- }
-
- }
- }