iam-git / WellMet (public) (License: MIT) (since 2021-08-31) (hash sha1)
WellMet is pure Python framework for spatial structural reliability analysis. Or, more specifically, for "failure probability estimation and detection of failure surfaces by adaptive sequential decomposition of the design domain".

/IS_stat.py (dbc921a5ff53594363973972d53c5d572d2826d1) (18023 bytes) (mode 100644) (type blob)

#!/usr/bin/env python
# coding: utf-8

"""
"""


import numpy as np
import collections # for defaultdict
#from scipy import optimize # it was needed for spring solution
from .candybox import CandyBox
from scipy import stats # for sample_like()
from . import f_models # for sample_like()

# bisect function is taken from somewhere in internet. 
# https://www.quora.com/How-does-one-correctly-compare-two-floats-in-Python-to-test-if-they-are-equal
# Hope it is not big issue.
def bisect(f, target, low, high):
    low, high = float(low), float(high)
    while low != high:
        mid = (low + high) / 2
        f_mid = f(mid)
        if f_mid == target:
            return mid
        elif f_mid > target:
           high = mid if mid != high else low
        else:
           low = mid if mid != low else high
    return low
    

# нам позарез нужен ещё один, свой собственный словник 
# ten, na rozdil od defaultdict'a, neuklada chybejicí složky do slovníku
class DefaultDict(dict):
    def __init__(self, default_value=None):
        self.default_value = default_value
        
    def __missing__(self, key):
        return self.default_value
    
    
    #
    # deme na to, koťě!
    #
    
    # IS, (n-2)-krátá realizace, n>>2, n→∞
def IS(f, h_model, space_from_h='R', space_to_f='G',  Nsim=int(1e4)):
    """
    space_from_h
    space_to_f
    matching - v jakých souřadnicích robím merge a jaká PDF použiváme?
    """
    
    
    # zgenerujeme vzorky
    # nic zajimavýho
    h = h_model(Nsim)
    
    
    # tady musíme provést jeden trik
    # totež jako v IS_like - ve výsledku dycky dostaneme f_model
    to_sample = f.new_sample(getattr(h, space_from_h), space_to_f) # R-ko smerdžíme ako G-čko
    w = to_sample.pdf(space_to_f) / h.pdf(space_from_h) # snad je to správně
    
    # vahy máme
    # zabalme do boxu
    # zbytek už nejsou naši starosti
    return CandyBox(to_sample, w=w)
        




    # for simplex: d = nvar+2 
    # for cell: d = base_r**2
def IS_like(f_plan, sampling_space='G', weights=None, nis=1000, d=1):
    """
    takes sample and returns sampling plan with the same cov (in case d=1)
    covariance matrix we'll divide by d
    """
    
    plan = getattr(f_plan, sampling_space)
    
                
    S_bc = np.cov(plan, rowvar=False, bias=True, aweights=weights)
    barycenter = np.average(plan, axis=0, weights=weights)
    
    
    # matika
    w, v = np.linalg.eig(S_bc)
    
    # use IS sampling density with center equal to the simplex's barycenter
    # set the minimum distance as the standard deviation of IS densisty
    # u stats.norm zadáváme směrodatnou odchylku, to je asi správné
    sigmas = np.sqrt(w/d) 
    h_i = [stats.norm(0, sigma) for sigma in sigmas]
    # rozdělení ve vlastním prostoru
    # select nis = 100 points from IS density 
    h_L = f_models.UnCorD(h_i)(nis)
    
    # здесь уже так легко не отделаемся. Трансформовать кароно.
    h_plan_bc = (v @ h_L.R.T).T
    h_plan_sing = h_plan_bc + barycenter
    
    
    
    # sice to má nazev h_plan, ale nese rozdělení a hustoty v f-ku
    #
    # jelikož výtvaříme nový vzorek z "čístých" souřadnic
    # máme zaručeno, že h_plan vždy bude f_modelem (podle současného kódu CandyBox)
    h_plan = f_plan.new_sample(h_plan_sing, sampling_space) 
    w = h_plan.pdf(sampling_space) / h_L.pdf('R') # snad je to správně
    
    # vahy máme
    # zabalme do boxu
    # zbytek už nejsou naši starosti
    return CandyBox(h_plan, w=w)



        
    

    
    
    
    # for simplex: d = nvar+2 
    # for cell: d = base_r**2
#def sample_like(plan, weights=None, nis=1000, d=1):
#    """
#    takes coordinates and returns coordinates of the same cov sampling plan
#    covariance matrix we'll divide by d
#    """
#    
#                
#    S_bc = np.cov(plan, rowvar=False, bias=True, aweights=weights)
#    barycenter = np.average(plan, axis=0, weights=weights)
#    
#    
#    # matika
#    w, v = np.linalg.eig(S_bc)
#    
#    # use IS sampling density with center equal to the simplex's barycenter
#    # set the minimum distance as the standard deviation of IS densisty
#    # u stats.norm zadáváme směrodatnou odchylku, to je asi správné
#    sigmas = np.sqrt(w/d) 
#    h_i = [stats.norm(0, sigma) for sigma in sigmas]
#    # rozdělení ve vlastním prostoru
#    # select nis = 100 points from IS density 
#    h_L = f_models.UnCorD(h_i)(nis)
#    
#    # здесь уже так легко не отделаемся. Трансформовать кароно.
#    h_plan_bc = (v @ h_L.R.T).T
#    h_plan_sing = h_plan_bc + barycenter
#    
#        
#    return h_plan_sing
        


            


class TrueIS:
    def __init__(self, f, IS_mode='G'):
        self.f_sample = f()
        self.series_data = []
        self.IS_mode = IS_mode
        self.events = []
        
    def add_IS_serie(self, sample, events, alpha=1):
        """
        alpha is for rejection sampling, not used
        """
        self.series_data.append((sample, events, alpha))
        self.events += events
        if self.IS_mode == 'R':
            # jestli máme to právé vzorkovácí rozdělení - tak nemáme čo robiť
            self.f_sample.add_sample(sample) # smerdží se to po R
            # w like weights
            #wt.w = to_sample.pdf_R / wt.h.pdf_R
        else: #IS_mode == 'G':
            # tady musíme provést jeden trik
            self.f_sample.add_sample(sample.R, 'G') # R-ko smerdžíme ako G-čko
            #wt.w = to_sample.pdf_G / wt.h.pdf_R # snad je to správně
        
        
    def get_weights(self):
        accu_denom_w = np.zeros(self.f_sample.nsim, dtype=float)
        if self.IS_mode == 'R':
            for serie in self.series_data:
                h_sample, events, alpha = serie
                h = h_sample.new_sample(self.f_sample)
                accu_denom_w += h.pdf_R * h_sample.nsim
            return self.f_sample.pdf_R / accu_denom_w, self.events
                
        else: # IS_mode == 'G'
            for serie in self.series_data:
                h_sample, events, alpha = serie
                h = h_sample.new_sample(self.f_sample.G, 'R')
                accu_denom_w += h.pdf_R * h_sample.nsim
            return self.f_sample.pdf_G / accu_denom_w, self.events
                
        
    def get_means(self):
        w, events = self.get_weights()
        keys = np.unique(events)
        Nsim = len(w)
        
        means = np.empty(len(keys), dtype=float)
        vars = np.empty(len(keys), dtype=float)
        
        
        # tak bacha
        ev = np.array(events)
        for key, i in zip(keys, range(len(keys))):
                
            mask = ev==key
            ev_w = w[mask]
            # podle IS vzorečků (skoro)
            key_mean = np.sum(ev_w)
            key_var = (np.sum(ev_w**2)*Nsim - key_mean**2) / Nsim
                
            # uložime
            means[i] = key_mean
            vars[i] = key_var
            
            # vyfiltrujeme zbytek
            w = w[~mask]
            ev = ev[~mask]
        
        # kontrola  
        assert len(w)==0 and len(ev)==0, "Что за хренотень?!"
        
        return means, vars
        

class ISSI:
    """
    IS statistics = weights series + events
    ISSI calculates probabilities of repeated IS series
    with implicit (non-zero) variances
    
    zda se mi, že tím nelze nic zhoršit
    """
    #č mám pocit, že je tu někde bug pythonu
    #č ten prazdnej list [] přežije cokoliv
    def __init__(self, events=None):
        """
        """ 
        self.series_data = []
        if events is None:
            self.events = []
        else:
            self.events = events
        
    def add_IS_serie(self, weights, events, implicit_multiplicator=1):
        keys = np.unique(events)
        Nsim = len(weights)
        
        # vytvoříme slovník pro sadu vzorků, který implicitně
        # bude předpokládát průměr=0 a rozptyl 1/Nsim^2 
        # pro všecko, co se v sadě neobjevilo
        if Nsim == 1:
            # jedno meření je taky měření)
            implicit_var = implicit_multiplicator
        else:
            implicit_var = implicit_multiplicator*(1-1/Nsim)/Nsim**2
        serie = DefaultDict((0, implicit_var))
        
        # tak bacha
        w = np.array(weights)
        ev = np.array(events)
        for key in keys:
            if key not in self.events:
                self.events.append(key)
                
            mask = ev==key
            ev_w = w[mask]
            # podle IS vzorečků
            key_mean = np.sum(ev_w)/Nsim
            key_var = (np.sum(ev_w**2)/Nsim - key_mean**2) / Nsim
            if key_var == 0: # to nechcem
                key_var = implicit_var
                
            # uložime
            serie[key] = (key_mean, key_var)
            
            # vyfiltrujeme zbytek
            w = w[~mask]
            ev = ev[~mask]
        
        # kontrola  
        assert len(w)==0 and len(ev)==0, "Что за хренотень?!"
        
        self.series_data.append(serie)
        
        # ачиз значение утёз
        self.get_estimations()
        
        
        
    def add_single_event_data(self, weights, event, nis=None, implicit_multiplicator=np.inf):
        
        if nis is None:
            Nsim = len(weights)
        else:
            Nsim = nis
            
        # kontrola předpokladů
        assert len(weights) <= Nsim, "jseš jistej, že máš spravnej počet měření?"
        
        # vytvoříme slovník pro sadu vzorků, který implicitně
        # bude předpokládát průměr=0 a rozptyl 1/Nsim^2 
        # pro všecko, co se v sadě neobjevilo
        if Nsim == 1:
            # jedno meření je taky měření)
            implicit_var = implicit_multiplicator
        else:
            implicit_var = implicit_multiplicator*(1-1/Nsim)/Nsim**2
        serie = DefaultDict((0, implicit_var))
        
        
        w = np.array(weights)
        if event not in self.events:
            self.events.append(event)
            
        # podle IS vzorečků
        key_mean = np.sum(w)/Nsim
        key_var = (np.sum(w**2)/Nsim - key_mean**2) / Nsim
        if key_var == 0: # to nechcem
            key_var = implicit_var
            
        # uložime
        serie[event] = (key_mean, key_var)
        
        self.series_data.append(serie)
        
        #č nebudeme hned počítat odhady, nechť to dělá volající kód sam
        # ачиз значение утёз
        #self.get_estimations()
        #self.estimations = {self.events[i] : self.values[i] for i in range(len(self.events))}
    
        
    def get_means(self):
        # počet jevů
        # number of events
        n_ev = len(self.events)
        self.weighted_means = np.empty(n_ev, dtype=float)
        self.weighted_vars = np.empty(n_ev, dtype=float)
        
        # spočteme važené průměry a rozptyly
        for event, key in zip(self.events, range(n_ev)):
            key_accusum = 0
            key_accuweight = 0
            for serie in self.series_data:
                key_mean, key_var = serie[event]
                key_accusum += key_mean / key_var
                key_accuweight += 1/key_var
            
            if key_accuweight == 0:
                #č já vidím, že .get_estimations nuly skryje
                self.weighted_means[key] = 0
                self.weighted_vars[key] = np.inf
            else:
                self.weighted_means[key] = key_accusum / key_accuweight
                self.weighted_vars[key] = 1/key_accuweight
            
        
        return self.weighted_means, self.weighted_vars, np.array(self.events)
            
    def get_estimations(self):
    
        # p-čka. We are still talking about probabilities, right?    
        p, vars, __ = self.get_means() 
        
        sum_p = np.sum(p)
        if sum_p == 1: # а вдруг?
            self.values = p
            #♥оӵ ачиз значение утёз
            self.estimations = {self.events[i] : self.values[i] for i in range(len(self.events))}
            return p, np.array(self.events)
            
            # spring (non-linear) analogue
        # silu, kterou zatížíme system jen tak neseženeme
        elif sum_p > 1: # stlačit
            low_atF = -np.pi/2
            high_atF = 0
        else: # roztahnout
            low_atF = 0
            high_atF = np.pi/2
        
        # nuly nám udělaj problém    
        mask = p==0
        p = np.ma.array(p)
        vars = np.ma.array(p)
        p.mask = mask
        vars.mask = mask
        
        F = np.tan(bisect(lambda atF: np.sum(np.exp(np.tan(atF)*vars/p)*p), 1, low_atF, high_atF))
        corrected_means = p * np.exp(F * vars/p)
        
        corrected_means.mask = False
        self.values = corrected_means
        #♥ ачиз значение утёз
        self.estimations = {self.events[i] : self.values[i] for i in range(len(self.events))}
        return corrected_means, np.array(self.events)
        
        
    def delete_event_data(self, event):
        """
        pomocná funkce třeba pro případ změny (zpřesnění) nějakých jevů na straně modelu
        function doesn't recalculate estimations after that!
        """
        # prozatím nebudu kontrolovat, zda ten jev tam vůbec je
        self.events.remove(event)
        for serie in self.series_data:
            # vymažem jev
            if event in serie:
                serie.pop(event)
        
        #č krucinál, tady narazím už ne natolik triviálné chyby
        for i in range(len(self.series_data)-1, -1, -1): # reverse
            serie = self.series_data[i]
            #č zkontrolujem, zda v serii se ještě něco zůstalo
            if len(serie) == 0:
                #č jako doufám, že tam tato serie bude jedina 
                self.series_data.remove(serie)
                
        
        
        
        
        


class ISS:
    """
    IS statistics = weights series + events
    ISS calculates probabilities of repeated IS series
    """
    def __init__(self):
        """
        defaultdict zajistí, že na každý jev nás čeka seznam, do kterého 
        může přidávat průměr a rozptyl ze sady
        """ 
        self.data = collections.defaultdict(list)
        
    def add_IS_serie(self, weights, events):
        keys = np.unique(events)
        Nsim = len(weights)
        
        # tak bacha
        w = np.array(weights)
        ev = np.array(events)
        for key in keys:
            mask = ev==key
            ev_w = w[mask]
            # podle IS vzorečků
            key_mean = np.sum(ev_w)/Nsim
            key_var = (np.sum(ev_w**2)/Nsim - key_mean**2) / Nsim
            # uložime
            self.data[key].append((key_mean, key_var))
            
            # vyfiltrujeme zbytek
            w = w[~mask]
            ev = ev[~mask]
        
        # kontrola  
        assert len(w)==0 and len(ev)==0, "Что за хренотень?!"
        
        
        
    def get_means(self):
        # počet jevů
        # number of events
        weighted_means = []
        weighted_vars = []
        
        # spočteme važené průměry a rozptyly
        for key_data in self.data.values():
            key_accusum = 0
            key_accuweight = 0
            for key_mean, key_var in key_data:
                key_accusum += key_mean / key_var
                key_accuweight += 1/key_var
            
            weighted_means.append(key_accusum / key_accuweight)
            weighted_vars.append(1/key_accuweight)
            
            
        return weighted_means, weighted_vars, np.array(list(self.data.keys()))
            
    def get_estimations(self):
        weighted_means, weighted_vars, __ = self.get_means() 
        
        # p-čka. We are still talking about probabilities, right?    
        p = np.array(weighted_means)
        vars = np.array(weighted_vars)
        
        sum_p = np.sum(p)
        if sum_p == 1: # а вдруг?
            return p, np.array(list(self.data.keys()))
            
            # spring (non-linear) analogue
        # silu, kterou zatížíme system jen tak neseženeme
        elif sum_p > 1: # stlačit
            low_atF = -np.pi/2
            high_atF = 0
        else: # roztahnout
            low_atF = 0
            high_atF = np.pi/2
            
        F = np.tan(bisect(lambda atF: np.sum(np.exp(np.tan(atF)*vars/p)*p), 1, low_atF, high_atF))
        corrected_means = p * np.exp(F * vars/p)
        
        return corrected_means, np.array(list(self.data.keys()))
        
        
        
            
           # scipy проверяет брэкеты, чем вызывает overflow warning, раздражает
#        sol = optimize.root_scalar(lambda atF: np.sum(np.exp(np.tan(atF)*vars/p)*p)-1, bracket=(-np.pi/2, np.pi/2) )
#        F = np.tan(sol.root)
        
        
        
        
        
                # triangle analogue        
#        if len(weighted_means) == 2:
#           # tak je to jednoduchý
#           # it's piece of cake
#           # triangle analogue
#           a, b = *weighted_means
#           # derivations of Heron's formula
#           da = 8*a*b**2 + 6*a - 2*b - 2
#           db = 8*b*a**2 + 6*b - 2*a - 2
#           # matice koeficientů přetvořené podmínkové rovnice
#           B = np.array([[1,1], [da, db]])

#           u = 1 - np.sum(p)
#           # vzoreček z teorii chyb měření a vyrovnávacího počtu nefunguje
#           # dává aj záporné pravděpodobnosti
#           #k = (1 - np.sum(weighted_means))/np.sum(weighted_vars)
#           #corrected_means = weighted_means + weighted_vars*k


Mode Type Size Ref File
100644 blob 18023 dbc921a5ff53594363973972d53c5d572d2826d1 IS_stat.py
100644 blob 6 0916b75b752887809bac2330f3de246c42c245cd __init__.py
100644 blob 73368 3d245b8568158ac63c80fa0847631776a140db0f blackbox.py
100644 blob 11243 10c424c2ce5e8cdd0da97a5aba74c54d1ca71e0d candybox.py
100644 blob 53090 36d72557a0b012a8b30888e26a425a507929bfff dicebox.py
100644 blob 47075 3ad01c91c9781b03caf9d0365932c12eb1ccec5c estimation.py
100644 blob 34189 e2b43f8f1a46cfc950347d6106ff3cba9ffe5f0c f_models.py
100644 blob 31025 70bab60405bfe783a2f7a9f2c41b7c1629d3d474 g_models.py
100644 blob 42845 e66a644b3f32e3a7b2556eebe581ef7ef6a638d7 gl_plot.py
100644 blob 2718 5d721d117448dbb96c554ea8f0e4651ffe9ac457 gp_plot.py
100644 blob 29393 96162a5d181b8307507ba2f44bafe984aa939163 lukiskon.py
100644 blob 2004 6ea8dc8f50a656c48f786d5a00bd6398276c9741 misc.py
100644 blob 10489 1f6dd06a036fdc4ba6a7e6d61ac0b84e8ad3a4c1 mplot.py
100644 blob 1366 993a88f239b6304e48eb519c20a640f28055d7c9 plot.py
100644 blob 2807 1feb1d43e90e027f35bbd0a6730ab18501cef63a plotly_plot.py
100644 blob 108414 0582ff11304f24e05f5f13bf611a17d85cb37254 qt_plot.py
100644 blob 6304 7fc6ac75e415df43af5b7aa9d6d1848aa5d0963d reader.py
100644 blob 4284 a0e0b4e593204ff6254f23a67652804db07800a6 samplebox.py
100644 blob 5553 bac994ae58f1df80c7f8b3f33955af5402f5a4f3 sball.py
100644 blob 21623 281aef80556b8d22842b8659f6f0b7dab0ad71af shapeshare.py
100644 blob 19837 5517d072307bd4c5a462a20943e3a354f32a9589 simplex.py
100644 blob 10357 80c60a409f7b1eb0592d1276dff7aacb065a0f84 stm_df.py
100644 blob 3411 526104441da7029c83ff7c5037ae6b0dbc9a118d testcases_2D.py
100644 blob 22048 4a6014ca5255aa96059ff9ed5a7e29df98d26ffc whitebox.py
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/iam-git/WellMet

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/iam-git/WellMet

Clone this repository using git:
git clone git://git.rocketgit.com/user/iam-git/WellMet

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main