def simulate(self, rowid, query, constraints=None, inputs=None, N=None):
        """Return N iid samples of `targets` given `constraints` and `inputs`.

            (X_1, X_2, ... X_N) ~iid Pr[targets | constraints; inputs]

        rowid : int, or None to indicate a hypothetical row
            Specifies the identity of the population member whose posterior
            distribution over unobserved outputs to simulate from.

        query : list<int>
            List of `output` variables to simulate. If `rowid` corresponds to an
            existing member, it is an error for `targets` to contain any output
            variable for that `rowid` which has already been incorporated.

        constraints : dict{int:value}, optional
            The keys of `constraints` must be a subset of the `output`
            variables, and disjoint from the keys of `targets`. These
            constraints serve as probabilistic conditions on the multivariate
            output distribution. If `rowid` corresponds to an existing member,
            it is an error for `constraints` to contain any output variable for
            that `rowid` which has already been incorporated.

        inputs : dict{int:value}, optional
            The keys of `inputs` must contain all the cgpm's `input` variables,
            if any. These values comprise a full realization of all exogenous
            variables required by the cgpm. If `rowid` corresponds to an
            existing member, then `inputs` is expected to be None.

        N : int, (optional, default None)
            Number of samples to return. If None, returns a single sample as
            a dictionary with size len(query), where each key is an `output`
            variable and each value the sample for that dimension. If `N` is
            is not None, a size N list of dictionaries will be returned, each
            corresponding to a single sample.
        """
        raise NotImplementedError