lnicola
6/24/2014 - 9:06 AM

An expression generator

An expression generator

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace EG
{
    static class NativeMethods
    {
        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern int memcmp(int[] b1, int[] b2, long count);

        public static bool Compare(int[] b1, int[] b2)
        {
            var length = b1.Length;
            for (var i = 0; i < length; i++)
                if (b1[i] != b2[i])
                    return false;

            return true;

            //            return /*b1.Length == b2.Length &&*/ memcmp(b1, b2, b1.Length * 4) == 0;
        }
    }

    abstract class Node : IEquatable<Node>
    {
        public int[] Values;
        protected int hashCode;
        public bool IsConstant;
        public int Size;

        public Node(bool isConstant, int[] values, int size)
        {
            IsConstant = isConstant;
            Values = values;
            Size = size;

            foreach (var value in values)
                hashCode ^= value.GetHashCode();
        }

        public bool Equals(Node other)
        {
            return NativeMethods.Compare(Values, other.Values);
        }

        public abstract override string ToString();

        public override int GetHashCode()
        {
            return hashCode;
        }
    }

    class ArgumentNode : Node
    {
        public ArgumentNode(int[] values)
            : base(false, values, 1)
        {
        }

        public override string ToString()
        {
            return "x";
        }
    }

    class ConstantNode : Node
    {
        private int value;

        public ConstantNode(int value, int[] values)
            : base(true, values, 1)
        {
            this.value = value;
        }

        public override string ToString()
        {
            return value.ToString();
        }
    }

    enum UnaryOpType
    {
        LogicalNot,
        BitwiseNot,
        UnaryNeg
    }

    class UnaryOpNode : Node
    {
        private UnaryOpType unaryOpType;
        private Node node;

        public UnaryOpNode(UnaryOpType unaryOpType, Node node, int[] values)
            : base(node.IsConstant, values, node.Size + 1)
        {
            this.unaryOpType = unaryOpType;
            this.node = node;
        }

        public override string ToString()
        {
            string op;
            switch (unaryOpType)
            {
                case UnaryOpType.LogicalNot:
                    op = "!";
                    break;
                case UnaryOpType.BitwiseNot:
                    op = "~";
                    break;
                case UnaryOpType.UnaryNeg:
                    op = "-";
                    break;
                default:
                    throw new NotImplementedException();
            }

            return op.ToString() + node.ToString();
        }
    }

    enum BinaryOpType
    {
        Add,
        Sub,
        Mul,
        Div,
        Mod,
        LogicalAnd,
        BitwiseAnd,
        LogicalOr,
        BitwiseOr,
        Xor
    }

    class BinaryOpNode : Node
    {
        private BinaryOpType binaryOpType;
        private Node leftNode;
        private Node rightNode;

        public BinaryOpNode(BinaryOpType binaryOpType, Node leftNode, Node rightNode, int[] values)
            : base(leftNode.IsConstant && rightNode.IsConstant, values, leftNode.Size + rightNode.Size + 1)
        {
            this.binaryOpType = binaryOpType;
            this.leftNode = leftNode;
            this.rightNode = rightNode;
        }

        public override string ToString()
        {
            string op;
            switch (binaryOpType)
            {
                case BinaryOpType.Add:
                    op = "+";
                    break;
                case BinaryOpType.Sub:
                    op = "-";
                    break;
                case BinaryOpType.Mul:
                    op = "*";
                    break;
                case BinaryOpType.Div:
                    op = "/";
                    break;
                case BinaryOpType.Mod:
                    op = "%";
                    break;
                case BinaryOpType.LogicalAnd:
                    op = "&&";
                    break;
                case BinaryOpType.BitwiseAnd:
                    op = "&";
                    break;
                case BinaryOpType.LogicalOr:
                    op = "||";
                    break;
                case BinaryOpType.BitwiseOr:
                    op = "|";
                    break;
                case BinaryOpType.Xor:
                    op = "^";
                    break;
                default:
                    throw new NotImplementedException();
            }
            return String.Format("({0}{1}{2})", leftNode.ToString(), op, rightNode.ToString());
        }
    }

    class UnaryOpNodeFactory
    {
        public static Node Create(UnaryOpType unaryOpType, Node node)
        {
            var values = new int[node.Values.Length];

            for (var i = 0; i < values.Length; i++)
            {
                int result;
                switch (unaryOpType)
                {
                    case UnaryOpType.LogicalNot:
                        result = node.Values[i] == 0 ? 1 : 0;
                        break;
                    case UnaryOpType.BitwiseNot:
                        result = ~node.Values[i];
                        break;
                    case UnaryOpType.UnaryNeg:
                        result = -node.Values[i];
                        break;
                    default:
                        throw new NotImplementedException();
                }
                values[i] = result;
            }

            //var constant = true;
            //for (var i = 1; i < values.Length; i++)
            //    if (values[i] != values[0])
            //        constant = false;

            //if (constant)
            //    return new ConstantNode(values[0], values);
            //else
            return new UnaryOpNode(unaryOpType, node, values);
        }
    }

    class BinaryOpNodeFactory
    {
        public static Node Create(BinaryOpType binaryOpType, Node leftNode, Node rightNode)
        {
            var values = new int[leftNode.Values.Length];

            for (var i = 0; i < values.Length; i++)
            {
                int result;
                switch (binaryOpType)
                {
                    case BinaryOpType.Add:
                        result = leftNode.Values[i] + rightNode.Values[i];
                        break;
                    case BinaryOpType.Sub:
                        result = leftNode.Values[i] - rightNode.Values[i];
                        break;
                    case BinaryOpType.Mul:
                        result = leftNode.Values[i] * rightNode.Values[i];
                        break;
                    case BinaryOpType.Div:
                        {
                            var right = rightNode.Values[i];
                            result = right == 0 ? -1 : leftNode.Values[i] / right;
                            break;
                        }
                    case BinaryOpType.Mod:
                        {
                            var right = rightNode.Values[i];
                            result = right == 0 ? -1 : leftNode.Values[i] % rightNode.Values[i];
                            break;
                        }
                    case BinaryOpType.LogicalAnd:
                        result = leftNode.Values[i] != 0 && rightNode.Values[i] != 0 ? 1 : 0;
                        break;
                    case BinaryOpType.BitwiseAnd:
                        result = leftNode.Values[i] & rightNode.Values[i];
                        break;
                    case BinaryOpType.LogicalOr:
                        result = leftNode.Values[i] != 0 || rightNode.Values[i] != 0 ? 1 : 0;
                        break;
                    case BinaryOpType.BitwiseOr:
                        result = leftNode.Values[i] | rightNode.Values[i];
                        break;
                    case BinaryOpType.Xor:
                        result = leftNode.Values[i] ^ rightNode.Values[i];
                        break;
                    default:
                        throw new NotImplementedException();
                }
                values[i] = result;
            }

            //var constant = true;
            //for (var i = 1; i < values.Length; i++)
            //    if (values[i] != values[0])
            //        constant = false;

            //if (constant)
            //    return new ConstantNode(values[0], values);
            //else
            return new BinaryOpNode(binaryOpType, leftNode, rightNode, values);
        }
    }

    class ExpressionGenerator
    {
        private List<Node> nodes;
        private List<Node> newNodes;

        public ExpressionGenerator()
        {
            nodes = new List<Node>();
        }

        private IEnumerable<Node> GetConstantNodes()
        {
            for (var i = 0; i < 2; i++)
                yield return new ConstantNode(i, new[] { i, i, i, i, i, i, i, i });
            //yield return new ConstantNode(Int32.MaxValue, new[] { Int32.MaxValue, Int32.MaxValue, Int32.MaxValue, Int32.MaxValue, Int32.MaxValue, Int32.MaxValue, Int32.MaxValue });
        }

        private long count;
        List<Node> closed = new List<Node>();

        public void Run()
        {
            //nodes.Add(new ArgumentNode(new[] { (int)'M' & 15, (int)'D' & 15, (int)'C' & 15, (int)'L' & 15, (int)'X' & 15, (int)'V' & 15, (int)'I' & 15 }));
            nodes.Add(new ArgumentNode(new[] { (int)'M' , (int)'D' , (int)'C' , (int)'L' , (int)'X' , (int)'V' , (int)'I', 0 }));

            //foreach (var node in GetConstantNodes())
            //    nodes.Add(node);

            //var nn = nodes.ToList().AsParallel();

            var constantNodes = GetConstantNodes().ToArray();

            while (nodes.Count > 0)
            {
                newNodes = new List<Node>();

                count = 0;

                //nn = nn.AsParallel()
                //                .Union(nn.AsParallel()
                //                            .Where(node => !node.IsConstant)
                //                            .SelectMany(node => GetUnaryOpNodes(node)
                //                                               .Union(nn.AsParallel()
                //                                                           .Where(otherNode => !otherNode.IsConstant)
                //                                                           .SelectMany(otherNode => GetBinaryOpNodes(node, otherNode)
                //                                                                                   .Where(n => !n.IsConstant)))))
                //                ;//.ToList();


                foreach (var node in nodes)
                {
                   // if (closed.Add(node))
                    {
                        AddNode(UnaryOpNodeFactory.Create(UnaryOpType.LogicalNot, node));
                        AddNode(UnaryOpNodeFactory.Create(UnaryOpType.BitwiseNot, node));
                        AddNode(UnaryOpNodeFactory.Create(UnaryOpType.UnaryNeg, node));

                        foreach (var constantNode in constantNodes)
                        {
                            AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Add, node, constantNode));
                            //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Sub, node, constantNode));
                            //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Sub, constantNode, node));
                            //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Mul, node, constantNode));
                            //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Div, node, constantNode));
                            //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Div, constantNode, constantNode));
                            //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Mod, node, constantNode));
                            //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Mod, constantNode, node));
                            //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.LogicalAnd, node, constantNode));
                            AddNode(BinaryOpNodeFactory.Create(BinaryOpType.BitwiseAnd, node, constantNode));
                            //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.LogicalOr, node, constantNode));
                            AddNode(BinaryOpNodeFactory.Create(BinaryOpType.BitwiseOr, node, constantNode));
                            AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Xor, node, constantNode));
                        }
                    }
                    //else
                    //    if (Test(node))
                    //    {
                    //         Trace.WriteLine(String.Format("found {0}: {1}", node, String.Join(" ", node.Values.Select(v => v.ToString()))));
                    //        //Environment.Exit(0);
                    //    }

//                    continue;

                    foreach (var otherNode in nodes)
                    {
                        AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Add, node, otherNode));
                        //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Sub, node, otherNode));
                        //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Mul, node, otherNode));
                        //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Div, node, otherNode));
                        //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Mod, node, otherNode));
                        //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.LogicalAnd, node, otherNode));
                        AddNode(BinaryOpNodeFactory.Create(BinaryOpType.BitwiseAnd, node, otherNode));
                        //AddNode(BinaryOpNodeFactory.Create(BinaryOpType.LogicalOr, node, otherNode));
                        AddNode(BinaryOpNodeFactory.Create(BinaryOpType.BitwiseOr, node, otherNode));
                        AddNode(BinaryOpNodeFactory.Create(BinaryOpType.Xor, node, otherNode));
                    }
                }


                //foreach (var leftNode in nodes)
                //{
                //    foreach (var rightNode in nodes)
                //        if (!leftNode.IsConstant ^ !rightNode.IsConstant)
                //            foreach (var newNode in GetBinaryOpNodes(leftNode, rightNode))
                //                if (!newNode.IsConstant)
                //                    AddNode(newNode);
                //}



                nodes = newNodes;

                //Console.WriteLine("{0} nodes in the new generation", nodes.Count());
            }
        }

        private Node sol = BinaryOpNodeFactory.Create(BinaryOpType.Mod,
                                BinaryOpNodeFactory.Create(BinaryOpType.Mod,
                                    new ArgumentNode(new[] { (int)'M' , (int)'D' , (int)'C' , (int)'L' , (int)'X' , (int)'V' , (int)'I', 0 }),
                                    new ConstantNode(71, new[] { 71, 71, 71, 71, 71, 71, 71, 71 })),
                                new ConstantNode(8, new[] { 8, 8, 8, 8, 8, 8, 8, 8 }));

        private void AddNode(Node newNode)
        {
            //if (Test(newNode))
            //{
            //    Trace.WriteLine(String.Format("found {0}: {1}", newNode, String.Join(" ", newNode.Values.Select(v => v.ToString()))));
            //    //Environment.Exit(0);
            //}

            if (newNode.Size >= 14)
                return;

            for (int i = 0; i < newNode.Values.Length; i++)
                if (newNode.Values[i] < 0)
                    return;

            for (int i = 0; i < newNode.Values.Length - 1; i++)
            {
                for (int j = i + 1; j < newNode.Values.Length; j++)
                    if (newNode.Values[i] == newNode.Values[j])
                        return;
            }

            //if (/*!newNode.IsConstant && */!closed.Contains(newNode))
            {

                count++;
                if (count % 1 == 0)
                    Console.WriteLine("{0} {1}", newNode, count);
                newNodes.Add(newNode);
            }
        }

        //private int[] lookFor = new[] { /*1000, 500, 100,*/ 50, 10, 5, 1 };
        //private int[] lookFor = new[] { /*1000, 500, */10, 9, 7, 6, 4, 3, 0 };
        //private int[] lookFor = new[] { 1, 1, 1, 0, 0, 0, 0 };
        private int[] lookFor = new[] { 6, 4, 3, 5, 1, 7, 2, 0 };

        private bool[] p = new bool[8];

        private bool Test(Node node)
        {
            var n = node.Values.Length;
            for (var i = 0; i < n; i++)
                p[i] = false;
            for (var i = 0; i < n; i++)
            {
                if (node.Values[i] < 0 || node.Values[i] > 7 || p[node.Values[i]])
                    return false;

                p[node.Values[i]] = true;
            }

            //if (node.Values[0] < 6 || node.Values[1] < 6)
            //    return false;

            return true;

            return NativeMethods.Compare(lookFor, node.Values);
        }
    }

    class Program
    {
        static void Main()
        {
            new ExpressionGenerator().Run();
        }
    }
}