示例#1
0
    def build_problem(self):
        """
        Build the linear programming problem
        """

        for trans in self.smap:
            rv = self.smap[trans]
            if rv.get_transition_type() == "IMMEDIATE":
                new_rv = Exponential()
                new_rv.scale = DEFAULT_REPLACEMENT_IMMEDIATE
                self.smap[trans] = new_rv
        aeq_1, beq_1, aub_1, bub_1 = self.build_1_throughput()
        aeq_2, beq_2, aub_2, bub_2 = self.build_2_flowbalance()
        aeq_3, beq_3, aub_3, bub_3 = self.build_3_secondmoment()
        aeq_4, beq_4, aub_4, bub_4 = self.build_4_populationcovariance()
        aeq_5, beq_5, aub_5, bub_5 = self.build_5_liveness()
        aeq_6, beq_6, aub_6, bub_6 = self.build_6_liveness()
        aeq_18, beq_18, aub_18, bub_18 = self.build_18_samplepath()
        aeq_19, beq_19, aub_19, bub_19 = self.build_19_samplepath()
        aeq_21, beq_21, aub_21, bub_21 = self.build_21_samplepath()
        aeq_22, beq_22, aub_22, bub_22 = self.build_22_samplepath()
        aeq_26, beq_26, aub_26, bub_26 = self.build_26_littlelaw()
        aeq_general, beq_general, aub_general, bub_general = self.build_general_cond()

        self.Aeq = np.vstack(
            (aeq_1, aeq_2, aeq_3, aeq_4, aeq_5, aeq_6, aeq_18, aeq_19, aeq_21, aeq_22, aeq_26, aeq_general))
        self.beq = np.vstack(
            (beq_1, beq_2, beq_3, beq_4, beq_5, beq_6, beq_18, beq_19, beq_21, beq_22, beq_26, beq_general))
        self.Aub = np.vstack(
            (aub_1, aub_2, aub_3, aub_4, aub_5, aub_6, aub_18, aub_19, aub_21, aub_22, aub_26, aub_general))
        self.bub = np.vstack(
            (bub_1, bub_2, bub_3, bub_4, bub_5, bub_6, bub_18, bub_19, bub_21, bub_22, bub_26, bub_general))

        self.Aeq, self.beq = aeq_redundant_fix.remove_redundant_rows(self.Aeq, self.beq)

        if DEFAULT_LP_SOLVER_VARIANT == lp_solver.CVXOPT:
            self.Aeq = np.transpose(self.Aeq.astype(np.float64)).tolist()
            self.beq = np.transpose(self.beq.astype(np.float64)).tolist()
            self.Aub = np.transpose(self.Aub.astype(np.float64)).tolist()
            self.bub = np.transpose(self.bub.astype(np.float64)).tolist()
    def read_from_string(self, distribution_type, distribution_parameters):
        """
        Read the random variable from string

        Parameters
        -----------
        distribution_type
            Distribution type
        distribution_parameters
            Distribution parameters splitted by ;
        """
        if distribution_type == "NORMAL":
            self.random_variable = Normal()
            self.random_variable.read_from_string(distribution_parameters)
        elif distribution_type == "UNIFORM":
            self.random_variable = Uniform()
            self.random_variable.read_from_string(distribution_parameters)
        elif distribution_type == "EXPONENTIAL":
            self.random_variable = Exponential()
            self.random_variable.read_from_string(distribution_parameters)
        elif distribution_type == "IMMEDIATE":
            self.random_variable = Constant0()
    def transform_net(self, net0, initial_marking0, final_marking0, s_map,
                      avg_time_starts):
        """
        Transform the source Petri net removing the initial and final marking, and connecting
        to each "initial" place a hidden timed transition mimicking the case start

        Parameters
        -------------
        net0
            Initial Petri net provided to the object
        initial_marking0
            Initial marking of the Petri net provided to the object
        final_marking0
            Final marking of the Petri net provided to the object
        s_map
            Stochastic map of transitions (EXPONENTIAL distribution since we assume a Markovian process)
        avg_time_starts
            Average time interlapsed between case starts

        Returns
        -------------
        net
            Petri net that will be simulated
        initial_marking
            Initial marking of the Petri net that will be simulated (empty)
        final_marking
            Final marking of the Petri net that will be simulated (empty)
        s_map
            Stochastic map of transitions enriched by new hidden case-generator transitions
        """
        # copy the Petri net object (assure that we do not change the original Petri net)
        [net1, initial_marking1,
         final_marking1] = copy([net0, initial_marking0, final_marking0])
        # on the copied Petri net, add a sucking transition for the final marking
        for index, place in enumerate(final_marking1):
            suck_transition = PetriNet.Transition(
                "SUCK_TRANSITION" + str(index), None)
            net1.transitions.add(suck_transition)
            add_arc_from_to(place, suck_transition, net1)
            hidden_generator_distr = Exponential()
            hidden_generator_distr.scale = avg_time_starts
            s_map[suck_transition] = hidden_generator_distr
        # on the copied Petri net, remove both the place(s) in the initial marking and
        # the immediate transitions that are connected to it.
        target_places = []
        for place in initial_marking1:
            out_arcs = list(place.out_arcs)
            for target_arc in out_arcs:
                target_trans = target_arc.target
                if len(target_trans.in_arcs) == 1:
                    out_arcs_lev2 = list(target_trans.out_arcs)
                    for arc in out_arcs_lev2:
                        target_place = arc.target
                        target_places.append(target_place)
                    net1 = remove_transition(net1, target_trans)
            net1 = remove_place(net1, place)
        # add hidden case-generation transitions to the model.
        # all places that are left orphan by the previous operation are targeted.
        for index, place in enumerate(target_places):
            hidden_generator_trans = PetriNet.Transition(
                "HIDDEN_GENERATOR_TRANS" + str(index), None)
            net1.transitions.add(hidden_generator_trans)
            add_arc_from_to(hidden_generator_trans, place, net1)
            hidden_generator_distr = Exponential()
            hidden_generator_distr.scale = avg_time_starts
            s_map[hidden_generator_trans] = hidden_generator_distr
        # the simulated Petri net is assumed to start from an empty initial and final marking
        initial_marking = Marking()
        final_marking = Marking()
        return net1, initial_marking, final_marking, s_map
    def calculate_parameters(self,
                             values,
                             parameters=None,
                             force_distribution=None):
        """
        Calculate parameters of the current distribution

        Parameters
        -----------
        values
            Empirical values to work on
        parameters
            Possible parameters of the algorithm
        force_distribution
            If provided, distribution to force usage (e.g. EXPONENTIAL)

        """

        if parameters is None:
            parameters = {}

        debug_mode = parameters["debug"] if "debug" in parameters else False

        if self.random_variable is not None:
            self.random_variable.calculate_parameters(values)
        else:
            norm = Normal()
            unif = Uniform()
            expon = Exponential()
            constant = Constant0()

            if not force_distribution or not force_distribution == "EXPONENTIAL":
                likelihoods = list()
                likelihoods.append(
                    [constant,
                     constant.calculate_loglikelihood(values)])
                if force_distribution == "NORMAL" or force_distribution is None:
                    norm.calculate_parameters(values)
                    likelihoods.append(
                        [norm, norm.calculate_loglikelihood(values)])
                if force_distribution == "UNIFORM" or force_distribution is None:
                    unif.calculate_parameters(values)
                    likelihoods.append(
                        [unif, unif.calculate_loglikelihood(values)])
                if force_distribution == "EXPONENTIAL" or force_distribution is None:
                    expon.calculate_parameters(values)
                    likelihoods.append(
                        [expon, expon.calculate_loglikelihood(values)])
                likelihoods = [x for x in likelihoods if str(x[1]) != 'nan']
                likelihoods = sorted(likelihoods,
                                     key=lambda x: x[1],
                                     reverse=True)

                if debug_mode:
                    print("likelihoods = ", likelihoods)

                self.random_variable = likelihoods[0][0]
            else:
                avg_values = np.average(values)
                if values and avg_values > 0.00000:
                    expon.scale = avg_values
                    self.random_variable = expon
                else:
                    self.random_variable = constant
class RandomVariable(object):
    def __init__(self):
        self.random_variable = None

    def read_from_string(self, distribution_type, distribution_parameters):
        """
        Read the random variable from string

        Parameters
        -----------
        distribution_type
            Distribution type
        distribution_parameters
            Distribution parameters splitted by ;
        """
        if distribution_type == "NORMAL":
            self.random_variable = Normal()
            self.random_variable.read_from_string(distribution_parameters)
        elif distribution_type == "UNIFORM":
            self.random_variable = Uniform()
            self.random_variable.read_from_string(distribution_parameters)
        elif distribution_type == "EXPONENTIAL":
            self.random_variable = Exponential()
            self.random_variable.read_from_string(distribution_parameters)
        elif distribution_type == "IMMEDIATE":
            self.random_variable = Constant0()

    def get_distribution_type(self):
        """
        Get current distribution type

        Returns
        -----------
        distribution_type
            String representing the distribution type
        """
        if self.random_variable is not None:
            return self.random_variable.get_distribution_type()

    def get_transition_type(self):
        """
        Get the type of transition associated to the current distribution

        Returns
        -----------
        transition_type
            String representing the type of the transition
        """
        if self.random_variable is not None:
            return self.random_variable.get_transition_type()

    def get_distribution_parameters(self):
        """
        Get a string representing distribution parameters

        Returns
        -----------
        distribution_parameters
            String representing distribution parameters
        """
        if self.random_variable is not None:
            return self.random_variable.get_distribution_parameters()

    def calculate_loglikelihood(self, values):
        """
        Calculate log likelihood

        Parameters
        ------------
        values
            Empirical values to work on

        Returns
        ------------
        likelihood
            Log likelihood that the values follows the distribution
        """
        if self.random_variable is not None:
            return self.random_variable.calculate_loglikelihood(values)

    def calculate_parameters(self,
                             values,
                             parameters=None,
                             force_distribution=None):
        """
        Calculate parameters of the current distribution

        Parameters
        -----------
        values
            Empirical values to work on
        parameters
            Possible parameters of the algorithm
        force_distribution
            If provided, distribution to force usage (e.g. EXPONENTIAL)

        """

        if parameters is None:
            parameters = {}

        debug_mode = parameters["debug"] if "debug" in parameters else False

        if self.random_variable is not None:
            self.random_variable.calculate_parameters(values)
        else:
            norm = Normal()
            unif = Uniform()
            expon = Exponential()
            constant = Constant0()

            if not force_distribution or not force_distribution == "EXPONENTIAL":
                likelihoods = list()
                likelihoods.append(
                    [constant,
                     constant.calculate_loglikelihood(values)])
                if force_distribution == "NORMAL" or force_distribution is None:
                    norm.calculate_parameters(values)
                    likelihoods.append(
                        [norm, norm.calculate_loglikelihood(values)])
                if force_distribution == "UNIFORM" or force_distribution is None:
                    unif.calculate_parameters(values)
                    likelihoods.append(
                        [unif, unif.calculate_loglikelihood(values)])
                if force_distribution == "EXPONENTIAL" or force_distribution is None:
                    expon.calculate_parameters(values)
                    likelihoods.append(
                        [expon, expon.calculate_loglikelihood(values)])
                likelihoods = [x for x in likelihoods if str(x[1]) != 'nan']
                likelihoods = sorted(likelihoods,
                                     key=lambda x: x[1],
                                     reverse=True)

                if debug_mode:
                    print("likelihoods = ", likelihoods)

                self.random_variable = likelihoods[0][0]
            else:
                avg_values = np.average(values)
                if values and avg_values > 0.00000:
                    expon.scale = avg_values
                    self.random_variable = expon
                else:
                    self.random_variable = constant

    def get_value(self):
        """
        Get a random value following the distribution

        Returns
        -----------
        value
            Value obtained following the distribution
        """
        if self.random_variable is not None:
            return self.random_variable.get_value()

    def get_values(self, no_values=400):
        """
        Get some random values following the distribution

        Parameters
        -----------
        no_values
            Number of values to return

        Returns
        ----------
        values
            Values extracted according to the probability distribution
        """
        if self.random_variable is not None:
            return self.random_variable.get_values(no_values=no_values)

    def get_weight(self):
        """
        Getter of weight

        Returns
        ----------
        weight
            Weight of the transition
        """
        if self.random_variable is not None:
            return self.random_variable.get_weight()

    def set_weight(self, weight):
        """
        Setter of the weight

        Parameters
        -----------
        weight
            Weight of the transition
        """
        if self.random_variable is not None:
            self.random_variable.set_weight(weight)

    def get_priority(self):
        """
        Getter of the priority

        Returns
        -----------
        priority
            Priority of the transition
        """
        if self.random_variable is not None:
            return self.random_variable.get_priority()

    def set_priority(self, priority):
        """
        Setter of the priority variable

        Parameters
        ------------
        priority
            Priority of the transition
        """
        if self.random_variable is not None:
            self.random_variable.set_priority(priority)

    def __str__(self):
        """
        Returns a representation of the current object

        Returns
        ----------
        repr
            Representation of the current object
        """
        if self.random_variable is not None:
            return str(self.random_variable)
        else:
            return "UNINITIALIZED"

    def __repr__(self):
        """
        Returns a representation of the current object

        Returns
        ----------
        repr
            Representation of the current object
        """
        if self.random_variable is not None:
            return repr(self.random_variable)
        else:
            return "UNINITIALIZED"