Example #1
0
    def _flatten_structures(self):
        c_specs, self.edges, self.weights, self.einstrs, self.einpaths = [], [], [], [], []
        ks = {}

        # handle n=1 case specially
        c_specs.append([1,0,0,0,0,1,1,0])
        self.edges.append(())
        self.weights.append(())
        self.einstrs.append(self.einstrs_d[(1,0)][0])
        self.einpaths.append(self.einpaths_d[(1,0)][0])

        for ne in sorted(self.edges_d.keys()):
            n, e = ne
            z = zip(self.edges_d[ne], self.weights_d[ne], self.chis_d[ne],
                    self.einstrs_d[ne], self.einpaths_d[ne])
            for edgs, ws, c, es, ep in z:
                for w in ws:
                    d = sum(w)
                    k = ks.setdefault((n,d), 0)
                    ks[(n,d)] += 1
                    vs = valencies(EFPElem(edgs, weights=w).edges).values()
                    v = max(vs)
                    h = Counter(vs)[1]
                    c_specs.append([n, e, d, v, k, c, 1, h])
                    self.edges.append(edgs)
                    self.weights.append(w)
                    self.einstrs.append(es)
                    self.einpaths.append(ep)
        self.c_specs = np.asarray(c_specs)
Example #2
0
    def __init__(self,
                 edges,
                 measure='hadr',
                 beta=1,
                 kappa=1,
                 normed=True,
                 coords=None,
                 check_input=True,
                 np_optimize='greedy'):
        """
        **Arguments**

        - **edges** : _list_
            - Edges of the EFP graph specified by pairs of vertices.
        - **measure** : {`'hadr'`, `'hadrdot'`, `'ee'`}
            - The choice of measure. See [Measures](../measures) 
            for additional info.
        - **beta** : _float_
            - The parameter $\\beta$ appearing in the measure.
            Must be greater than zero.
        - **kappa** : {_float_, `'pf'`}
            - If a number, the energy weighting parameter $\\kappa$.
            If `'pf'`, use $\\kappa=v-1$ where $v$ is the valency of the vertex.
        - **normed** : _bool_
            - Controls normalization of the energies in the measure.
        - **coords** : {`'ptyphim'`, `'epxpypz'`, `None`}
            - Controls which coordinates are assumed for the input. See 
            [Measures](../measures) for additional info.
        - **check_input** : _bool_
            - Whether to check the type of the input each time or assume
            the first input type.
        - **np_optimize** : {`True`, `False`, `'greedy'`, `'optimal'`}
            - The `optimize` keyword of `numpy.einsum_path`.
        """

        # initialize EFPBase
        super(EFP, self).__init__(measure, beta, kappa, normed, coords,
                                  check_input)

        # store these edges as an EFPElem
        self.efpelem = EFPElem(edges)
        self._np_optimize = np_optimize

        # setup ve for standard efp compute
        (self.efpelem.einstr, self.efpelem.einpath,
         self.chi) = VariableElimination(np_optimize).einspecs(
             self.simple_graph, self.n)
Example #3
0
class EFP(EFPBase):
    """A class for representing and computing a single EFP. Note that all
    keyword arguments are stored as properties of the `EFP` instance.
    """
    def __init__(self,
                 edges,
                 measure='hadr',
                 beta=1,
                 kappa=1,
                 normed=True,
                 coords=None,
                 check_input=True,
                 np_optimize='greedy'):
        """
        **Arguments**

        - **edges** : _list_
            - Edges of the EFP graph specified by pairs of vertices.
        - **measure** : {`'hadr'`, `'hadrdot'`, `'ee'`}
            - The choice of measure. See [Measures](../measures) 
            for additional info.
        - **beta** : _float_
            - The parameter $\\beta$ appearing in the measure.
            Must be greater than zero.
        - **kappa** : {_float_, `'pf'`}
            - If a number, the energy weighting parameter $\\kappa$.
            If `'pf'`, use $\\kappa=v-1$ where $v$ is the valency of the vertex.
        - **normed** : _bool_
            - Controls normalization of the energies in the measure.
        - **coords** : {`'ptyphim'`, `'epxpypz'`, `None`}
            - Controls which coordinates are assumed for the input. See 
            [Measures](../measures) for additional info.
        - **check_input** : _bool_
            - Whether to check the type of the input each time or assume
            the first input type.
        - **np_optimize** : {`True`, `False`, `'greedy'`, `'optimal'`}
            - The `optimize` keyword of `numpy.einsum_path`.
        """

        # initialize EFPBase
        super(EFP, self).__init__(measure, beta, kappa, normed, coords,
                                  check_input)

        # store these edges as an EFPElem
        self.efpelem = EFPElem(edges)
        self._np_optimize = np_optimize

        # setup ve for standard efp compute
        (self.efpelem.einstr, self.efpelem.einpath,
         self.chi) = VariableElimination(np_optimize).einspecs(
             self.simple_graph, self.n)

    #===============
    # public methods
    #===============

    # compute(event=None, zs=None, thetas=None)
    def compute(self, event=None, zs=None, thetas=None, batch_call=None):
        """Computes the value of the EFP on a single event.

        **Arguments**

        - **event** : 2-d array_like or `fastjet.PseudoJet`
            - The event as an array of particles in the coordinates specified
            by `coords`.
        - **zs** : 1-d array_like
            - If present, `thetas` must also be present, and `zs` is used in place 
            of the energies of an event.
        - **thetas** : 2-d array_like
            - If present, `zs` must also be present, and `thetas` is used in place 
            of the pairwise angles of an event.

        **Returns**

        - _float_
            - The EFP value.
        """

        zs, thetas_dict = self.get_zs_thetas_dict(event, zs, thetas)
        return self.efpelem.compute(zs, thetas_dict)

    #===========
    # properties
    #===========

    @property
    def _weight_set(self):
        """Set of edge weights for the graph of this EFP."""

        return self.efpelem.weight_set

    @property
    def _einstr(self):
        """Einstein summation string for the EFP computation."""

        return self.efpelem.einstr

    @property
    def _einpath(self):
        """Numpy einsum path specification for EFP computation."""

        return self.efpelem.einpath

    @property
    def np_optimize(self):
        """The np_optimize keyword argument that initialized this EFP instance."""

        return self._np_optimize

    @property
    def graph(self):
        """Graph of this EFP represented by a list of edges."""

        return self.efpelem.edges

    @property
    def simple_graph(self):
        """Simple graph of this EFP (forgetting all multiedges)
        represented by a list of edges."""

        return self.efpelem.simple_edges

    @property
    def n(self):
        """Number of vertices in the graph of this EFP."""

        return self.efpelem.n

    @property
    def d(self):
        """Degree, or number of edges, in the graph of this EFP."""

        return self.efpelem.d

    @property
    def e(self):
        """Number of edges in the simple graph of this EFP."""

        return self.efpelem.e

    @property
    def c(self):
        """VE complexity $\\chi$ of this EFP."""

        return self.chi
Example #4
0
    def __init__(self, *args, **kwargs):
        r"""EFPSet can be initialized in one of three ways (in order of precedence):

        1. **Default** - Use the ($d\le10$) EFPs that come installed with the
        `EnergFlow` package.
        2. **Generator** - Pass in a custom `Generator` object as the
        first positional argument.
        3. **Custom File** - Pass in the name of a `.npz` file saved
        with a custom `Generator`.

        To control which EFPs are included, `EFPSet` accepts an arbitrary
        number of specifications (see [`sel`](#sel)) and only EFPs meeting each
        specification are included in the set.

        **Arguments**

        - ***args** : _arbitrary positional arguments_
            - If the first positional argument is a `Generator` instance,
            it is used for initialization. The remaining positional
            arguments must be valid arguments to `sel`.
        - **filename** : _string_
            - Path to a `.npz` file which has been saved by a valid
            `energyflow.Generator`.
        - **measure** : {`'hadr'`, `'hadr-dot'`, `'ee'`}
            - See [Measures](../measures) for additional info.
        - **beta** : _float_
            - The parameter $\\beta$ appearing in the measure.
            Must be greater than zero.
        - **kappa** : {_float_, `'pf'`}
            - If a number, the energy weighting parameter $\\kappa$.
            If `'pf'`, use $\\kappa=v-1$ where $v$ is the valency of the vertex.
        - **normed** : _bool_
            - Controls normalization of the energies in the measure.
        - **coords** : {`'ptyphim'`, `'epxpypz'`, `None`}
            - Controls which coordinates are assumed for the input. See 
            [Measures](../measures) for additional info.
        - **check_input** : _bool_
            - Whether to check the type of the input each time or assume
            the first input type.
        - **verbose** : _bool_
            - Controls printed output when initializing EFPSet.
        """

        default_kwargs = {
            'filename': None,
            'measure': 'hadr',
            'beta': 1,
            'kappa': 1,
            'normed': True,
            'coords': None,
            'check_input': True,
            'verbose': False
        }
        measure_kwargs = [
            'measure', 'beta', 'kappa', 'normed', 'coords', 'check_input'
        ]

        # process arguments
        for k, v in default_kwargs.items():
            if k not in kwargs:
                kwargs[k] = v
            if k not in measure_kwargs:
                setattr(self, k, kwargs.pop(k))

        kwargs_check('__init__', kwargs, allowed=measure_kwargs)

        # initialize EFPBase
        super(EFPSet, self).__init__(*[kwargs[k] for k in measure_kwargs])

        # handle different methods of initialization
        maxs = ['nmax', 'emax', 'dmax', 'cmax', 'vmax', 'comp_dmaxs']
        elemvs = ['edges', 'weights', 'einstrs', 'einpaths']
        if len(args) >= 1 and isinstance(args[0], Generator):
            constructor_attrs = maxs + elemvs + [
                'cols', 'c_specs', 'disc_specs', 'disc_formulae'
            ]
            gen = {attr: getattr(args[0], attr) for attr in constructor_attrs}
            args = args[1:]
        elif self.filename is not None:
            self.filename += '.npz' if not self.filename.endswith(
                '.npz') else ''
            gen = np.load(self.filename, allow_pickle=True)
        else:
            gen = np.load(DEFAULT_EFP_FILE, allow_pickle=True)

        # compile regular expression for use in sel()
        self.SEL_RE = SEL_RE

        # put column headers and indices into namespace
        self._cols = gen['cols']
        self._set_col_inds()

        # put gen maxs into dict
        self.gen_maxs = {m: gen[m] for m in maxs}

        # get disc formulae and disc mask
        orig_disc_specs = gen['disc_specs']
        disc_mask = self.sel(*args, specs=orig_disc_specs)
        self.disc_formulae = gen['disc_formulae'][disc_mask]

        # get connected specs and full specs
        orig_c_specs = gen['c_specs']
        c_mask = self.sel(*args, specs=orig_c_specs)
        self._cspecs = orig_c_specs[c_mask]
        self._specs = concat_specs(self._cspecs, orig_disc_specs[disc_mask])

        # make EFPElem list
        z = zip(*([gen[v] for v in elemvs] + [orig_c_specs[:, self.k_ind]]))
        self.efpelems = [
            EFPElem(*args) for m, args in enumerate(z) if c_mask[m]
        ]

        # union over all weights needed
        self.__weight_set = frozenset(w for efpelem in self.efpelems
                                      for w in efpelem.weight_set)

        # get col indices for disconnected formulae
        connected_ndk = {
            efpelem.ndk: i
            for i, efpelem in enumerate(self.efpelems)
        }
        self.disc_col_inds = []
        for formula in self.disc_formulae:
            try:
                self.disc_col_inds.append(
                    [connected_ndk[factor] for factor in formula])
            except KeyError:
                warnings.warn(
                    'connected efp needed for {} not found'.format(formula))

        # handle printing
        if self.verbose:
            print('Originally Available EFPs:')
            self.print_stats(specs=concat_specs(orig_c_specs, orig_disc_specs),
                             lws=2)
            if len(args) > 0:
                print('Currently Stored EFPs:')
                self.print_stats(lws=2)