【问题标题】:Expand product of sums to a minimum sum of products将总和的乘积扩展到最小的乘积总和
【发布时间】:2017-03-20 13:40:27
【问题描述】:

我正在尝试编写Petrick's method,这是Quine–McCluskey algorithm 的一种技术。

假设我有一个数学方程式,它由+* 组成。例如:

(K+L)(K+M)(L+N)(M+P)(N+Q)(P+Q)

我如何扩展等式以获得所有产品的总和,像这样?

K*K*L*M*N*P + K*K*L*M*N*Q + .... (63 terms)

(你可以用WolframAlpha看到推断的结果)

【问题讨论】:

  • 您如何存放产品?
  • 我不明白这个问题。您在寻找 Mathematica 命令吗?那就是Expand[(K + L) (K + M) (L + N) (M + P) (N + Q) (P + Q)]
  • @Michael 我的意思是如何获得类似于 WolframAlpha 的结果。
  • @Charles 我可以使用不可变的字符数组。
  • 出于某种原因,WolframAlpha 的结果不适合您——也许是因为您正在使用其他编程语言编写代码?但是你需要说出你真正想要什么才能回答这个问题。

标签: algorithm math wolfram-mathematica boolean-logic algebra


【解决方案1】:

我有点怀疑这是否是你想要的,但要以字符数组的形式获得结果......

w = Expand[(K + L) (K + M) (L + N) (M + P) (N + Q) (P + Q)];
x = ToString@InputForm[w];
z = StringReplace[x, y_ ~~ "^2" :> StringJoin[y, "*", y]]
K*K*L*M*N*P + K*L*L*M*N*P + K*L*M*M*N*P + ... + L*M*N*P*Q*Q
DeleteCases[Characters@z, " "]
{K,*,K,*,L,*,M,*,N,*,P,+, ... ,+,L,*,M,*,N,*,P,*,Q,*,Q}

【讨论】:

    【解决方案2】:

    我得到的条款比你预期的要少 - 只有五个而不是 63 个:

    作为Boolean 表达式:

    (k+l) & (l+n) & (k+m) & (m+p) & (n+q) & (p+q)
    
    
    knp + lmq + lmnp + klpq + kmnq
    

    看看this site 后面的JavaScript 代码可能会很有趣。它是JavaScriptPetrick 的 方法的实现。

    【讨论】:

      【解决方案3】:

      关于你的陈述

      “我正在尝试编写 Petrick 方法,这是一种用于 Quine-McCluskey 算法的技术。”

      我会告诉你一个

      • 准备使用 Petrick 方法的实现和
      • 也是一个成熟的 Quine & McCluskey 实施和
      • 我实现的算法的解释

      首先,完整的解决方案可以在这里找到:

      MCDC

      源代码是一个优雅的解决方案,使用集合操作实现高效:

      // Functor operator for applying Petricks methhod
      ProductTermVector PetricksMethod::operator ()(const CNF& cnf)
      {
          // We select an iterative approach. Start with the first Element of the CNF (which is a DNF)
          // And we store the result of each iterative operation again in this element
          DNF resultingDNF{ cnf[0] };
          // We will always start with the element 1 (not element 0) because in 0 is the initial value
          // or respectively the intermediate result
          for (CNF::size_type dnfInCnfIndex = 1; dnfInCnfIndex < cnf.size(); ++dnfInCnfIndex)
          {
              // Result of multipliying out the intermediate (initial) value with the current CNF Product term
              DNF intermediateCalculatedDNF;
              // Now go through all elements of the intermediate (initial) product term/DNF
              // For (1+2)(3+4)  this would be the (1+2) part
              for (const ProductTerm& productTermLeftSide : resultingDNF)
              {
                  // Next we will iterate over all Minterms in the next DNF
                  // For (1+2)(3+4)  this would be the (3+4) part
                  for (const ProductTerm& productTermRightSide : cnf[dnfInCnfIndex])
                  {
                      ProductTerm productTerm{ productTermLeftSide }; // Resulting Product term is now 1
                      // Add all elements from the right side
                      productTerm.insert(productTermRightSide.begin(), productTermRightSide.end());   // Resulting Product term is now 1,2
                      intermediateCalculatedDNF.insert(std::move(productTerm));  // Store this one
                      // And continue to add more product terms. The stl::set will ensure the idempotence law and prevent memory waste
                  }
              }
              // And now add all found terms to the result and continue with the next element of the right hand side
              // Please note: also here the set will prevent double terms
              resultingDNF = std::move(intermediateCalculatedDNF);
          }
      
          // Now we have the result (with 10 lines of code). The result contains all product terms in DNF
          // But for our prupose we are only interested in the minimum size terms
          // so, lets find the element with the minimu size (can be more than one)
          uint minLength{ narrow_cast<uint>(std::min_element(resultingDNF.begin(), resultingDNF.end(), [](const ProductTerm & left, const ProductTerm & right) noexcept {return left.size() < right.size(); })->size()) };
          // And from the big list of the DNF with all product terms, we copy all elements having the minimu size to the result. These are our best coverage sets
          ProductTermVector cheapestVector;
          // Copy result and return it to caller
          std::copy_if(resultingDNF.begin(), resultingDNF.end(), std::back_inserter(cheapestVector), [&minLength](const ProductTerm& pt) noexcept {return pt.size() == minLength; });
          return cheapestVector;
      }
      

      净代码行数为 14。使用了一些额外的定义,以便更容易理解和使用类型:

      using BooleanVariable = uint_fast8_t;
      using ProductTerm = std::set<BooleanVariable>;
      using ProductTermVector = std::vector<ProductTerm>;
      // Disjunctive Normal Form
      using DNF = std::set<ProductTerm>;
      // Conjunctive Normal Form
      using CNF = std::vector<DNF>;
      
      class PetricksMethod    // Functor
      {
      public:
          ProductTermVector operator()(const CNF& cnf); // Functor operator
      };
      

      请注意。 “BooleanVariable”类型也可以是字符、字符串或任何您喜欢的类型。这对实现无关紧要,但会对消耗的内存产生影响。

      该算法背后的思想是使用“STL 集”并利用集合操作的属性。例如,如果您看一下术语 (a+b)(c+d): 如果您想将其相乘,那么结果将是:ac+ad+bc+bd。如果您将布尔变量视为只有一个成员的特殊乘积项并将该乘积项实现为一个集合,那么操作就是将变量添加到现有集合中。因此,如果您有一个包含“a”的集合,并且您想将其与包含“b”的集合相乘,那么您只需将“b”添加到“a”即可。然后该集合将包含“ab”。

      所以,我们将把包含“b”的集合插入到包含“a”的集合中,以此类推。我们将循环执行此操作,将获得 4 个集合(产品术语)。这 4 个集合构成了一个结果 DNF。刚刚计算的 DNF 可以与 CNF 的附加项进一步组合。

      如果我们有“(a+b)(c+d)(e+f)”,我们会将其视为“((a+b)(c+d)) (e+f)”。我们首先将前 2 个 MaxTerm 相乘,得到 (ac+ad+bc+bd) 并对 (e+f) 应用相同的算法。我们将始终将新变量添加到现有集合中。我们将迭代地执行此操作,直到评估完整的表达式。

      问题是产生的子项很多。但幸运的是,这里集合的属性,具有独特的排序元素会有所帮助。对于 (a+b)(b+a),我们将得到 ab+aa+bb+ba。 stl 集合将为我们提供幂等律。意思是“a”和“a”是“a”,“b”或“b”是“b”。因此,尝试将“a”添加到已经包含“a”的集合中是行不通的。结果仍然是“a”。与完整的产品术语相同,例如 2 次“ab”。它们不会被添加到 DNF 替身中。所以,上述操作的结果是:

      ab+aa+bb+ba --> ab+ab+aa+bb --> ab+aa+bb --> a+b+ab

      采用这种方法,不会有双重条款,而且通常会更短。

      但请注意。计算时间和内存消耗会随着词条的数量呈几何级数增长。因此,该函数只能与有限数量的变量/术语一起应用。

      我希望我能给出一个可以理解的解释。如果您需要更多信息,请询问。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多