如何在 C# 中线性化二进制和-或图?
How to linearize a binary and-or graph in C#?
我尝试 'linearize' 二进制和-或树的每一种可能性,以使其更易于阅读。每种可能性都应添加到以下结构中:
// (x1 AND x2) OR (x2 AND x3)
List<List<Node>> possibilities = new List<List<Node>>() {
{ x1, x2 },
{ x2, x3 }
};
我在从树结构生成基于列表的可能性时遇到了一些困难。在许多情况下 return 没有正确答案的简化版本或我的算法是:
class TreeDecomposer {
public List<TreePath> Possibilities = new List<TreePath>();
// TreePath = { List<TreeNode> path, bool IsAdded }
public TreeDecomposer(AbstractTree tree) {
DecomposeTree(tree, new TreePath());
}
public void DecomposeTree(AbstractTree tree, TreePath path)
{
// Add the path to the list of possibilities
if (!path.IsAdded)
{
Possibilities.Add(path);
path.IsAdded = true;
}
// Recursive browse
if (tree is TreeConnector) {
TreeConnector treeConnector = (TreeConnector)tree;
if (treeConnector.Connection == "&")
{
DecomposeTree(treeConnector.LeftTree, path);
DecomposeTree(treeConnector.RightTree, path);
}
else if (treeConnector.Connection == "|")
{
TreePath clonedPath = (TreePath)path.Clone(); // deep clone
DecomposeTree(treeConnector.LeftTree, path);
DecomposeTree(treeConnector.RightTree, clonedPath); // somehow 'or' operator multiplies possibilities by two?
}
}
// Leaf
else if (tree is TreeValue) {
TreeValue treeValue = (TreeValue)tree;
path.Add(treeValue);
}
}
}
我需要帮助找到正确的算法来使用我的树结构来浏览树并构建 'AND-path' 的所有可能性。
两个基本示例:
Binary end-or tree example (1)
公式: (a | b) & (c | d)
可能性:
{
{a, c}, // or {c, a}, the order doesn't matter
{a, d},
{b, c},
{b, d}
}
Binary end-or tree example (2)
公式: a & ((b | c) & d)
可能性:
{
{a, b, d}, // or {d, b, a}, the order doesn't matter
{a, c, d}
}
树结构:
实现或树结构如下:
abstract class AbstractTree {}
class TreeConnector: AbstractTree
{
public string Connection; // '&' or '|'
public AbstractTree LeftTree;
public AbstractTree RightTree;
}
class TreeValue : AbstractTree
{
public string Data; // 'a', or 'b', ...
}
非常感谢您的帮助。
基于@Freggar link,这里是 'OR' 分布的简化实现。它可能不是以最有效的方式完成的,但它给出了我正在寻找的东西的全局概念。
/*
TreePath = {
HashSet<TreeNode> path,
bool IsAdded // set to false even if it's true when an instance is cloned
}
Every class (Tree...) define the methods:
public object Clone()
public bool Equals(T typedObj)
public override bool Equals(object obj)
public override int GetHashCode()
*/
enum TreeBranch
{
Unknown,
Left,
Right
}
class TreeDecomposer {
public List<TreePath> Possibilities = new List<TreePath>();
public TreeDecomposer(AbstractTree tree)
{
DecomposeTree(null, tree, TreeBranch.Unknown, new TreePath());
RemoveDuplicatePaths();
}
public void DecomposeTree(AbstractTree parentNode, AbstractTree node, TreeBranch branch, TreePath path)
{
if (!path.IsAdded)
{
Possibilities.Add(path);
path.IsAdded = true;
}
// Recursive browse
if (node is TreeConnector) {
TreeConnector treeConnector = (TreeConnector)node;
if (treeConnector.Connection == "&")
{
DecomposeTree(treeConnector, treeConnector.LeftTree, TreeBranch.Left, path);
DecomposeTree(treeConnector, treeConnector.RightTree, TreeBranch.Right, path);
}
else if (treeConnector.Connection == "|")
{
// In this case, parentNode is a TreeOperator
if (parentNode != null)
{
// Left distribution
TreePath clonedPathLeftDistribution = (TreePath)path.Clone();
TreeConnector parentTreeConnectorLeftDistribution = (TreeConnector)parentNode.Clone();
// Right distribution
TreePath clonedPathRightDistribution = (TreePath)path.Clone();
TreeConnector parentTreeConnectorRightDistribution = (TreeConnector)parentNode.Clone();
if (branch == TreeBranch.Left)
{
parentTreeConnectorLeftDistribution.LeftTree = treeConnector.LeftTree;
parentTreeConnectorRightDistribution.LeftTree = treeConnector.RightTree;
}
else if (branch == TreeBranch.Right)
{
parentTreeConnectorLeftDistribution.RightTree = treeConnector.LeftTree;
parentTreeConnectorRightDistribution.RightTree = treeConnector.RightTree;
}
// Remove obsolete path
Possibilities.Remove(path);
// Browse recursively distributed tree ; the path must be different (by ref) if the parent operator is 'OR'
DecomposeTree(
parentTreeConnectorLeftDistribution,
parentTreeConnectorLeftDistribution.LeftTree,
TreeBranch.Left,
parentTreeConnectorLeftDistribution.Connection == "|"
? (TreePath)clonedPathLeftDistribution.Clone()
: clonedPathLeftDistribution
);
DecomposeTree(
parentTreeConnectorLeftDistribution,
parentTreeConnectorLeftDistribution.RightTree,
TreeBranch.Right,
clonedPathLeftDistribution
);
DecomposeTree(
parentTreeConnectorRightDistribution,
parentTreeConnectorRightDistribution.LeftTree,
TreeBranch.Left,
parentTreeConnectorLeftDistribution.Connection == "|"
? (TreePath)clonedPathRightDistribution.Clone()
: clonedPathRightDistribution
);
DecomposeTree(
parentTreeConnectorRightDistribution,
parentTreeConnectorRightDistribution.RightTree,
TreeBranch.Right,
clonedPathRightDistribution
);
}
// The operator is the root of the tree; we simply divide the path
else
{
TreePath clonedLeftPath = (TreePath)path.Clone();
TreePath clonedRightPath = (TreePath)path.Clone();
// Remove obsolete path
Possibilities.Remove(path);
DecomposeTree(treeConnector, treeConnector.LeftTree, TreeBranch.Left, clonedLeftPath);
DecomposeTree(treeConnector, treeConnector.RightTree, TreeBranch.Right, clonedRightPath);
}
}
break;
}
// Leaf
else if (node is TreeValue) {
TreeValue treeValue = (TreeValue)node;
path.Add(treeValue);
}
}
public void RemoveDuplicatePaths()
{
Possibilities = Possibilities.Distinct().ToList();
}
}
注:
在这里,我只想保留唯一的可能性;这就是为什么我使用 HashSet 而不是 List:
- "a & a & b" => "a & b"
方法 RemoveDuplicatePaths 用于删除重复的组合:
- "a & b"和"b & a"都是同一种可能性(关于真值)
我尝试 'linearize' 二进制和-或树的每一种可能性,以使其更易于阅读。每种可能性都应添加到以下结构中:
// (x1 AND x2) OR (x2 AND x3)
List<List<Node>> possibilities = new List<List<Node>>() {
{ x1, x2 },
{ x2, x3 }
};
我在从树结构生成基于列表的可能性时遇到了一些困难。在许多情况下 return 没有正确答案的简化版本或我的算法是:
class TreeDecomposer {
public List<TreePath> Possibilities = new List<TreePath>();
// TreePath = { List<TreeNode> path, bool IsAdded }
public TreeDecomposer(AbstractTree tree) {
DecomposeTree(tree, new TreePath());
}
public void DecomposeTree(AbstractTree tree, TreePath path)
{
// Add the path to the list of possibilities
if (!path.IsAdded)
{
Possibilities.Add(path);
path.IsAdded = true;
}
// Recursive browse
if (tree is TreeConnector) {
TreeConnector treeConnector = (TreeConnector)tree;
if (treeConnector.Connection == "&")
{
DecomposeTree(treeConnector.LeftTree, path);
DecomposeTree(treeConnector.RightTree, path);
}
else if (treeConnector.Connection == "|")
{
TreePath clonedPath = (TreePath)path.Clone(); // deep clone
DecomposeTree(treeConnector.LeftTree, path);
DecomposeTree(treeConnector.RightTree, clonedPath); // somehow 'or' operator multiplies possibilities by two?
}
}
// Leaf
else if (tree is TreeValue) {
TreeValue treeValue = (TreeValue)tree;
path.Add(treeValue);
}
}
}
我需要帮助找到正确的算法来使用我的树结构来浏览树并构建 'AND-path' 的所有可能性。
两个基本示例:
Binary end-or tree example (1)
公式: (a | b) & (c | d)
可能性:
{
{a, c}, // or {c, a}, the order doesn't matter
{a, d},
{b, c},
{b, d}
}
Binary end-or tree example (2)
公式: a & ((b | c) & d)
可能性:
{
{a, b, d}, // or {d, b, a}, the order doesn't matter
{a, c, d}
}
树结构:
实现或树结构如下:
abstract class AbstractTree {}
class TreeConnector: AbstractTree
{
public string Connection; // '&' or '|'
public AbstractTree LeftTree;
public AbstractTree RightTree;
}
class TreeValue : AbstractTree
{
public string Data; // 'a', or 'b', ...
}
非常感谢您的帮助。
基于@Freggar link,这里是 'OR' 分布的简化实现。它可能不是以最有效的方式完成的,但它给出了我正在寻找的东西的全局概念。
/*
TreePath = {
HashSet<TreeNode> path,
bool IsAdded // set to false even if it's true when an instance is cloned
}
Every class (Tree...) define the methods:
public object Clone()
public bool Equals(T typedObj)
public override bool Equals(object obj)
public override int GetHashCode()
*/
enum TreeBranch
{
Unknown,
Left,
Right
}
class TreeDecomposer {
public List<TreePath> Possibilities = new List<TreePath>();
public TreeDecomposer(AbstractTree tree)
{
DecomposeTree(null, tree, TreeBranch.Unknown, new TreePath());
RemoveDuplicatePaths();
}
public void DecomposeTree(AbstractTree parentNode, AbstractTree node, TreeBranch branch, TreePath path)
{
if (!path.IsAdded)
{
Possibilities.Add(path);
path.IsAdded = true;
}
// Recursive browse
if (node is TreeConnector) {
TreeConnector treeConnector = (TreeConnector)node;
if (treeConnector.Connection == "&")
{
DecomposeTree(treeConnector, treeConnector.LeftTree, TreeBranch.Left, path);
DecomposeTree(treeConnector, treeConnector.RightTree, TreeBranch.Right, path);
}
else if (treeConnector.Connection == "|")
{
// In this case, parentNode is a TreeOperator
if (parentNode != null)
{
// Left distribution
TreePath clonedPathLeftDistribution = (TreePath)path.Clone();
TreeConnector parentTreeConnectorLeftDistribution = (TreeConnector)parentNode.Clone();
// Right distribution
TreePath clonedPathRightDistribution = (TreePath)path.Clone();
TreeConnector parentTreeConnectorRightDistribution = (TreeConnector)parentNode.Clone();
if (branch == TreeBranch.Left)
{
parentTreeConnectorLeftDistribution.LeftTree = treeConnector.LeftTree;
parentTreeConnectorRightDistribution.LeftTree = treeConnector.RightTree;
}
else if (branch == TreeBranch.Right)
{
parentTreeConnectorLeftDistribution.RightTree = treeConnector.LeftTree;
parentTreeConnectorRightDistribution.RightTree = treeConnector.RightTree;
}
// Remove obsolete path
Possibilities.Remove(path);
// Browse recursively distributed tree ; the path must be different (by ref) if the parent operator is 'OR'
DecomposeTree(
parentTreeConnectorLeftDistribution,
parentTreeConnectorLeftDistribution.LeftTree,
TreeBranch.Left,
parentTreeConnectorLeftDistribution.Connection == "|"
? (TreePath)clonedPathLeftDistribution.Clone()
: clonedPathLeftDistribution
);
DecomposeTree(
parentTreeConnectorLeftDistribution,
parentTreeConnectorLeftDistribution.RightTree,
TreeBranch.Right,
clonedPathLeftDistribution
);
DecomposeTree(
parentTreeConnectorRightDistribution,
parentTreeConnectorRightDistribution.LeftTree,
TreeBranch.Left,
parentTreeConnectorLeftDistribution.Connection == "|"
? (TreePath)clonedPathRightDistribution.Clone()
: clonedPathRightDistribution
);
DecomposeTree(
parentTreeConnectorRightDistribution,
parentTreeConnectorRightDistribution.RightTree,
TreeBranch.Right,
clonedPathRightDistribution
);
}
// The operator is the root of the tree; we simply divide the path
else
{
TreePath clonedLeftPath = (TreePath)path.Clone();
TreePath clonedRightPath = (TreePath)path.Clone();
// Remove obsolete path
Possibilities.Remove(path);
DecomposeTree(treeConnector, treeConnector.LeftTree, TreeBranch.Left, clonedLeftPath);
DecomposeTree(treeConnector, treeConnector.RightTree, TreeBranch.Right, clonedRightPath);
}
}
break;
}
// Leaf
else if (node is TreeValue) {
TreeValue treeValue = (TreeValue)node;
path.Add(treeValue);
}
}
public void RemoveDuplicatePaths()
{
Possibilities = Possibilities.Distinct().ToList();
}
}
注:
在这里,我只想保留唯一的可能性;这就是为什么我使用 HashSet 而不是 List:
- "a & a & b" => "a & b"
方法 RemoveDuplicatePaths 用于删除重复的组合:
- "a & b"和"b & a"都是同一种可能性(关于真值)