コード例 #1
0
    def update(self, sample: GrainSizeSample, distribution: BaseDistribution,
               func_args: typing.Iterable[float], fraction: float):
        self.__func_args = func_args
        if np.any(np.isnan(func_args)):
            self.__fraction = np.nan
            self.__distribution = np.full_like(sample.distribution,
                                               fill_value=np.nan)
            self.__geometric_moments = INVALID_STATISTIC
            self.__logarithmic_moments = INVALID_STATISTIC
            self.__is_valid = False
        else:
            self.__fraction = fraction
            self.__distribution = distribution.single_function(
                sample.classes_φ, *func_args)
            self.__geometric_moments = geometric(sample.classes_μm,
                                                 self.__distribution)
            self.__logarithmic_moments = logarithmic(sample.classes_φ,
                                                     self.__distribution)

            values_to_check = [self.__fraction]
            values_to_check.extend(self.__distribution)
            keys = ["mean", "std", "skewness", "kurtosis"]
            for key in keys:
                values_to_check.append(self.__geometric_moments[key])
                values_to_check.append(self.__logarithmic_moments[key])
            values_to_check = np.array(values_to_check)
            # if any value is nan of inf, this result is invalid
            if np.any(np.isnan(values_to_check) | np.isinf(values_to_check)):
                self.__is_valid = False
            else:
                self.__is_valid = True
コード例 #2
0
 def get_distance(self, distance: str):
     distance_func = distance_func_numpy(distance)
     distribution = BaseDistribution.get_distribution(
         self.__distribution_type, self.__n_components)
     values = distribution.mixed_function(self.__sample.classes_φ,
                                          *self.__mixed_func_args)
     targets = self.__sample.distribution
     distance = distance_func(values, targets)
     return distance
コード例 #3
0
 def on_try_clicked(self):
     if self.last_task is None:
         return
     new_task = copy.copy(self.last_task)
     reference, fractions = self.expected
     initial_guess = BaseDistribution.get_initial_guess(
         self.last_task.distribution_type, reference, fractions=fractions)
     new_task.initial_guess = initial_guess
     self.async_worker.execute_task(new_task)
コード例 #4
0
 def setup_task(self, task: SSUTask):
     self.last_task = task
     self.try_button.setEnabled(True)
     if self.n_components != task.n_components:
         self.change_n_components(task.n_components)
     reference, fractions = self.expected
     initial_guess = BaseDistribution.get_initial_guess(
         task.distribution_type, reference, fractions=fractions)
     result = SSUResult(task, initial_guess)
     self.chart.show_model(result.view_model, quick=False)
コード例 #5
0
 def get_distance_series(self, distance: str):
     distance_func = distance_func_numpy(distance)
     distribution = BaseDistribution.get_distribution(
         self.__distribution_type, self.__n_components)
     distance_series = []
     for func_args in self.__history:
         values = distribution.mixed_function(self.__sample.classes_φ,
                                              *func_args)
         targets = self.__sample.distribution
         distance = distance_func(values, targets)
         distance_series.append(distance)
     return distance_series
コード例 #6
0
 def update_chart(self):
     if self.last_task is None:
         return
     reference, fractions = self.expected
     for comp_ref in reference:
         if comp_ref["std"] == 0.0:
             return
     # print(reference)
     initial_guess = BaseDistribution.get_initial_guess(
         self.last_task.distribution_type, reference, fractions=fractions)
     result = SSUResult(self.last_task, initial_guess)
     self.chart.show_model(result.view_model, quick=True)
コード例 #7
0
    def update(self, mixed_func_args: typing.Iterable[float]):
        distribution = BaseDistribution.get_distribution(
            self.__distribution_type, self.__n_components)

        if np.any(np.isnan(mixed_func_args)):
            self.__distribution = np.full_like(self.__sample.distribution,
                                               fill_value=np.nan)
            self.__is_valid = False
        else:
            self.__distribution = distribution.mixed_function(
                self.__sample.classes_φ, *mixed_func_args)
            unpacked_args = distribution.unpack_parameters(mixed_func_args)
            if len(self.__components) == 0:
                for func_args, fraction in unpacked_args:
                    component_result = ComponentResult(self.__sample,
                                                       distribution, func_args,
                                                       fraction)
                    self.__components.append(component_result)
            else:
                for component, (func_args,
                                fraction) in zip(self.__components,
                                                 unpacked_args):
                    component.update(self.__sample, distribution, func_args,
                                     fraction)
            # sort by mean φ values
            # reverse is necessary
            self.__components.sort(
                key=lambda component: component.logarithmic_moments["mean"],
                reverse=True)

            self.__is_valid = True
            if np.any(
                    np.isnan(self.__distribution)
                    | np.isinf(self.__distribution)):
                self.__is_valid = False
            for component in self.__components:
                if not component.is_valid:
                    self.__is_valid = False
                    break
コード例 #8
0
    def try_fit(self, task: SSUTask) -> typing.Tuple[FittingState, object]:
        assert task.resolver == "classic"
        history = []
        distribution = BaseDistribution.get_distribution(
            task.distribution_type, task.n_components)
        if task.resolver_setting is None:
            setting = ClassicResolverSetting()
        else:
            assert isinstance(task.resolver_setting, ClassicResolverSetting)
            setting = task.resolver_setting
        distance = distance_func_numpy(setting.distance)
        start_time = time.time()
        self.on_fitting_started()
        use_weights = False
        if use_weights:
            weights = self.get_weights(task.sample.classes_φ,
                                       task.sample.distribution)

            def closure(params):
                params[-task.n_components:] = np.abs(
                    params[-task.n_components:])
                current_values = distribution.mixed_function(
                    task.sample.classes_φ, *params)
                return distance(current_values * weights,
                                task.sample.distribution * weights)
        else:

            def closure(params):
                params[-task.n_components:] = np.abs(
                    params[-task.n_components:])
                current_values = distribution.mixed_function(
                    task.sample.classes_φ, *params)
                return distance(current_values, task.sample.distribution)

        def local_callback(mixed_func_args, *addtional):
            history.append(mixed_func_args)
            self.local_iteration_callback(mixed_func_args)

        initial_guess = task.initial_guess
        if task.initial_guess is None:
            initial_guess = np.array(distribution.defaults)

        if task.reference is not None:
            assert len(task.reference) == task.n_components
            initial_guess = BaseDistribution.get_initial_guess(
                task.distribution_type, task.reference)

        if setting.minimizer == "trust-constr":
            GO_options = {
                "maxiter": setting.GO_minimizer_max_niter,
                #    "ftol": setting.GO_minimizer_ftol,
                "disp": False
            }
            FLO_options = {
                "maxiter": setting.FLO_max_niter,
                #    "ftol": setting.FLO_ftol,
                "disp": False
            }
        else:
            GO_options = {
                "maxiter": setting.GO_minimizer_max_niter,
                "ftol": setting.GO_minimizer_ftol,
                "disp": False
            }
            FLO_options = {
                "maxiter": setting.FLO_max_niter,
                "ftol": setting.FLO_ftol,
                "disp": False
            }

        if setting.try_GO:
            global_optimization_minimizer_kwargs = \
                dict(method=setting.minimizer,
                     tol=setting.GO_minimizer_tol,
                     bounds=distribution.bounds,
                     constraints=distribution.constrains,
                     callback=local_callback,
                     options=GO_options)

            GO_result = \
                basinhopping(closure, x0=initial_guess,
                            minimizer_kwargs=global_optimization_minimizer_kwargs,
                            callback=self.global_iteration_callback,
                            niter_success=setting.GO_success_niter,
                            niter=setting.GO_max_niter,
                            stepsize=setting.GO_step)

            if GO_result.lowest_optimization_result.success or \
                    GO_result.lowest_optimization_result.status == 9:
                self.on_global_fitting_succeeded(GO_result)
                initial_guess = GO_result.x
            else:
                self.on_global_fitting_failed(GO_result)
                self.on_fitting_finished()
                return FittingState.Failed, GO_result

        FLO_result = \
            minimize(closure, method=setting.minimizer,
                    x0=initial_guess,
                    tol=setting.FLO_tol,
                    bounds=distribution.bounds,
                    constraints=distribution.constrains,
                    callback=local_callback,
                    options=FLO_options)
        # judge if the final fitting succeed
        # see https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fmin_slsqp.html
        # When the minimizer is "Nelder-Mead", it will return failed result if it has reached the max niter
        if FLO_result.success or FLO_result.status == 9 or setting.minimizer == "Nelder-Mead" or setting.minimizer == "trust-constr":
            finish_time = time.time()
            self.on_fitting_finished()
            time_spent = finish_time - start_time
            fitting_result = SSUResult(task,
                                       FLO_result.x,
                                       history=history,
                                       time_spent=time_spent)
            self.on_fitting_succeeded(FLO_result, fitting_result)
            return FittingState.Succeeded, fitting_result
        else:
            self.on_final_fitting_failed(FLO_result)
            self.on_fitting_finished()
            return FittingState.Failed, FLO_result
コード例 #9
0
def get_initial_guess(distribution_type: DistributionType, reference):
    return BaseDistribution.get_initial_guess(distribution_type, reference)