【问题标题】:smart automatic C code generator with nested if in pythonpython中带有嵌套if的智能自动C代码生成器
【发布时间】:2011-04-05 10:36:35
【问题描述】:

我正在从 python 生成自动 C++ 代码,特别是我需要为事件列表选择一些事件。我声明了一些选择:

selectionA = Selection(name="selectionA", formula="A>10")
selectionB = Selection(name="selectionB", formula="cobject->f()>50")
selectionC = selectionA * selectionB # * means AND

这会生成 C++ 代码:

for(...) { // cicle on events
  event = GetEvent(i);

  bool selectionA = A>10;
  bool selectionB = cobject->f()>50;
  bool selectionC = (A>10) and (cobject->f()>50);

  if (selectionA) { histo_selectionA->Fill(event); }
  if (selectionB) { histo_selectionB->Fill(event); }
  if (selectionC) { histo_selectionC->Fill(event); }
}

这不是很聪明,因为最聪明的代码是:

bool selectionC = selectionA and selectionB

这个问题看似简单,其实不然,因为我有 100+ 个基本选择(如selectionAselectionB)和 300+ 个派生选择,当然派生选择可以从派生选择中派生.明显的派生选择不是从使用常规模式的基本选择派生的。

我知道这很难回答,但有人可以给我一些提示吗?例如:真的有必要编写智能代码吗?我的意思是,编译器无法优化这段代码?

【问题讨论】:

  • 我相信大多数 C++ 编译器已经为你做这件事了。
  • 为什么变量中没有一个标志,只在第一代扩展为公式,然后扩展为布尔条件的名称?
  • @blwy10: 因为它不是那么容易,特别是你必须保证以正确的顺序声明 bool 变量并且没有重复
  • 没错,这并不容易。但是考虑到一个 Selection 对象只能通过其构造函数或 * 运算符创建,这已经可以用来跟踪函数中所有选择变量的顺序。除非我在这里遗漏了什么......

标签: c++ python compiler-construction code-generation


【解决方案1】:

编译器不太可能优化此代码。部分原因是cobject->f() 可能有编译器看不到的副作用。

您可以通过将您的布尔值声明为 const 来提供一些帮助。

否则,您似乎已经在重载运算符来组成选择。因此,使组合选择使用其组成的选择的名称而不是表达式应该不会太难。这为您做了一些优化,并允许编译器在可能的情况下进一步优化,特别是如果您将选择布尔值声明为 const

您还必须小心地发出代码以初始化bool 标志,其顺序与在 Python 中创建选择对象的顺序相同。这将确保 bool 在以后使用之前总是被声明和初始化。您可以通过在 Python Selection 类中创建一个列表并让 __init__ 方法将新的 Selection 添加到该列表中来做到这一点。当然,如果您创建 Selection 对象,然后将其丢弃,这可能是个问题。但如果你把它们都保留下来,它会起作用。

【讨论】:

    【解决方案2】:

    编译器也许能够优化这个代码,但如果你有数百个相互依赖的复杂表达式,我会怀疑它是否能很好地工作。

    但一个更基本的问题是:您真的需要优化吗?计算机速度很快,如果您不经常运行该代码,那么cobject->f()>50 运行一次或十次可能并不重要。

    另一方面,如果cobject->f() 有副作用(例如,它打印一些东西),编译器将永远不会优化重复调用,您必须确保它只在您生成的代码中被调用尽可能多地打印。

    最好的解决方案是,当您的Selection 类用作派生定义的一部分时,可以只输出name 而不是formula。难易程度取决于您生成的代码。

    【讨论】:

      【解决方案3】:

      作为对我评论的修正,我什至认为您不需要我建议的跟踪变量。为什么不试试这个?

      import string
      
      class Selection:
          selections = []
          letters = string.letters[26:] + string.letters[:26]
      
          def __init__(self, name, formula):
              self.name = name
              self.formula = formula
              Selection.selections.append(self)
      
          def __mul__(self, selection):
              name = 'selection' + letters[len(selections)]
              return Selection(name, self.name + ' and ' + selection.name)
      
          @classmethod
          def generate(c):
              code = []
              for selection in c.selections:
                  code.append('bool ')
                  code.append(selection.name)
                  code.append(' = ')
                  code.append(selection.formula)
                  code.append(';\n')
      
              code.append('\n')
      
              for selection in c.selections:
                  code.append('if (')
                  code.append(selection.name)
                  code.append(') { histo_')
                  code.append(selection.name)
                  code.append('->Fill(event); }\n')
      
              return ''.join(code)
      

      这当然有效,假设您只有 52 个选择对象,但该限制仅存在,因为此类仅生成表单选择 [A-Za-z] 的名称

      【讨论】:

        【解决方案4】:

        那么,如果我正确理解了您的示例,您是在创建一组 Selection 对象,然后使用它们生成代码?

        首先,为什么不直接用 C++ 编写代码呢?事实上,您将 C++ 表达式作为字符串变量嵌入到 Python 中,并使用重载数学运算符来构造布尔表达式(事实上,您觉得需要评论 * 表示 AND 表明这是一个糟糕的选择)?简直丑爆了!

        话虽如此,您拥有所需的所有信息——在 Python 代码中,selectionA 知道它的名字是“selectionA”,而 selectionB 知道它的名字是“selectionB”。唯一的问题是,您没有提供足够的上下文来了解对象 selectionC 的类型。我假设它类似于 AndExpression,并持有引用 selectionA 和 selectionB(可能是 param1 和 param2?)。让它输出"(" + self.param1.name + " && " + self.param2.name + ")"

        【讨论】:

        • 我正在使用 python 生成 C++ 代码,因为代码非常无聊、简单、重复,但非常长(10000+ 行)。 Python代码生成C++代码,编译它,并行执行一些不同参数的程序实例,并使用它们的输出。
        • 在python中你不能重载and和or运算符,因为它们很懒所以你需要使用别的东西,它不是那么难看
        • 是的,但没那么简单。关键是你需要知道你必须在selectionC之前声明selectionAselectionB。我的例子是微不足道的,现实生活不是。
        • 嗯,也许有更好的方法来编写 C++ 代码?真的,如果你发现自己写了 10000 多行“无聊、简单、重复,但很长”的代码,那么你就做错了。
        • 另外,我知道您不能在 Python 中覆盖 andor。但关键是,如果您需要解释覆盖的含义,那么它可能不是合适的覆盖——请改用方法。
        猜你喜欢
        • 2023-03-23
        • 2018-06-04
        • 2015-04-19
        • 2011-07-14
        • 2011-09-19
        • 2021-08-17
        • 2015-12-16
        • 2012-04-25
        • 2021-05-06
        相关资源
        最近更新 更多