def visit_Call_Aggregate_only(self, node: ast.Call):
        '''
        - (acc lambda): the accumulator is set to the first element, and the lambda is called to
                        update it after that. This is called `agg_only`.
        '''
        agg_lambda = node.args[0]

        # Get the sequence we are calling against and the accumulator
        seq = self.as_sequence(node.func.value)
        accumulator, accumulator_scope = self.create_accumulator(seq)

        # We have to do a simple if statement here so that the first time through we can set the
        # accumulator, and the second time we can add to it.

        is_first_iter = crep.cpp_variable(unique_name("is_first"),
                                          self._gc.current_scope(),
                                          cpp_type=ctyp.terminal('bool'),
                                          initial_value=crep.cpp_value(
                                              'true', self._gc.current_scope(),
                                              ctyp.terminal('bool')))
        accumulator_scope.declare_variable(is_first_iter)

        # Set the scope where we will be doing the accumulation
        sv = seq.sequence_value()
        if isinstance(sv, crep.cpp_sequence):
            self._gc.set_scope(sv.iterator_value().scope()[-1])
        else:
            self._gc.set_scope(sv.scope())

        # Code up if statement to select out the first element.
        if_first = statement.iftest(is_first_iter)
        self._gc.add_statement(if_first)
        self._gc.add_statement(
            statement.set_var(
                is_first_iter,
                crep.cpp_value("false", self._gc.current_scope(),
                               ctyp.terminal('bool'))))

        # Set the accumulator
        self._gc.add_statement(
            statement.set_var(accumulator, seq.sequence_value()))
        self._gc.pop_scope()

        # Now do the if statement and make the call to calculate the accumulation.
        self._gc.add_statement(statement.elsephrase())
        call = ast.Call(
            func=agg_lambda,
            args=[accumulator.as_ast(),
                  seq.sequence_value().as_ast()])
        self._gc.add_statement(
            statement.set_var(accumulator, self.get_rep(call)))

        # Finally, since this is a terminal, we need to pop off the top.
        self._gc.set_scope(accumulator_scope)

        # Cache the results in our result in case we are skipping nodes in the AST.
        node.rep = accumulator
        self._result = accumulator
def test_deepest_scope_equal():
    g = generated_code()
    s1 = statement.iftest("true")
    s2 = statement.set_var("v1", "true")
    g.add_statement(s1)
    scope_1 = g.current_scope()

    v1 = crep.cpp_value("v1", scope_1, ctyp.terminal('int'))
    v2 = crep.cpp_value("v2", scope_1, ctyp.terminal('int'))

    assert v1 == deepest_scope(v1, v2)
    assert v2 == deepest_scope(v2, v1)
    def visit_IfExp(self, node):
        r'''
        We'd like to be able to use the "?" operator in C++, but the
        problem is lazy evaluation. It could be when we look at one or the
        other item, a bunch of prep work has to be done - and that will
        show up in separate statements. So we have to use if/then/else with
        a result value.
        '''

        # The result we'll store everything in.
        result = crep.cpp_variable(unique_name("if_else_result"),
                                   self._gc.current_scope(),
                                   cpp_type=ctyp.terminal("double"))
        self._gc.declare_variable(result)

        # We always have to evaluate the test.
        current_scope = self._gc.current_scope()
        test_expr = self.get_rep(node.test)
        self._gc.add_statement(statement.iftest(test_expr))
        if_scope = self._gc.current_scope()

        # Next, we do the true and false if statement.
        self._gc.add_statement(
            statement.set_var(result, self.get_rep(node.body)))
        self._gc.set_scope(if_scope)
        self._gc.pop_scope()
        self._gc.add_statement(statement.elsephrase())
        self._gc.add_statement(
            statement.set_var(result, self.get_rep(node.orelse)))
        self._gc.set_scope(current_scope)

        # Done, the result is the rep of this node!
        node.rep = result
        self._result = result
def determine_type_mf(parent_type, function_name):
    '''
    Determine the return type of the member function. Do our best to make
    an intelligent case when we can.

    parent_type:        the type of the parent
    function_name:      the name of the function we are calling
    '''
    # If we don't know the type...
    if parent_type is None:
        raise BaseException(
            "Internal Error: Trying to call member function for a type we do not know!"
        )
    # If we are doing one of the normal "terminals", then we can just bomb. This should not happen!

    rtn_type = ctyp.method_type_info(str(parent_type), function_name)
    if rtn_type is not None:
        return rtn_type

    # We didn't know it. Lets make a guess, and error out if we are clearly making a mistake.
    base_types = ['double', 'float', 'int']
    s_parent_type = str(parent_type)
    if s_parent_type in base_types:
        raise BaseException(
            "Unable to call method '{0}' on type '{1}'.".format(
                function_name, str(parent_type)))

    # Ok - we give up. Return a double.
    print(
        "Warning: assumping that the method '{0}.{1}(...)' has return type 'double'. Use cpp_types.add_method_type_info to suppress (or correct) this warning."
        .format(str(s_parent_type), function_name))
    return ctyp.terminal('double')
Esempio n. 5
0
def test_can_call_prodVtx():
    ctyp.add_method_type_info(
        "xAOD::TruthParticle", "prodVtx",
        ctyp.terminal('xAODTruth::TruthVertex', is_pointer=True))
    MyEventStream() \
        .Select("lambda e: e.TruthParticles('TruthParticles').Select(lambda t: t.prodVtx().x()).Sum()") \
        .AsROOTFile("n_jets") \
        .value()
    def visit_First(self, node):
        'We are in a sequence. Take the first element of the sequence and use that for future things.'

        # Make sure we are in a loop.
        seq = self.as_sequence(node.source)

        # The First terminal works by protecting the code with a if (first_time) {} block.
        # We need to declare the first_time variable outside the block where the thing we are
        # looping over here is defined. This is a little tricky, so we delegate to another method.
        loop_scope = seq.iterator_value().scope()
        outside_block_scope = loop_scope[-1]

        # Define the variable to track this outside that block.
        is_first = crep.cpp_variable(unique_name('is_first'),
                                     outside_block_scope,
                                     cpp_type=ctyp.terminal('bool'),
                                     initial_value=crep.cpp_value(
                                         'true', self._gc.current_scope(),
                                         ctyp.terminal('bool')))
        outside_block_scope.declare_variable(is_first)

        # Now, as long as is_first is true, we can execute things inside this statement.
        # The trick is putting the if statement in the right place. We need to locate it just one level
        # below where we defined the scope above.
        s = statement.iftest(is_first)
        s.add_statement(
            statement.set_var(
                is_first,
                crep.cpp_value('false', None, cpp_type=ctyp.terminal('bool'))))

        sv = seq.sequence_value()
        if isinstance(sv, crep.cpp_sequence):
            self._gc.set_scope(sv.iterator_value().scope()[-1])
        else:
            self._gc.set_scope(sv.scope())
        self._gc.add_statement(s)

        # If we just found the first sequence in a sequence, return that.
        # Otherwise return a new version of the value.
        first_value = sv if isinstance(
            sv, crep.cpp_sequence) else sv.copy_with_new_scope(
                self._gc.current_scope())

        node.rep = first_value
        self._result = first_value
    def visit_Compare(self, node):
        'A compare between two things. Python supports more than that, but not implemented yet.'
        if len(node.ops) != 1:
            raise BaseException("Do not support 1 < a < 10 comparisons yet!")

        left = self.get_rep(node.left)
        right = self.get_rep(node.comparators[0])

        r = crep.cpp_value(
            '({0}{1}{2})'.format(left.as_cpp(),
                                 compare_operations[type(node.ops[0])],
                                 right.as_cpp()), self._gc.current_scope(),
            ctyp.terminal("bool"))
        node.rep = r
        self._result = r
Esempio n. 8
0
    .SelectMany('lambda ev: ev[1].Select(lambda j1: (ev[0], j1, ev[2].Where(lambda tp2: DeltaR(tp2.eta(), tp2.phi(), j1.eta(), j1.phi()) < 0.4)))')

# Build us a list of columns
tc = track_columns()
tc.add_col('RunNumber', 'ji[0].runNumber()')
tc.add_col('EventNumber', 'ji[0].eventNumber()')

tc.add_col('JetPt', 'ji[1].pt()/1000.0')
tc.add_col('JetEta', 'ji[1].eta()')

# If it is signal, we can add a bunch of extra info
tc.add_col('IsLLP', 'ji[2].Count() > 0')
tc.add_col('LLP_Count', 'ji[2].Count()')
ctyp.add_method_type_info(
    "xAOD::TruthParticle", "prodVtx",
    ctyp.terminal('xAODTruth::TruthVertex', is_pointer=True))
ctyp.add_method_type_info(
    "xAOD::TruthParticle", "decayVtx",
    ctyp.terminal('xAODTruth::TruthVertex', is_pointer=True))
for c in ['x', 'y', 'z']:
    tc.add_col(
        'L{0}'.format(c),
        '0 if ji[2].Count() == 0 else abs(ji[2].First().prodVtx().{0}()-ji[2].First().decayVtx().{0}())'
        .format(c))

# The basic moments for the layer weights.
add_sampling_layer('EMM_BL0', 0, tc)
add_sampling_layer('EMM_BL1', 1, tc)
add_sampling_layer('EMM_BL2', 2, tc)
add_sampling_layer('EMM_BL3', 3, tc)
def getAttributeFloatAst(call_node: ast.Call):
    r'''
    Return an attribute on one of the xAOD objects.
    '''
    # Get the name of the moment out
    if len(call_node.args) != 1:
        raise BaseException("Calling getMomentFloat - only one argument is allowed")
    if type(call_node.args[0]) is not ast.Str:
        raise BaseException("Calling getMomentFloat - only acceptable argument is a string")

    r = cpp_ast.CPPCodeValue()
    # We don't need include files for this - just quick access
    r.args = ['moment_name',]
    r.replacement_instance_obj = ('obj_j', call_node.func.value.id)
    r.running_code += ['float result = obj_j->getAttribute<float>(moment_name);']
    r.result = 'result'
    r.result_rep = lambda sc: crep.cpp_variable(unique_name("jet_attrib"), scope=sc, cpp_type=ctyp.terminal('float'))

    # Replace it as the function that is going to get called.
    call_node.func = r

    return call_node
 def visit_Str(self, node):
     node.rep = crep.cpp_value('"{0}"'.format(node.s),
                               self._gc.current_scope(),
                               ctyp.terminal("string"))
     self._result = node.rep
Esempio n. 11
0
def test_expression_pointer_decl():
    e2 = crep.cpp_value("dude", top_level_scope(), ctyp.terminal("int"))
    assert False == e2.is_pointer()

    e3 = crep.cpp_value("dude", top_level_scope(), ctyp.terminal("int", is_pointer=True))
    assert True == e3.is_pointer()
Esempio n. 12
0
 def __init__(self, filename, treename, scope):
     cpp_value.__init__(self, unique_name("ttree_rep"), scope,
                        ctyp.terminal("ttreetfile"))
     self.filename = filename
     self.treename = treename
def guess_type_from_number(n):
    if int(n) == n:
        return ctyp.terminal("int")
    return ctyp.terminal("double")
Esempio n. 14
0
 def element_type(self):
     'Return the type of the elements in the collection'
     return ctyp.terminal(self._element_name, is_pointer=True)
Esempio n. 15
0
def DeltaRAst(call_node):
    r'''
    User is trying to call DeltaR (eta1, phi1, eta2, phi2). We turn this into a call
    into a call into ROOT that does the phi subtraction (I can never get that crap right).
    '''

    if len(call_node.args) != 4:
        raise BaseException("Calling DeltaR(eta1, phi1, eta2, phi2) has incorrect number of arguments")
    
    # Create an AST to hold onto all of this.
    r = cpp_ast.CPPCodeValue()
    # We need TVector2 included here
    r.include_files += ['TVector2.h', 'math.h']

    # We need all four arguments pushed through.
    r.args = ['eta1', 'phi1', 'eta2', 'phi2']
    
    # The code is three steps
    r.running_code += ['auto d_eta = eta1 - eta2;']
    r.running_code += ['auto d_phi = TVector2::Phi_mpi_pi(phi1-phi2);']
    r.running_code += ['auto result = sqrt(d_eta*d_eta + d_phi*d_phi);']
    r.result = 'result'
    r.result_rep = lambda sc: crep.cpp_variable(unique_name('delta_r'), scope=sc, cpp_type=ctyp.terminal('double'))

    call_node.func = r
    return call_node
def getAttributeVectorFloatAst(call_node: ast.Call):
    r'''
    Return a cpp ast accessing a vector of doubles for an xAOD attribute
    '''
    # Get the name of the moment out
    if len(call_node.args) != 1:
        raise BaseException("Calling getMomentFloat - only one argument is allowed")
    if type(call_node.args[0]) is not ast.Str:
        raise BaseException("Calling getMomentFloat - only acceptable argument is a string")

    r = cpp_ast.CPPCodeValue()
    r.include_files += ['vector']
    r.args = ['moment_name',]
    r.replacement_instance_obj = ('obj_j', call_node.func.value.id)
    r.running_code += ['auto result = obj_j->getAttribute<std::vector<double>>(moment_name);']
    r.result = 'result'
    r.result_rep = lambda sc: crep.cpp_collection(unique_name("jet_vec_attrib_"), scope=sc, collection_type=ctyp.collection(ctyp.terminal('double')))

    # Replace it as the function that is going to get called.
    call_node.func = r

    return call_node
Esempio n. 17
0
def test_method_type_found():
    ctyp.add_method_type_info("bogus", "pt", ctyp.terminal('double'))
    assert 'double' == str(ctyp.method_type_info("bogus", "pt"))
Esempio n. 18
0
def test_int_pointer():
    t_int = ctyp.terminal('int')
    assert False == t_int.is_pointer()
Esempio n. 19
0
 def __init__(self, filename, treename, scope):
     cpp_value.__init__(self, unique_name("pandas"), scope,
                        ctyp.terminal("pandasdf"))
     self.filename = filename
     self.treename = treename
Esempio n. 20
0
 def __init__(self, filename, treename, scope):
     cpp_value.__init__(self, unique_name("awk_array"), scope,
                        ctyp.terminal("awkwardarray"))
     self.filename = filename
     self.treename = treename