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();
}
}
}