''' This file is part of PM4Py (More Info: https://pm4py.fit.fraunhofer.de). PM4Py is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PM4Py is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PM4Py. If not, see . ''' import numpy as np from pm4py.objects.random_variables.constant0.random_variable import Constant0 from pm4py.objects.random_variables.deterministic.random_variable import Deterministic from pm4py.objects.random_variables.exponential.random_variable import Exponential from pm4py.objects.random_variables.normal.random_variable import Normal from pm4py.objects.random_variables.uniform.random_variable import Uniform from pm4py.objects.random_variables.lognormal.random_variable import LogNormal from pm4py.objects.random_variables.gamma.random_variable import Gamma 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 == "LOGNORMAL": self.random_variable = LogNormal() self.random_variable.read_from_string(distribution_parameters) elif distribution_type == "GAMMA": self.random_variable = Gamma() self.random_variable.read_from_string(distribution_parameters) elif distribution_type == "DETERMINISTIC": self.random_variable = Deterministic() 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() lognormal = LogNormal() gamma = Gamma() 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"