<commit_before>from __future__ import division
import sys
import os
import logging
import time
import numpy as np
from math import log
from collections import deque
from random import random,randrange

from . import parameter
from .proposal import DefaultProposalCycle
from . import proposal
from .cpnest import CheckPoint, RunManager
from tqdm import tqdm
from operator import attrgetter
import numpy.lib.recfunctions as rfn

from .nest2pos import acl

import pickle
__checkpoint_flag = False

class Sampler(object):
    """
    Sampler class.
    ---------

    Initialisation arguments:

    args:
    model: :obj:`cpnest.Model` user defined model to sample

    maxmcmc:
        :int: maximum number of mcmc steps to be used in the :obj:`cnest.sampler.Sampler`

    ----------
    kwargs:

    verbose:
        :int: display debug information on screen
        Default: 0

    poolsize:
        :int: number of objects for the affine invariant sampling
        Default: 1000

    seed:
        :int: random seed to initialise the pseudo-random chain
        Default: None

    proposal:
        :obj:`cpnest.proposals.Proposal` to use
        Defaults: :obj:`cpnest.proposals.DefaultProposalCycle`)

    resume_file:
        File for checkpointing
        Default: None

    manager:
        :obj:`multiprocessing.Manager` hosting all communication objects
        Default: None
    """

    def __init__(self,
                 model,
                 maxmcmc,
                 seed         = None,
                 output       = None,
                 verbose      = False,
                 store_chain  = False,
                 sample_prior = False,
                 poolsize     = 1000,
                 proposal     = None,
                 resume_file  = None,
                 manager      = None):

        self.seed = seed
        self.model = model
        self.initial_mcmc = maxmcmc//10
        self.maxmcmc = maxmcmc
        self.resume_file = resume_file
        self.manager = manager
        self.logLmin = self.manager.logLmin
        self.logLmax = self.manager.logLmax
        self.logger = logging.getLogger('CPNest')

        if proposal is None:
            self.proposal = DefaultProposalCycle()
        else:
            self.proposal = proposal

        self.Nmcmc              = self.initial_mcmc
        self.Nmcmc_exact        = float(self.initial_mcmc)

        self.poolsize           = poolsize
        self.evolution_points   = deque(maxlen = self.poolsize)
        self.verbose            = verbose
        self.acceptance         = 0.0
        self.sub_acceptance     = 0.0
        self.mcmc_accepted      = 0
        self.mcmc_counter       = 0
        self.initialised        = False
        self.output             = output
        self.sample_prior       = sample_prior
        self.store_chain        = store_chain
        self.samples            = None # the list of samples from the mcmc chain
        self.producer_pipe, self.thread_id = self.manager.connect_producer()
        self.last_checkpoint_time = time.time()

    def reset(self):
        """
        Initialise the sampler by generating :int:`poolsize` `cpnest.parameter.LivePoint`
        and distributing them according to :obj:`cpnest.model.Model.log_prior`
        """
        np.random.seed(seed=self.seed)
        for n in tqdm(range(self.poolsize), desc='SMPLR {} init draw'.format(self.thread_id),
                disable= not self.verbose, position=self.thread_id, leave=False):
            while True: # Generate an in-bounds sample
                p = self.model.new_point()
                p.logP = self.model.log_prior(p)
                if np.isfinite(p.logP): break
            p.logL=self.model.log_likelihood(p)
            if p.logL is None or not np.isfinite(p.logL):
                self.logger.warning("Received non-finite logL value {0} with parameters {1}".format(str(p.logL), str(p)))
                self.logger.warning("You may want to check your likelihood function to improve sampling")
            self.evolution_points.append(p)

        self.proposal.set_ensemble(self.evolution_points)

        # initialise the structure to store the mcmc chain
        self.samples = []

        # Now, run evolution so samples are drawn from actual prior
        for k in tqdm(range(self.poolsize), desc='SMPLR {} init evolve'.format(self.thread_id),
                disable= not self.verbose, position=self.thread_id, leave=False):
            _, p = next(self.yield_sample(-np.inf))
            self.estimate_nmcmc_on_the_fly()

        if self.sample_prior is True:
            # save the poolsize as prior samples

            prior_samples = []
            for k in tqdm(range(self.maxmcmc), desc='SMPLR {} generating prior samples'.format(self.thread_id),
                disable= not self.verbose, position=self.thread_id, leave=False):
                _, p = next(self.yield_sample(-np.inf))
                prior_samples.append(p)
            prior_samples = rfn.stack_arrays([prior_samples[j].asnparray()
                for j in range(0,len(prior_samples))],usemask=False)
            np.savetxt(os.path.join(self.output,'prior_samples_%s.dat'%os.getpid()),
                       prior_samples.ravel(),header=' '.join(prior_samples.dtype.names),
                       newline='\n',delimiter=' ')
            self.logger.critical("Sampler process {0!s}: saved {1:d} prior samples in {2!s}".format(os.getpid(),self.maxmcmc,'prior_samples_%s.dat'%os.getpid()))
            self.prior_samples = prior_samples
        self.proposal.set_ensemble(self.evolution_points)
        self.initialised=True

    def estimate_nmcmc_on_the_fly(self, safety=5, tau=None):
        """
        Estimate autocorrelation length of chain using acceptance fraction
        ACL = (2/acc) - 1
        multiplied by a safety margin of 5
        Uses moving average with decay time tau iterations
        (default: :int:`self.poolsize`)

        Taken from http://github.com/farr/Ensemble.jl
        """
        if tau is None: tau = self.poolsize/safety

        if self.sub_acceptance == 0.0:
            self.Nmcmc_exact = (1.0 + 1.0/tau)*self.Nmcmc_exact
        else:
            self.Nmcmc_exact = (1.0 - 1.0/tau)*self.Nmcmc_exact + (safety/tau)*(2.0/self.sub_acceptance - 1.0)

        self.Nmcmc_exact = float(min(self.Nmcmc_exact,self.maxmcmc))
        self.Nmcmc = max(safety,int(self.Nmcmc_exact))

        return self.Nmcmc

    def estimate_nmcmc(self):
        """
        Estimate autocorrelation length of the chain
        """
        # first of all, build a numpy array out of
        # the stored samples
        self.ACL = []
        samples = np.array(self.samples)

        if self.store_chain is False:
            self.ACL = [acl(samples[:,i]) for i in range(samples.shape[1])]
        else:
            self.ACL = [acl(samples[-self.maxmcmc:,i]) for i in range(samples.shape[1])]
        self.Nmcmc = int(np.max(self.ACL))
        if (not self.store_chain) and (len(self.samples) > self.maxmcmc):
            self.samples = []
        if self.Nmcmc < 20:
            self.Nmcmc = 20
        return self.Nmcmc

    def produce_sample(self):
        try:
            self._produce_sample()
        except CheckPoint:
            self.logger.critical("Checkpoint excepted in sampler")
            self.checkpoint()

    def _produce_sample(self):
        """
        main loop that takes the worst :obj:`cpnest.parameter.LivePoint` and
        evolves it. Proposed sample is then sent back
        to :obj:`cpnest.NestedSampler`.
        """
        if not self.initialised:
            self.reset()

        self.counter=1
        __checkpoint_flag=False
        while True:

            if self.manager.checkpoint_flag.value:
                self.checkpoint()
                sys.exit(130)

            if self.logLmin.value==np.inf:
                break

            if time.time() - self.last_checkpoint_time > self.manager.periodic_checkpoint_interval:
                self.checkpoint()
                self.last_checkpoint_time = time.time()

            # if the nested sampler is requesting for an update
            # produce a sample for it
            if self.producer_pipe.poll():
                p = self.producer_pipe.recv()

                if p is None:
                    break
                if p == "checkpoint":
                    self.checkpoint()
                    sys.exit(130)

                self.evolution_points.append(p)
                (Nmcmc, outParam) = next(self.yield_sample(self.logLmin.value))
                # Send the sample to the Nested Sampler
                self.producer_pipe.send((self.acceptance,self.sub_acceptance,Nmcmc,outParam))

            # otherwise, keep on sampling from the previous boundary
            else:
                (Nmcmc, outParam) = next(self.yield_sample(self.logLmin.value))
            # Update the ensemble every now and again
            if (self.counter%(self.poolsize//4))==0:
                self.proposal.set_ensemble(self.evolution_points)
                self.estimate_nmcmc()

            self.counter += 1

        self.logger.critical("Sampler process {0!s}: MCMC samples accumulated = {1:d}".format(os.getpid(),len(self.samples)))
#        self.samples.extend(self.evolution_points)

        if self.verbose >=3:

            self.mcmc_samples = rfn.stack_arrays([self.samples[j].asnparray()
                                                  for j in range(0,len(self.samples))],usemask=False)
            np.savetxt(os.path.join(self.output,'mcmc_chain_%s.dat'%os.getpid()),
                       self.mcmc_samples.ravel(),header=' '.join(self.mcmc_samples.dtype.names),
                       newline='\n',delimiter=' ')
            self.logger.critical("Sampler process {0!s}: saved {1:d} mcmc samples in {2!s}".format(os.getpid(),len(self.samples),'mcmc_chain_%s.dat'%os.getpid()))
        self.logger.critical("Sampler process {0!s} - mean acceptance {1:.3f}: exiting".format(os.getpid(), float(self.mcmc_accepted)/float(self.mcmc_counter)))
        return 0

    def checkpoint(self):
        """
        Checkpoint its internal state
        """
        self.logger.info('Checkpointing Sampler')
        with open(self.resume_file, "wb") as f:
            pickle.dump(self, f)

    @classmethod
    def resume(cls, resume_file, manager, model):
        """
        Resumes the interrupted state from a
        checkpoint pickle file.
        """
        with open(resume_file, "rb") as f:
            obj = pickle.load(f)
        obj.model   = model
        obj.manager = manager
        obj.logLmin = obj.manager.logLmin
        obj.logLmax = obj.manager.logLmax
        obj.logger = logging.getLogger("CPNest")
        obj.producer_pipe , obj.thread_id = obj.manager.connect_producer()
        obj.logger.info('Resuming Sampler from ' + resume_file)
        obj.last_checkpoint_time = time.time()
        return obj

    def __getstate__(self):
        state = self.__dict__.copy()
        # Remove the unpicklable entries.
        del state['model']
        del state['logLmin']
        del state['logLmax']
        del state['manager']
        del state['producer_pipe']
        del state['thread_id']
        del state['logger']
        return state

    def __setstate__(self, state):
        self.__dict__ = state
        self.manager = None

class MetropolisHastingsSampler(Sampler):
    """
    metropolis-hastings acceptance rule
    for :obj:`cpnest.proposal.EnembleProposal`
    """
    def yield_sample(self, logLmin):

        while True:

            sub_counter = 0
            sub_accepted = 0
            oldparam = self.evolution_points.popleft()
            logp_old = self.model.log_prior(oldparam)

            while True:

                sub_counter += 1
                newparam = self.proposal.get_sample(oldparam.copy())
                newparam.logP = self.model.log_prior(newparam)

                if newparam.logP-logp_old + self.proposal.log_J > log(random()):
                    newparam.logL = self.model.log_likelihood(newparam)
                    if newparam.logL > logLmin:
                        self.logLmax.value = max(self.logLmax.value, newparam.logL)
                        oldparam = newparam.copy()
                        logp_old = newparam.logP
                        sub_accepted+=1
                # append the sample to the array of samples
                self.samples.append(oldparam.values)

                if (sub_counter >= self.Nmcmc and sub_accepted > 0 ) or sub_counter >= self.maxmcmc:
                    break

            # Put sample back in the stack, unless that sample led to zero accepted points
            self.evolution_points.append(oldparam)
            # append the sample to the array of samples
            self.samples.append(oldparam.values)

            self.sub_acceptance = float(sub_accepted)/float(sub_counter)
            self.mcmc_accepted += sub_accepted
            self.mcmc_counter += sub_counter
            self.acceptance    = float(self.mcmc_accepted)/float(self.mcmc_counter)
            # Yield the new sample
            yield (sub_counter, oldparam)

class HamiltonianMonteCarloSampler(Sampler):
    """
    HamiltonianMonteCarlo acceptance rule
    for :obj:`cpnest.proposal.HamiltonianProposal`
    """
    def yield_sample(self, logLmin):

        global_lmax = self.logLmax.value

        while True:

            sub_accepted    = 0
            sub_counter     = 0
            oldparam        = self.evolution_points.pop()

            while sub_accepted == 0:

                sub_counter += 1
                newparam     = self.proposal.get_sample(oldparam.copy(), logLmin = logLmin)

                if self.proposal.log_J > np.log(random()):

                    if newparam.logL > logLmin:
                        global_lmax = max(global_lmax, newparam.logL)
                        oldparam        = newparam.copy()
                        sub_accepted   += 1

            self.evolution_points.append(oldparam)

            self.sub_acceptance = float(sub_accepted)/float(sub_counter)
            self.mcmc_accepted += sub_accepted
            self.mcmc_counter  += sub_counter
            self.acceptance     = float(self.mcmc_accepted)/float(self.mcmc_counter)
            self.logLmax.value = global_lmax

            for p in self.proposal.proposals:
                p.update_time_step(self.acceptance)
                p.update_trajectory_length(self.estimate_nmcmc())
                #print(p.dt,p.L)

            yield (sub_counter, oldparam)

    def insert_sample(self, p):
        # if we did not accept, inject a new particle in the system (gran-canonical) from the prior
        # by picking one from the existing pool and giving it a random trajectory
        k = np.random.randint(self.evolution_points.maxlen)
        self.evolution_points.rotate(k)
        p  = self.evolution_points.pop()
        self.evolution_points.append(p)
        self.evolution_points.rotate(-k)
        return self.proposal.get_sample(p.copy(),logLmin=p.logL)
<commit_msg>Don't store ACL in object<commit_after>from __future__ import division
import sys
import os
import logging
import time
import numpy as np
from math import log
from collections import deque
from random import random,randrange

from . import parameter
from .proposal import DefaultProposalCycle
from . import proposal
from .cpnest import CheckPoint, RunManager
from tqdm import tqdm
from operator import attrgetter
import numpy.lib.recfunctions as rfn

from .nest2pos import acl

import pickle
__checkpoint_flag = False

class Sampler(object):
    """
    Sampler class.
    ---------

    Initialisation arguments:

    args:
    model: :obj:`cpnest.Model` user defined model to sample

    maxmcmc:
        :int: maximum number of mcmc steps to be used in the :obj:`cnest.sampler.Sampler`

    ----------
    kwargs:

    verbose:
        :int: display debug information on screen
        Default: 0

    poolsize:
        :int: number of objects for the affine invariant sampling
        Default: 1000

    seed:
        :int: random seed to initialise the pseudo-random chain
        Default: None

    proposal:
        :obj:`cpnest.proposals.Proposal` to use
        Defaults: :obj:`cpnest.proposals.DefaultProposalCycle`)

    resume_file:
        File for checkpointing
        Default: None

    manager:
        :obj:`multiprocessing.Manager` hosting all communication objects
        Default: None
    """

    def __init__(self,
                 model,
                 maxmcmc,
                 seed         = None,
                 output       = None,
                 verbose      = False,
                 store_chain  = False,
                 sample_prior = False,
                 poolsize     = 1000,
                 proposal     = None,
                 resume_file  = None,
                 manager      = None):

        self.seed = seed
        self.model = model
        self.initial_mcmc = maxmcmc//10
        self.maxmcmc = maxmcmc
        self.resume_file = resume_file
        self.manager = manager
        self.logLmin = self.manager.logLmin
        self.logLmax = self.manager.logLmax
        self.logger = logging.getLogger('CPNest')

        if proposal is None:
            self.proposal = DefaultProposalCycle()
        else:
            self.proposal = proposal

        self.Nmcmc              = self.initial_mcmc
        self.Nmcmc_exact        = float(self.initial_mcmc)

        self.poolsize           = poolsize
        self.evolution_points   = deque(maxlen = self.poolsize)
        self.verbose            = verbose
        self.acceptance         = 0.0
        self.sub_acceptance     = 0.0
        self.mcmc_accepted      = 0
        self.mcmc_counter       = 0
        self.initialised        = False
        self.output             = output
        self.sample_prior       = sample_prior
        self.store_chain        = store_chain
        self.samples            = None # the list of samples from the mcmc chain
        self.producer_pipe, self.thread_id = self.manager.connect_producer()
        self.last_checkpoint_time = time.time()

    def reset(self):
        """
        Initialise the sampler by generating :int:`poolsize` `cpnest.parameter.LivePoint`
        and distributing them according to :obj:`cpnest.model.Model.log_prior`
        """
        np.random.seed(seed=self.seed)
        for n in tqdm(range(self.poolsize), desc='SMPLR {} init draw'.format(self.thread_id),
                disable= not self.verbose, position=self.thread_id, leave=False):
            while True: # Generate an in-bounds sample
                p = self.model.new_point()
                p.logP = self.model.log_prior(p)
                if np.isfinite(p.logP): break
            p.logL=self.model.log_likelihood(p)
            if p.logL is None or not np.isfinite(p.logL):
                self.logger.warning("Received non-finite logL value {0} with parameters {1}".format(str(p.logL), str(p)))
                self.logger.warning("You may want to check your likelihood function to improve sampling")
            self.evolution_points.append(p)

        self.proposal.set_ensemble(self.evolution_points)

        # initialise the structure to store the mcmc chain
        self.samples = []

        # Now, run evolution so samples are drawn from actual prior
        for k in tqdm(range(self.poolsize), desc='SMPLR {} init evolve'.format(self.thread_id),
                disable= not self.verbose, position=self.thread_id, leave=False):
            _, p = next(self.yield_sample(-np.inf))
            self.estimate_nmcmc_on_the_fly()

        if self.sample_prior is True:
            # save the poolsize as prior samples

            prior_samples = []
            for k in tqdm(range(self.maxmcmc), desc='SMPLR {} generating prior samples'.format(self.thread_id),
                disable= not self.verbose, position=self.thread_id, leave=False):
                _, p = next(self.yield_sample(-np.inf))
                prior_samples.append(p)
            prior_samples = rfn.stack_arrays([prior_samples[j].asnparray()
                for j in range(0,len(prior_samples))],usemask=False)
            np.savetxt(os.path.join(self.output,'prior_samples_%s.dat'%os.getpid()),
                       prior_samples.ravel(),header=' '.join(prior_samples.dtype.names),
                       newline='\n',delimiter=' ')
            self.logger.critical("Sampler process {0!s}: saved {1:d} prior samples in {2!s}".format(os.getpid(),self.maxmcmc,'prior_samples_%s.dat'%os.getpid()))
            self.prior_samples = prior_samples
        self.proposal.set_ensemble(self.evolution_points)
        self.initialised=True

    def estimate_nmcmc_on_the_fly(self, safety=5, tau=None):
        """
        Estimate autocorrelation length of chain using acceptance fraction
        ACL = (2/acc) - 1
        multiplied by a safety margin of 5
        Uses moving average with decay time tau iterations
        (default: :int:`self.poolsize`)

        Taken from http://github.com/farr/Ensemble.jl
        """
        if tau is None: tau = self.poolsize/safety

        if self.sub_acceptance == 0.0:
            self.Nmcmc_exact = (1.0 + 1.0/tau)*self.Nmcmc_exact
        else:
            self.Nmcmc_exact = (1.0 - 1.0/tau)*self.Nmcmc_exact + (safety/tau)*(2.0/self.sub_acceptance - 1.0)

        self.Nmcmc_exact = float(min(self.Nmcmc_exact,self.maxmcmc))
        self.Nmcmc = max(safety,int(self.Nmcmc_exact))

        return self.Nmcmc

    def estimate_nmcmc(self):
        """
        Estimate autocorrelation length of the chain
        """
        # first of all, build a numpy array out of
        # the stored samples
        ACL = []
        samples = np.array(self.samples)
        if not self.store_chain:
            ACL = [acl(samples[:,i]) for i in range(samples.shape[1])]
        else:
            ACL = [acl(samples[-self.maxmcmc:,i]) for i in range(samples.shape[1])]
        self.Nmcmc = int(np.max(ACL))
        if (not self.store_chain) and (len(self.samples) > self.maxmcmc):
            self.samples = []
        if self.Nmcmc < 20:
            self.Nmcmc = 20
        return self.Nmcmc

    def produce_sample(self):
        try:
            self._produce_sample()
        except CheckPoint:
            self.logger.critical("Checkpoint excepted in sampler")
            self.checkpoint()

    def _produce_sample(self):
        """
        main loop that takes the worst :obj:`cpnest.parameter.LivePoint` and
        evolves it. Proposed sample is then sent back
        to :obj:`cpnest.NestedSampler`.
        """
        if not self.initialised:
            self.reset()

        self.counter=1
        __checkpoint_flag=False
        while True:

            if self.manager.checkpoint_flag.value:
                self.checkpoint()
                sys.exit(130)

            if self.logLmin.value==np.inf:
                break

            if time.time() - self.last_checkpoint_time > self.manager.periodic_checkpoint_interval:
                self.checkpoint()
                self.last_checkpoint_time = time.time()

            # if the nested sampler is requesting for an update
            # produce a sample for it
            if self.producer_pipe.poll():
                p = self.producer_pipe.recv()

                if p is None:
                    break
                if p == "checkpoint":
                    self.checkpoint()
                    sys.exit(130)

                self.evolution_points.append(p)
                (Nmcmc, outParam) = next(self.yield_sample(self.logLmin.value))
                # Send the sample to the Nested Sampler
                self.producer_pipe.send((self.acceptance,self.sub_acceptance,Nmcmc,outParam))

            # otherwise, keep on sampling from the previous boundary
            else:
                (Nmcmc, outParam) = next(self.yield_sample(self.logLmin.value))
            # Update the ensemble every now and again
            if (self.counter%(self.poolsize//4))==0:
                self.proposal.set_ensemble(self.evolution_points)
                self.estimate_nmcmc()

            self.counter += 1

        self.logger.critical("Sampler process {0!s}: MCMC samples accumulated = {1:d}".format(os.getpid(),len(self.samples)))
#        self.samples.extend(self.evolution_points)

        if self.verbose >=3:

            self.mcmc_samples = rfn.stack_arrays([self.samples[j].asnparray()
                                                  for j in range(0,len(self.samples))],usemask=False)
            np.savetxt(os.path.join(self.output,'mcmc_chain_%s.dat'%os.getpid()),
                       self.mcmc_samples.ravel(),header=' '.join(self.mcmc_samples.dtype.names),
                       newline='\n',delimiter=' ')
            self.logger.critical("Sampler process {0!s}: saved {1:d} mcmc samples in {2!s}".format(os.getpid(),len(self.samples),'mcmc_chain_%s.dat'%os.getpid()))
        self.logger.critical("Sampler process {0!s} - mean acceptance {1:.3f}: exiting".format(os.getpid(), float(self.mcmc_accepted)/float(self.mcmc_counter)))
        return 0

    def checkpoint(self):
        """
        Checkpoint its internal state
        """
        self.logger.info('Checkpointing Sampler')
        with open(self.resume_file, "wb") as f:
            pickle.dump(self, f)

    @classmethod
    def resume(cls, resume_file, manager, model):
        """
        Resumes the interrupted state from a
        checkpoint pickle file.
        """
        with open(resume_file, "rb") as f:
            obj = pickle.load(f)
        obj.model   = model
        obj.manager = manager
        obj.logLmin = obj.manager.logLmin
        obj.logLmax = obj.manager.logLmax
        obj.logger = logging.getLogger("CPNest")
        obj.producer_pipe , obj.thread_id = obj.manager.connect_producer()
        obj.logger.info('Resuming Sampler from ' + resume_file)
        obj.last_checkpoint_time = time.time()
        return obj

    def __getstate__(self):
        state = self.__dict__.copy()
        # Remove the unpicklable entries.
        del state['model']
        del state['logLmin']
        del state['logLmax']
        del state['manager']
        del state['producer_pipe']
        del state['thread_id']
        del state['logger']
        return state

    def __setstate__(self, state):
        self.__dict__ = state
        self.manager = None

class MetropolisHastingsSampler(Sampler):
    """
    metropolis-hastings acceptance rule
    for :obj:`cpnest.proposal.EnembleProposal`
    """
    def yield_sample(self, logLmin):

        while True:

            sub_counter = 0
            sub_accepted = 0
            oldparam = self.evolution_points.popleft()
            logp_old = self.model.log_prior(oldparam)

            while True:

                sub_counter += 1
                newparam = self.proposal.get_sample(oldparam.copy())
                newparam.logP = self.model.log_prior(newparam)

                if newparam.logP-logp_old + self.proposal.log_J > log(random()):
                    newparam.logL = self.model.log_likelihood(newparam)
                    if newparam.logL > logLmin:
                        self.logLmax.value = max(self.logLmax.value, newparam.logL)
                        oldparam = newparam.copy()
                        logp_old = newparam.logP
                        sub_accepted+=1
                # append the sample to the array of samples
                self.samples.append(oldparam.values)

                if (sub_counter >= self.Nmcmc and sub_accepted > 0 ) or sub_counter >= self.maxmcmc:
                    break

            # Put sample back in the stack, unless that sample led to zero accepted points
            self.evolution_points.append(oldparam)

            self.sub_acceptance = float(sub_accepted)/float(sub_counter)
            self.mcmc_accepted += sub_accepted
            self.mcmc_counter += sub_counter
            self.acceptance    = float(self.mcmc_accepted)/float(self.mcmc_counter)
            # Yield the new sample
            yield (sub_counter, oldparam)

class HamiltonianMonteCarloSampler(Sampler):
    """
    HamiltonianMonteCarlo acceptance rule
    for :obj:`cpnest.proposal.HamiltonianProposal`
    """
    def yield_sample(self, logLmin):

        global_lmax = self.logLmax.value

        while True:

            sub_accepted    = 0
            sub_counter     = 0
            oldparam        = self.evolution_points.pop()

            while sub_accepted == 0:

                sub_counter += 1
                newparam     = self.proposal.get_sample(oldparam.copy(), logLmin = logLmin)

                if self.proposal.log_J > np.log(random()):

                    if newparam.logL > logLmin:
                        global_lmax = max(global_lmax, newparam.logL)
                        oldparam        = newparam.copy()
                        sub_accepted   += 1

            self.evolution_points.append(oldparam)

            self.sub_acceptance = float(sub_accepted)/float(sub_counter)
            self.mcmc_accepted += sub_accepted
            self.mcmc_counter  += sub_counter
            self.acceptance     = float(self.mcmc_accepted)/float(self.mcmc_counter)
            self.logLmax.value = global_lmax

            for p in self.proposal.proposals:
                p.update_time_step(self.acceptance)
                p.update_trajectory_length(self.estimate_nmcmc())
                #print(p.dt,p.L)

            yield (sub_counter, oldparam)

    def insert_sample(self, p):
        # if we did not accept, inject a new particle in the system (gran-canonical) from the prior
        # by picking one from the existing pool and giving it a random trajectory
        k = np.random.randint(self.evolution_points.maxlen)
        self.evolution_points.rotate(k)
        p  = self.evolution_points.pop()
        self.evolution_points.append(p)
        self.evolution_points.rotate(-k)
        return self.proposal.get_sample(p.copy(),logLmin=p.logL)
<|endoftext|>


<commit_before>"""Support for media browsing."""

from homeassistant.components.media_player import BrowseMedia
from homeassistant.components.media_player.const import (
    MEDIA_CLASS_ALBUM,
    MEDIA_CLASS_ARTIST,
    MEDIA_CLASS_DIRECTORY,
    MEDIA_CLASS_EPISODE,
    MEDIA_CLASS_MOVIE,
    MEDIA_CLASS_PLAYLIST,
    MEDIA_CLASS_SEASON,
    MEDIA_CLASS_TV_SHOW,
    MEDIA_TYPE_ALBUM,
    MEDIA_TYPE_ARTIST,
    MEDIA_TYPE_EPISODE,
    MEDIA_TYPE_MOVIE,
    MEDIA_TYPE_PLAYLIST,
    MEDIA_TYPE_SEASON,
    MEDIA_TYPE_TRACK,
    MEDIA_TYPE_TVSHOW,
)

PLAYABLE_MEDIA_TYPES = [
    MEDIA_TYPE_ALBUM,
    MEDIA_TYPE_ARTIST,
    MEDIA_TYPE_TRACK,
]

EXPANDABLE_MEDIA_TYPES = [
    MEDIA_TYPE_ALBUM,
    MEDIA_TYPE_ARTIST,
    MEDIA_TYPE_PLAYLIST,
    MEDIA_TYPE_TVSHOW,
    MEDIA_TYPE_SEASON,
    "library_music",
]

CONTENT_TYPE_MEDIA_CLASS = {
    "library_music": MEDIA_CLASS_DIRECTORY,
    MEDIA_TYPE_SEASON: MEDIA_CLASS_SEASON,
    MEDIA_TYPE_ALBUM: MEDIA_CLASS_ALBUM,
    MEDIA_TYPE_ARTIST: MEDIA_CLASS_ARTIST,
    MEDIA_TYPE_MOVIE: MEDIA_CLASS_MOVIE,
    MEDIA_TYPE_PLAYLIST: MEDIA_CLASS_PLAYLIST,
    MEDIA_TYPE_TVSHOW: MEDIA_CLASS_TV_SHOW,
    MEDIA_TYPE_EPISODE: MEDIA_CLASS_EPISODE,
}

async def build_item_response(media_library, payload):
    """Create response payload for the provided media query."""
    search_id = payload["search_id"]
    search_type = payload["search_type"]

    thumbnail = None
    title = None
    media = None

    query = {"properties": ["thumbnail"]}
    # pylint: disable=protected-access
    if search_type == MEDIA_TYPE_ALBUM:
        if search_id:
            query.update({"filter": {"albumid": int(search_id)}})
            query["properties"].extend(
                ["albumid", "artist", "duration", "album", "track"]
            )
            album = await media_library._server.AudioLibrary.GetAlbumDetails(
                {"albumid": int(search_id), "properties": ["thumbnail"]}
            )
            thumbnail = media_library.thumbnail_url(
                album["albumdetails"].get("thumbnail")
            )
            title = album["albumdetails"]["label"]
            media = await media_library._server.AudioLibrary.GetSongs(query)
            media = media.get("songs")
        else:
            media = await media_library._server.AudioLibrary.GetAlbums(query)
            media = media.get("albums")
            title = "Albums"
    elif search_type == MEDIA_TYPE_ARTIST:
        if search_id:
            query.update({"filter": {"artistid": int(search_id)}})
            media = await media_library._server.AudioLibrary.GetAlbums(query)
            media = media.get("albums")
            artist = await media_library._server.AudioLibrary.GetArtistDetails(
                {"artistid": int(search_id), "properties": ["thumbnail"]}
            )
            thumbnail = media_library.thumbnail_url(
                artist["artistdetails"].get("thumbnail")
            )
            title = artist["artistdetails"]["label"]
        else:
            media = await media_library._server.AudioLibrary.GetArtists(query)
            media = media.get("artists")
            title = "Artists"
    elif search_type == "library_music":
        library = {MEDIA_TYPE_ALBUM: "Albums", MEDIA_TYPE_ARTIST: "Artists"}
        media = [{"label": name, "type": type_} for type_, name in library.items()]
        title = "Music Library"
    elif search_type == MEDIA_TYPE_MOVIE:
        media = await media_library._server.VideoLibrary.GetMovies(query)
        media = media.get("movies")
        title = "Movies"
    elif search_type == MEDIA_TYPE_TVSHOW:
        if search_id:
            media = await media_library._server.VideoLibrary.GetSeasons(
                {
                    "tvshowid": int(search_id),
                    "properties": ["thumbnail", "season", "tvshowid"],
                }
            )
            media = media.get("seasons")
            tvshow = await media_library._server.VideoLibrary.GetTVShowDetails(
                {"tvshowid": int(search_id), "properties": ["thumbnail"]}
            )
            thumbnail = media_library.thumbnail_url(
                tvshow["tvshowdetails"].get("thumbnail")
            )
            title = tvshow["tvshowdetails"]["label"]
        else:
            media = await media_library._server.VideoLibrary.GetTVShows(query)
            media = media.get("tvshows")
            title = "TV Shows"
    elif search_type == MEDIA_TYPE_SEASON:
        tv_show_id, season_id = search_id.split("/", 1)
        media = await media_library._server.VideoLibrary.GetEpisodes(
            {
                "tvshowid": int(tv_show_id),
                "season": int(season_id),
                "properties": ["thumbnail", "tvshowid", "seasonid"],
            }
        )
        media = media.get("episodes")
        if media:
            season = await media_library._server.VideoLibrary.GetSeasonDetails(
                {"seasonid": int(media[0]["seasonid"]), "properties": ["thumbnail"]}
            )
            thumbnail = media_library.thumbnail_url(
                season["seasondetails"].get("thumbnail")
            )
            title = season["seasondetails"]["label"]

    if media is None:
        return

    return BrowseMedia(
        media_class=CONTENT_TYPE_MEDIA_CLASS[search_type],
        media_content_id=payload["search_id"],
        media_content_type=search_type,
        title=title,
        can_play=search_type in PLAYABLE_MEDIA_TYPES and search_id,
        can_expand=True,
        children=[item_payload(item, media_library) for item in media],
        thumbnail=thumbnail,
    )

def item_payload(item, media_library):
    """
    Create response payload for a single media item.

    Used by async_browse_media.
    """
    if "songid" in item:
        media_content_type = MEDIA_TYPE_TRACK
        media_content_id = f"{item['songid']}"
    elif "albumid" in item:
        media_content_type = MEDIA_TYPE_ALBUM
        media_content_id = f"{item['albumid']}"
    elif "artistid" in item:
        media_content_type = MEDIA_TYPE_ARTIST
        media_content_id = f"{item['artistid']}"
    elif "movieid" in item:
        media_content_type = MEDIA_TYPE_MOVIE
        media_content_id = f"{item['movieid']}"
    elif "episodeid" in item:
        media_content_type = MEDIA_TYPE_EPISODE
        media_content_id = f"{item['episodeid']}"
    elif "seasonid" in item:
        media_content_type = MEDIA_TYPE_SEASON
        media_content_id = f"{item['tvshowid']}/{item['season']}"
    elif "tvshowid" in item:
        media_content_type = MEDIA_TYPE_TVSHOW
        media_content_id = f"{item['tvshowid']}"
    else:
        # this case is for the top folder of each type
        # possible content types: album, artist, movie, library_music, tvshow
        media_content_type = item.get("type")
        media_content_id = ""

    title = item["label"]
    can_play = media_content_type in PLAYABLE_MEDIA_TYPES and media_content_id
    can_expand = media_content_type in EXPANDABLE_MEDIA_TYPES

    thumbnail = item.get("thumbnail")
    if thumbnail:
        thumbnail = media_library.thumbnail_url(thumbnail)

    if media_content_type == MEDIA_TYPE_MOVIE and not media_content_id:
        media_class = MEDIA_CLASS_DIRECTORY
        can_expand = True
    else:
        media_class = CONTENT_TYPE_MEDIA_CLASS[media_content_type]

    return BrowseMedia(
        title=title,
        media_class=media_class,
        media_content_type=media_content_type,
        media_content_id=media_content_id,
        can_play=can_play,
        can_expand=can_expand,
        thumbnail=thumbnail,
    )

def library_payload(media_library):
    """
    Create response payload to describe contents of a specific library.

    Used by async_browse_media.
    """
    library_info = BrowseMedia(
        media_class=MEDIA_CLASS_DIRECTORY,
        media_content_id="library",
        media_content_type="library",
        title="Media Library",
        can_play=False,
        can_expand=True,
        children=[],
    )

    library = {
        "library_music": "Music",
        MEDIA_TYPE_MOVIE: "Movies",
        MEDIA_TYPE_TVSHOW: "TV shows",
    }
    for item in [{"label": name, "type": type_} for type_, name in library.items()]:
        library_info.children.append(
            item_payload(
                {"label": item["label"], "type": item["type"], "uri": item["type"]},
                media_library,
            )
        )

    return library_info
<commit_msg>Fix Kodi media browser (#39840)<commit_after>"""Support for media browsing."""
import logging

from homeassistant.components.media_player import BrowseError, BrowseMedia
from homeassistant.components.media_player.const import (
    MEDIA_CLASS_ALBUM,
    MEDIA_CLASS_ARTIST,
    MEDIA_CLASS_DIRECTORY,
    MEDIA_CLASS_EPISODE,
    MEDIA_CLASS_MOVIE,
    MEDIA_CLASS_MUSIC,
    MEDIA_CLASS_PLAYLIST,
    MEDIA_CLASS_SEASON,
    MEDIA_CLASS_TRACK,
    MEDIA_CLASS_TV_SHOW,
    MEDIA_TYPE_ALBUM,
    MEDIA_TYPE_ARTIST,
    MEDIA_TYPE_EPISODE,
    MEDIA_TYPE_MOVIE,
    MEDIA_TYPE_PLAYLIST,
    MEDIA_TYPE_SEASON,
    MEDIA_TYPE_TRACK,
    MEDIA_TYPE_TVSHOW,
)

PLAYABLE_MEDIA_TYPES = [
    MEDIA_TYPE_ALBUM,
    MEDIA_TYPE_ARTIST,
    MEDIA_TYPE_TRACK,
]

CONTENT_TYPE_MEDIA_CLASS = {
    "library_music": MEDIA_CLASS_MUSIC,
    MEDIA_TYPE_SEASON: MEDIA_CLASS_SEASON,
    MEDIA_TYPE_ALBUM: MEDIA_CLASS_ALBUM,
    MEDIA_TYPE_ARTIST: MEDIA_CLASS_ARTIST,
    MEDIA_TYPE_MOVIE: MEDIA_CLASS_MOVIE,
    MEDIA_TYPE_PLAYLIST: MEDIA_CLASS_PLAYLIST,
    MEDIA_TYPE_TRACK: MEDIA_CLASS_TRACK,
    MEDIA_TYPE_TVSHOW: MEDIA_CLASS_TV_SHOW,
    MEDIA_TYPE_EPISODE: MEDIA_CLASS_EPISODE,
}

_LOGGER = logging.getLogger(__name__)

class UnknownMediaType(BrowseError):
    """Unknown media type."""

async def build_item_response(media_library, payload):
    """Create response payload for the provided media query."""
    search_id = payload["search_id"]
    search_type = payload["search_type"]

    thumbnail = None
    title = None
    media = None

    query = {"properties": ["thumbnail"]}
    # pylint: disable=protected-access
    if search_type == MEDIA_TYPE_ALBUM:
        if search_id:
            query.update({"filter": {"albumid": int(search_id)}})
            query["properties"].extend(
                ["albumid", "artist", "duration", "album", "track"]
            )
            album = await media_library._server.AudioLibrary.GetAlbumDetails(
                {"albumid": int(search_id), "properties": ["thumbnail"]}
            )
            thumbnail = media_library.thumbnail_url(
                album["albumdetails"].get("thumbnail")
            )
            title = album["albumdetails"]["label"]
            media = await media_library._server.AudioLibrary.GetSongs(query)
            media = media.get("songs")
        else:
            media = await media_library._server.AudioLibrary.GetAlbums(query)
            media = media.get("albums")
            title = "Albums"
    elif search_type == MEDIA_TYPE_ARTIST:
        if search_id:
            query.update({"filter": {"artistid": int(search_id)}})
            media = await media_library._server.AudioLibrary.GetAlbums(query)
            media = media.get("albums")
            artist = await media_library._server.AudioLibrary.GetArtistDetails(
                {"artistid": int(search_id), "properties": ["thumbnail"]}
            )
            thumbnail = media_library.thumbnail_url(
                artist["artistdetails"].get("thumbnail")
            )
            title = artist["artistdetails"]["label"]
        else:
            media = await media_library._server.AudioLibrary.GetArtists(query)
            media = media.get("artists")
            title = "Artists"
    elif search_type == "library_music":
        library = {MEDIA_TYPE_ALBUM: "Albums", MEDIA_TYPE_ARTIST: "Artists"}
        media = [{"label": name, "type": type_} for type_, name in library.items()]
        title = "Music Library"
    elif search_type == MEDIA_TYPE_MOVIE:
        media = await media_library._server.VideoLibrary.GetMovies(query)
        media = media.get("movies")
        title = "Movies"
    elif search_type == MEDIA_TYPE_TVSHOW:
        if search_id:
            media = await media_library._server.VideoLibrary.GetSeasons(
                {
                    "tvshowid": int(search_id),
                    "properties": ["thumbnail", "season", "tvshowid"],
                }
            )
            media = media.get("seasons")
            tvshow = await media_library._server.VideoLibrary.GetTVShowDetails(
                {"tvshowid": int(search_id), "properties": ["thumbnail"]}
            )
            thumbnail = media_library.thumbnail_url(
                tvshow["tvshowdetails"].get("thumbnail")
            )
            title = tvshow["tvshowdetails"]["label"]
        else:
            media = await media_library._server.VideoLibrary.GetTVShows(query)
            media = media.get("tvshows")
            title = "TV Shows"
    elif search_type == MEDIA_TYPE_SEASON:
        tv_show_id, season_id = search_id.split("/", 1)
        media = await media_library._server.VideoLibrary.GetEpisodes(
            {
                "tvshowid": int(tv_show_id),
                "season": int(season_id),
                "properties": ["thumbnail", "tvshowid", "seasonid"],
            }
        )
        media = media.get("episodes")
        if media:
            season = await media_library._server.VideoLibrary.GetSeasonDetails(
                {"seasonid": int(media[0]["seasonid"]), "properties": ["thumbnail"]}
            )
            thumbnail = media_library.thumbnail_url(
                season["seasondetails"].get("thumbnail")
            )
            title = season["seasondetails"]["label"]

    if media is None:
        return None

    children = []
    for item in media:
        try:
            children.append(item_payload(item, media_library))
        except UnknownMediaType:
            pass

    return BrowseMedia(
        media_class=CONTENT_TYPE_MEDIA_CLASS[search_type],
        media_content_id=search_id,
        media_content_type=search_type,
        title=title,
        can_play=search_type in PLAYABLE_MEDIA_TYPES and search_id,
        can_expand=True,
        children=children,
        thumbnail=thumbnail,
    )

def item_payload(item, media_library):
    """
    Create response payload for a single media item.

    Used by async_browse_media.
    """
    title = item["label"]

    thumbnail = item.get("thumbnail")
    if thumbnail:
        thumbnail = media_library.thumbnail_url(thumbnail)

    if "songid" in item:
        media_content_type = MEDIA_TYPE_TRACK
        media_content_id = f"{item['songid']}"
        can_play = True
        can_expand = False
    elif "albumid" in item:
        media_content_type = MEDIA_TYPE_ALBUM
        media_content_id = f"{item['albumid']}"
        can_play = True
        can_expand = True
    elif "artistid" in item:
        media_content_type = MEDIA_TYPE_ARTIST
        media_content_id = f"{item['artistid']}"
        can_play = True
        can_expand = True
    elif "movieid" in item:
        media_content_type = MEDIA_TYPE_MOVIE
        media_content_id = f"{item['movieid']}"
        can_play = True
        can_expand = False
    elif "episodeid" in item:
        media_content_type = MEDIA_TYPE_EPISODE
        media_content_id = f"{item['episodeid']}"
        can_play = True
        can_expand = False
    elif "seasonid" in item:
        media_content_type = MEDIA_TYPE_SEASON
        media_content_id = f"{item['tvshowid']}/{item['season']}"
        can_play = False
        can_expand = True
    elif "tvshowid" in item:
        media_content_type = MEDIA_TYPE_TVSHOW
        media_content_id = f"{item['tvshowid']}"
        can_play = False
        can_expand = True
    else:
        # this case is for the top folder of each type
        # possible content types: album, artist, movie, library_music, tvshow
        media_content_type = item["type"]
        media_content_id = ""
        can_play = False
        can_expand = True

    try:
        media_class = CONTENT_TYPE_MEDIA_CLASS[media_content_type]
    except KeyError as err:
        _LOGGER.debug("Unknown media type received: %s", media_content_type)
        raise UnknownMediaType from err

    return BrowseMedia(
        title=title,
        media_class=media_class,
        media_content_type=media_content_type,
        media_content_id=media_content_id,
        can_play=can_play,
        can_expand=can_expand,
        thumbnail=thumbnail,
    )

def library_payload(media_library):
    """
    Create response payload to describe contents of a specific library.

    Used by async_browse_media.
    """
    library_info = BrowseMedia(
        media_class=MEDIA_CLASS_DIRECTORY,
        media_content_id="library",
        media_content_type="library",
        title="Media Library",
        can_play=False,
        can_expand=True,
        children=[],
    )

    library = {
        "library_music": "Music",
        MEDIA_TYPE_MOVIE: "Movies",
        MEDIA_TYPE_TVSHOW: "TV shows",
    }
    for item in [{"label": name, "type": type_} for type_, name in library.items()]:
        library_info.children.append(
            item_payload(
                {"label": item["label"], "type": item["type"], "uri": item["type"]},
                media_library,
            )
        )

    return library_info
<|endoftext|>


<commit_before>""" Contains convolution layers """
import logging
import numpy as np
import tensorflow as tf

from .core import Dense, Dropout, AlphaDropout, BatchNormalization, Mip
from .conv import Conv, ConvTranspose, SeparableConv, SeparableConvTranspose, DepthwiseConv, DepthwiseConvTranspose
from .pooling import Pooling, GlobalPooling
from .drop_block import Dropblock
from .resize import ResizeBilinearAdditive, ResizeBilinear, ResizeNn, SubpixelConv
from .utils import add_as_function
from ...utils import unpack_args

logger = logging.getLogger(__name__)

@add_as_function
class ConvBlock:
    """ Complex multi-dimensional block with a sequence of convolutions, batch normalization, activation, pooling,
    dropout and even dense layers.

    Parameters
    ----------
    layout : str
        A sequence of operations:

        - c - convolution
        - t - transposed convolution
        - C - separable convolution
        - T - separable transposed convolution
        - w - depthwise convolution
        - W - depthwise transposed convolution
        - f - dense (fully connected)
        - n - batch normalization
        - a - activation
        - p - pooling (default is max-pooling)
        - v - average pooling
        - P - global pooling (default is max-pooling)
        - V - global average pooling
        - d - dropout
        - D - alpha dropout
        - O - dropblock
        - m - maximum intensity projection (:func:`~.layers.mip`)
        - b - upsample with bilinear resize
        - B - upsample with bilinear additive resize
        - N - upsample with nearest neighbors resize
        - X - upsample with subpixel convolution (:func:`~.layers.subpixel_conv`)
        - R - start residual connection
        - A - start residual connection with bilinear additive upsampling
        - `+` - end residual connection with summation
        - `*` - end residual connection with multiplication
        - `.` - end residual connection with concatenation

        Default is ''.

    filters : int
        Number of filters in the output tensor.
    kernel_size : int
        Kernel size.
    name : str
        Name of the layer that will be used as a scope.
    units : int
        Number of units in the dense layer.
    strides : int
        Default is 1.
    padding : str
        Padding mode, can be 'same' or 'valid'. Default - 'same'.
    data_format : str
        'channels_last' or 'channels_first'. Default - 'channels_last'.
    dilation_rate: int
        Default is 1.
    activation : callable
        Default is `tf.nn.relu`.
    pool_size : int
        Default is 2.
    pool_strides : int
        Default is 2.
    pool_op : str
        Pooling operation ('max', 'mean', 'frac')
    dropout_rate : float
        Default is 0.
    factor : int or tuple of int
        Upsampling factor
    upsampling_layout : str
        Layout for upsampling layers
    is_training : bool or tf.Tensor
        Default is True.
    reuse : bool
        Whether to user layer variables if exist

    dense : dict
        Parameters for dense layers, like initializers, regularalizers, etc.
    conv : dict
        Parameters for convolution layers, like initializers, regularalizers, etc.
    transposed_conv : dict
        Parameters for transposed conv layers, like initializers, regularalizers, etc.
    batch_norm : dict or None
        Parameters for batch normalization layers, like momentum, intiializers, etc
        If None or inculdes parameters 'off' or 'disable' set to True or 1,
        the layer will be excluded whatsoever.
    pooling : dict
        Parameters for pooling layers, like initializers, regularalizers, etc.
    dropout : dict or None
        Parameters for dropout layers, like noise_shape, etc
        If None or inculdes parameters 'off' or 'disable' set to True or 1,
        the layer will be excluded whatsoever.
    dropblock : dict or None
        Parameters for dropblock layers, like dropout_rate, block_size, etc.
    subpixel_conv : dict or None
        Parameters for subpixel convolution like layout, activation, etc.
    resize_bilinear : dict or None
        Parameters for bilinear resize.
    resize_bilinear_additive : dict or None
        Parameters for bilinear additive resize like layout, activation, etc.

    Notes
    -----
    When ``layout`` includes several layers of the same type, each one can have its own parameters,
    if corresponding args are passed as lists (not tuples).

    Spaces may be used to improve readability.

    Examples
    --------
    A simple block: 3x3 conv, batch norm, relu, 2x2 max-pooling with stride 2::

        x = ConvBlock('cnap', filters=32, kernel_size=3)(x)

    A canonical bottleneck block (1x1, 3x3, 1x1 conv with relu in-between)::

        x = ConvBlock('nac nac nac', [64, 64, 256], [1, 3, 1])(x)

    A complex Nd block:

    - 5x5 conv with 32 filters
    - relu
    - 3x3 conv with 32 filters
    - relu
    - 3x3 conv with 64 filters and a spatial stride 2
    - relu
    - batch norm
    - dropout with rate 0.15

    ::

        x = ConvBlock('ca ca ca nd', [32, 32, 64], [5, 3, 3], strides=[1, 1, 2], dropout_rate=.15)(x)

    A residual block::

        x = ConvBlock('R nac nac +', [16, 16, 64], [1, 3, 1])(x)

    """
    C_LAYERS = {
        'a': 'activation',
        'R': 'residual_start',
        '+': 'residual_end',
        '.': 'residual_end',
        '*': 'residual_end',
        'f': 'dense',
        'c': 'conv',
        't': 'transposed_conv',
        'C': 'separable_conv',
        'T': 'separable_conv_transpose',
        'w': 'depthwise_conv',
        'W': 'depthwise_conv_transpose',
        'p': 'pooling',
        'v': 'pooling',
        'P': 'global_pooling',
        'V': 'global_pooling',
        'n': 'batch_norm',
        'd': 'dropout',
        'D': 'alpha_dropout',
        'O': 'dropblock',
        'm': 'mip',
        'A': 'residual_bilinear_additive',
        'b': 'resize_bilinear',
        'B': 'resize_bilinear_additive',
        'N': 'resize_nn',
        'X': 'subpixel_conv'
    }

    FUNC_LAYERS = {
        'activation': None,
        'residual_start': None,
        'residual_end': None,
        'dense': Dense,
        'conv': Conv,
        'transposed_conv': ConvTranspose,
        'separable_conv': SeparableConv,
        'separable_conv_transpose': SeparableConvTranspose,
        'depthwise_conv': DepthwiseConv,
        'depthwise_conv_transpose': DepthwiseConvTranspose,
        'pooling': Pooling,
        'global_pooling': GlobalPooling,
        'batch_norm': BatchNormalization,
        'dropout': Dropout,
        'alpha_dropout': AlphaDropout,
        'dropblock': Dropblock,
        'mip': Mip,
        'residual_bilinear_additive': None,
        'resize_bilinear': ResizeBilinear,
        'resize_bilinear_additive': ResizeBilinearAdditive,
        'resize_nn': ResizeNn,
        'subpixel_conv': SubpixelConv
    }

    DEFAULT_LAYERS = C_LAYERS.keys()
    C_GROUPS = dict(zip(DEFAULT_LAYERS, DEFAULT_LAYERS))
    C_GROUPS.update({
        'C': 'c',
        't': 'c',
        'T': 'c',
        'w': 'c',
        'W': 'c',
        'v': 'p',
        'V': 'P',
        'D': 'd',
        'O': 'd',
        'n': 'd',
        'A': 'b',
        'B': 'b',
        'N': 'b',
        'X': 'b',
        })

    def __init__(self, layout='',
                 filters=0, kernel_size=3, strides=1, dilation_rate=1, depth_multiplier=1,
                 activation=tf.nn.relu,
                 pool_size=2, pool_strides=2,
                 dropout_rate=0.,
                 padding='same', data_format='channels_last', name=None,
                 **kwargs):
        self.layout = layout
        self.filters, self.kernel_size, self.strides = filters, kernel_size, strides
        self.dilation_rate, self.depth_multiplier = dilation_rate, depth_multiplier
        self.activation = activation
        self.pool_size, self.pool_strides = pool_size, pool_strides
        self.dropout_rate = dropout_rate
        self.padding, self.data_format, self.name = padding, data_format, name
        self.kwargs = kwargs

    def add_letter(self, letter, func, name=None):
        """ Add custom letter to layout parsing procedure.

        Parameters
        ----------
        letter : str
            Letter to add.
        func : class
            Tensor-processing layer. Must have layer-like signature (both init and call overloaded).
        name : str
            Name of parameter dictionary. Defaults to `letter`.

        Examples
        --------
        Add custom `Q` letter::

            block = ConvBlock('cnap Q', filters=32, custom_params={'key': 'value'})
            block.add_letter('Q', my_func, 'custom_params')
            x = block(x)
        """
        name = name or letter
        self.C_LAYERS.update({letter: name})
        self.FUNC_LAYERS.update({name: func})
        self.C_GROUPS.update({letter: letter})

    def __call__(self, inputs, training=None):
        layout = self.layout or ''
        layout = layout.replace(' ', '')
        if len(layout) == 0:
            logger.warning('ConvBlock: layout is empty, so there is nothing to do, just returning inputs.')
            return inputs

        if training is None:
            training = self.kwargs.get('is_training')
        if training is None:
            training = self.kwargs.get('training')

        context = None
        if self.name is not None:
            context = tf.variable_scope(self.name, reuse=self.kwargs.get('reuse'))
            context.__enter__()

        layout_dict = {}
        for layer in layout:
            layer_group = self.C_GROUPS[layer]
            if layer_group not in layout_dict:
                layout_dict[layer_group] = [-1, 0]
            layout_dict[layer_group][1] += 1

        residuals = []
        tensor = inputs
        for i, layer in enumerate(layout):
            # Arguments for layer creating; arguments for layer call
            args, call_args = {}, {}

            layer_group = self.C_GROUPS[layer]
            layer_name = self.C_LAYERS[layer]
            layer_fn = self.FUNC_LAYERS[layer_name]
            layout_dict[layer_group][0] += 1

            if layer == 'a':
                args = dict(activation=self.activation)
                layer_fn = unpack_args(args, *layout_dict[layer_group])['activation']
                if layer_fn is not None:
                    tensor = layer_fn(tensor)
            elif layer == 'R':
                residuals += [tensor]
            elif layer == 'A':
                args = dict(factor=self.kwargs.get('factor'), data_format=self.data_format)
                args = unpack_args(args, *layout_dict[layer_group])
                t = self.FUNC_LAYERS['resize_bilinear_additive'](**args, name='rba-%d' % i)(tensor)
                residuals += [t]
            elif layer == '+':
                tensor = tensor + residuals[-1]
                residuals = residuals[:-1]
            elif layer == '*':
                tensor = tensor * residuals[-1]
                residuals = residuals[:-1]
            elif layer == '.':
                axis = -1 if self.data_format == 'channels_last' else 1
                tensor = tf.concat([tensor, residuals[-1]], axis=axis, name='concat-%d' % i)
                residuals = residuals[:-1]
            else:
                layer_args = self.kwargs.get(layer_name, {})
                skip_layer = layer_args is False \
                             or isinstance(layer_args, dict) and layer_args.get('disable', False)

                # Create params for the layer call
                if skip_layer:
                    pass
                elif layer in self.DEFAULT_LAYERS:
                    args = {param: getattr(self, param) if hasattr(self, param) else self.kwargs.get(param, None)
                            for param in layer_fn.params}
                else:
                    if layer not in self.C_LAYERS.keys():
                        raise ValueError('Unknown layer symbol - %s' % layer)

                # Additional params for some layers
                if layer_group == 'd':
                    # Layers that behave differently during train/test
                    call_args.update({'training': training})
                elif layer_group.lower() == 'p':
                    # Choosing pooling operation
                    pool_op = 'mean' if layer.lower() == 'v' else self.kwargs.pop('pool_op', 'max')
                    args['op'] = pool_op
                elif layer_group == 'b':
                    # Additional layots for all the upsampling layers
                    if self.kwargs.get('upsampling_layout'):
                        args['layout'] = self.kwargs.get('upsampling_layout')

                if not skip_layer:
                    args = {**args, **layer_args}
                    args = unpack_args(args, *layout_dict[layer_group])

                    with tf.variable_scope('layer-%d' % i):
                        tensor = layer_fn(**args)(tensor, **call_args)
        tensor = tf.identity(tensor, name='_output')

        if context is not None:
            context.__exit__(None, None, None)

        return tensor

def update_layers(letter, func, name=None):
    """ Add custom letter to layout parsing procedure.

    Parameters
    ----------
    letter : str
        Letter to add.
    func : class
        Tensor-processing layer. Must have layer-like signature (both init and call overloaded).
    name : str
        Name of parameter dictionary. Defaults to `letter`.

    Examples
    --------
    Add custom `Q` letter::

        block = ConvBlock('cnap Q', filters=32, custom_params={'key': 'value'})
        block.add_letter('Q', my_func, 'custom_params')
        x = block(x)
    """
    name = name or letter
    ConvBlock.C_LAYERS.update({letter: name})
    ConvBlock.FUNC_LAYERS.update({name: func})
    ConvBlock.C_GROUPS.update({letter: letter})

@add_as_function
class Upsample:
    """ Upsample inputs with a given factor.

    Parameters
    ----------
    factor : int
        An upsamping scale
    shape : tuple of int
        Shape to upsample to (used by bilinear and NN resize)
    layout : str
        Resizing technique, a sequence of:

        - A - use residual connection with bilinear additive upsampling
        - b - bilinear resize
        - B - bilinear additive upsampling
        - N - nearest neighbor resize
        - t - transposed convolution
        - T - separable transposed convolution
        - X - subpixel convolution

        all other :class:`.ConvBlock` layers are also allowed.

    Examples
    --------
    A simple bilinear upsampling::

        x = upsample(shape=(256, 256), layout='b')(x)

    Upsampling with non-linear normalized transposed convolution::

        x = Upsample(factor=2, layout='nat', kernel_size=3)(x)

    Subpixel convolution with a residual bilinear additive connection::

        x = Upsample(factor=2, layout='AX+')(x)
    """
    def __init__(self, factor=None, shape=None, layout='b', name='upsample', **kwargs):
        self.factor, self.shape, self.layout = factor, shape, layout
        self.name, self.kwargs = name, kwargs

    def __call__(self, inputs, *args, **kwargs):
        if np.all(self.factor == 1):
            return inputs

        if 't' in self.layout or 'T' in self.layout:
            if 'kernel_size' not in self.kwargs:
                self.kwargs['kernel_size'] = self.factor
            if 'strides' not in kwargs:
                self.kwargs['strides'] = self.factor

        return ConvBlock(self.layout, factor=self.factor, shape=self.shape,
                         name=self.name, **self.kwargs)(inputs, *args, **kwargs)
<commit_msg>Rename things<commit_after>""" Contains convolution layers """
import logging
import numpy as np
import tensorflow as tf

from .core import Dense, Dropout, AlphaDropout, BatchNormalization, Mip
from .conv import Conv, ConvTranspose, SeparableConv, SeparableConvTranspose, DepthwiseConv, DepthwiseConvTranspose
from .pooling import Pooling, GlobalPooling
from .drop_block import Dropblock
from .resize import ResizeBilinearAdditive, ResizeBilinear, ResizeNn, SubpixelConv
from .utils import add_as_function
from ...utils import unpack_args

logger = logging.getLogger(__name__)

@add_as_function
class ConvBlock:
    """ Complex multi-dimensional block with a sequence of convolutions, batch normalization, activation, pooling,
    dropout and even dense layers.

    Parameters
    ----------
    layout : str
        A sequence of operations:

        - c - convolution
        - t - transposed convolution
        - C - separable convolution
        - T - separable transposed convolution
        - w - depthwise convolution
        - W - depthwise transposed convolution
        - f - dense (fully connected)
        - n - batch normalization
        - a - activation
        - p - pooling (default is max-pooling)
        - v - average pooling
        - P - global pooling (default is max-pooling)
        - V - global average pooling
        - d - dropout
        - D - alpha dropout
        - O - dropblock
        - m - maximum intensity projection (:func:`~.layers.mip`)
        - b - upsample with bilinear resize
        - B - upsample with bilinear additive resize
        - N - upsample with nearest neighbors resize
        - X - upsample with subpixel convolution (:func:`~.layers.subpixel_conv`)
        - R - start residual connection
        - A - start residual connection with bilinear additive upsampling
        - `+` - end residual connection with summation
        - `*` - end residual connection with multiplication
        - `.` - end residual connection with concatenation

        Default is ''.

    filters : int
        Number of filters in the output tensor.
    kernel_size : int
        Kernel size.
    name : str
        Name of the layer that will be used as a scope.
    units : int
        Number of units in the dense layer.
    strides : int
        Default is 1.
    padding : str
        Padding mode, can be 'same' or 'valid'. Default - 'same'.
    data_format : str
        'channels_last' or 'channels_first'. Default - 'channels_last'.
    dilation_rate: int
        Default is 1.
    activation : callable
        Default is `tf.nn.relu`.
    pool_size : int
        Default is 2.
    pool_strides : int
        Default is 2.
    pool_op : str
        Pooling operation ('max', 'mean', 'frac')
    dropout_rate : float
        Default is 0.
    factor : int or tuple of int
        Upsampling factor
    upsampling_layout : str
        Layout for upsampling layers
    is_training : bool or tf.Tensor
        Default is True.
    reuse : bool
        Whether to user layer variables if exist

    dense : dict
        Parameters for dense layers, like initializers, regularalizers, etc.
    conv : dict
        Parameters for convolution layers, like initializers, regularalizers, etc.
    transposed_conv : dict
        Parameters for transposed conv layers, like initializers, regularalizers, etc.
    batch_norm : dict or None
        Parameters for batch normalization layers, like momentum, intiializers, etc
        If None or inculdes parameters 'off' or 'disable' set to True or 1,
        the layer will be excluded whatsoever.
    pooling : dict
        Parameters for pooling layers, like initializers, regularalizers, etc.
    dropout : dict or None
        Parameters for dropout layers, like noise_shape, etc
        If None or inculdes parameters 'off' or 'disable' set to True or 1,
        the layer will be excluded whatsoever.
    dropblock : dict or None
        Parameters for dropblock layers, like dropout_rate, block_size, etc.
    subpixel_conv : dict or None
        Parameters for subpixel convolution like layout, activation, etc.
    resize_bilinear : dict or None
        Parameters for bilinear resize.
    resize_bilinear_additive : dict or None
        Parameters for bilinear additive resize like layout, activation, etc.

    Notes
    -----
    When ``layout`` includes several layers of the same type, each one can have its own parameters,
    if corresponding args are passed as lists (not tuples).

    Spaces may be used to improve readability.

    Examples
    --------
    A simple block: 3x3 conv, batch norm, relu, 2x2 max-pooling with stride 2::

        x = ConvBlock('cnap', filters=32, kernel_size=3)(x)

    A canonical bottleneck block (1x1, 3x3, 1x1 conv with relu in-between)::

        x = ConvBlock('nac nac nac', [64, 64, 256], [1, 3, 1])(x)

    A complex Nd block:

    - 5x5 conv with 32 filters
    - relu
    - 3x3 conv with 32 filters
    - relu
    - 3x3 conv with 64 filters and a spatial stride 2
    - relu
    - batch norm
    - dropout with rate 0.15

    ::

        x = ConvBlock('ca ca ca nd', [32, 32, 64], [5, 3, 3], strides=[1, 1, 2], dropout_rate=.15)(x)

    A residual block::

        x = ConvBlock('R nac nac +', [16, 16, 64], [1, 3, 1])(x)

    """
    LETTERS_LAYERS = {
        'a': 'activation',
        'R': 'residual_start',
        '+': 'residual_end',
        '.': 'residual_end',
        '*': 'residual_end',
        'f': 'dense',
        'c': 'conv',
        't': 'transposed_conv',
        'C': 'separable_conv',
        'T': 'separable_conv_transpose',
        'w': 'depthwise_conv',
        'W': 'depthwise_conv_transpose',
        'p': 'pooling',
        'v': 'pooling',
        'P': 'global_pooling',
        'V': 'global_pooling',
        'n': 'batch_norm',
        'd': 'dropout',
        'D': 'alpha_dropout',
        'O': 'dropblock',
        'm': 'mip',
        'A': 'residual_bilinear_additive',
        'b': 'resize_bilinear',
        'B': 'resize_bilinear_additive',
        'N': 'resize_nn',
        'X': 'subpixel_conv'
    }

    LAYERS_CLASSES = {
        'activation': None,
        'residual_start': None,
        'residual_end': None,
        'dense': Dense,
        'conv': Conv,
        'transposed_conv': ConvTranspose,
        'separable_conv': SeparableConv,
        'separable_conv_transpose': SeparableConvTranspose,
        'depthwise_conv': DepthwiseConv,
        'depthwise_conv_transpose': DepthwiseConvTranspose,
        'pooling': Pooling,
        'global_pooling': GlobalPooling,
        'batch_norm': BatchNormalization,
        'dropout': Dropout,
        'alpha_dropout': AlphaDropout,
        'dropblock': Dropblock,
        'mip': Mip,
        'residual_bilinear_additive': None,
        'resize_bilinear': ResizeBilinear,
        'resize_bilinear_additive': ResizeBilinearAdditive,
        'resize_nn': ResizeNn,
        'subpixel_conv': SubpixelConv
    }

    DEFAULT_LETTERS = LETTERS_LAYERS.keys()
    LETTERS_GROUPS = dict(zip(DEFAULT_LETTERS, DEFAULT_LETTERS))
    LETTERS_GROUPS.update({
        'C': 'c',
        't': 'c',
        'T': 'c',
        'w': 'c',
        'W': 'c',
        'v': 'p',
        'V': 'P',
        'D': 'd',
        'O': 'd',
        'n': 'd',
        'A': 'b',
        'B': 'b',
        'N': 'b',
        'X': 'b',
        })

    def __init__(self, layout='',
                 filters=0, kernel_size=3, strides=1, dilation_rate=1, depth_multiplier=1,
                 activation=tf.nn.relu,
                 pool_size=2, pool_strides=2,
                 dropout_rate=0.,
                 padding='same', data_format='channels_last', name=None,
                 **kwargs):
        self.layout = layout
        self.filters, self.kernel_size, self.strides = filters, kernel_size, strides
        self.dilation_rate, self.depth_multiplier = dilation_rate, depth_multiplier
        self.activation = activation
        self.pool_size, self.pool_strides = pool_size, pool_strides
        self.dropout_rate = dropout_rate
        self.padding, self.data_format, self.name = padding, data_format, name
        self.kwargs = kwargs

    def add_letter(self, letter, cls, name=None):
        """ Add custom letter to layout parsing procedure.

        Parameters
        ----------
        letter : str
            Letter to add.
        cls : class
            Tensor-processing layer. Must have layer-like signature (both init and call overloaded).
        name : str
            Name of parameter dictionary. Defaults to `letter`.

        Examples
        --------
        Add custom `Q` letter::

            block = ConvBlock('cnap Q', filters=32, custom_params={'key': 'value'})
            block.add_letter('Q', my_func, 'custom_params')
            x = block(x)
        """
        name = name or letter
        self.LETTERS_LAYERS.update({letter: name})
        self.LAYERS_CLASSES.update({name: cls})
        self.LETTERS_GROUPS.update({letter: letter})

    def __call__(self, inputs, training=None):
        layout = self.layout or ''
        layout = layout.replace(' ', '')
        if len(layout) == 0:
            logger.warning('ConvBlock: layout is empty, so there is nothing to do, just returning inputs.')
            return inputs

        # Getting `training` indicator from kwargs by its aliases
        if training is None:
            training = self.kwargs.get('is_training')
        if training is None:
            training = self.kwargs.get('training')

        context = None
        if self.name is not None:
            context = tf.variable_scope(self.name, reuse=self.kwargs.get('reuse'))
            context.__enter__()

        layout_dict = {}
        for layer in layout:
            layer_group = self.LETTERS_GROUPS[layer]
            if layer_group not in layout_dict:
                layout_dict[layer_group] = [-1, 0]
            layout_dict[layer_group][1] += 1

        residuals = []
        tensor = inputs
        for i, layer in enumerate(layout):
            # Arguments for layer creating; arguments for layer call
            args, call_args = {}, {}

            layer_group = self.LETTERS_GROUPS[layer]
            layer_name = self.LETTERS_LAYERS[layer]
            layer_class = self.LAYERS_CLASSES[layer_name]
            layout_dict[layer_group][0] += 1

            if layer == 'a':
                args = dict(activation=self.activation)
                activation_fn = unpack_args(args, *layout_dict[layer_group])['activation']
                if activation_fn is not None:
                    tensor = activation_fn(tensor)
            elif layer == 'R':
                residuals += [tensor]
            elif layer == 'A':
                args = dict(factor=self.kwargs.get('factor'), data_format=self.data_format)
                args = unpack_args(args, *layout_dict[layer_group])
                t = self.LAYERS_CLASSES['resize_bilinear_additive'](**args, name='rba-%d' % i)(tensor)
                residuals += [t]
            elif layer == '+':
                tensor = tensor + residuals[-1]
                residuals = residuals[:-1]
            elif layer == '*':
                tensor = tensor * residuals[-1]
                residuals = residuals[:-1]
            elif layer == '.':
                axis = -1 if self.data_format == 'channels_last' else 1
                tensor = tf.concat([tensor, residuals[-1]], axis=axis, name='concat-%d' % i)
                residuals = residuals[:-1]
            else:
                layer_args = self.kwargs.get(layer_name, {})
                skip_layer = layer_args is False \
                             or isinstance(layer_args, dict) and layer_args.get('disable', False)

                # Create params for the layer call
                if skip_layer:
                    pass
                elif layer in self.DEFAULT_LETTERS:
                    args = {param: getattr(self, param) if hasattr(self, param) else self.kwargs.get(param, None)
                            for param in layer_class.params}
                else:
                    if layer not in self.LETTERS_LAYERS.keys():
                        raise ValueError('Unknown layer symbol - %s' % layer)

                # Additional params for some layers
                if layer_group == 'd':
                    # Layers that behave differently during train/test
                    call_args.update({'training': training})
                elif layer_group.lower() == 'p':
                    # Choosing pooling operation
                    pool_op = 'mean' if layer.lower() == 'v' else self.kwargs.pop('pool_op', 'max')
                    args['op'] = pool_op
                elif layer_group == 'b':
                    # Additional layots for all the upsampling layers
                    if self.kwargs.get('upsampling_layout'):
                        args['layout'] = self.kwargs.get('upsampling_layout')

                if not skip_layer:
                    args = {**args, **layer_args}
                    args = unpack_args(args, *layout_dict[layer_group])

                    with tf.variable_scope('layer-%d' % i):
                        tensor = layer_class(**args)(tensor, **call_args)
        tensor = tf.identity(tensor, name='_output')

        if context is not None:
            context.__exit__(None, None, None)

        return tensor

def update_layers(letter, func, name=None):
    """ Add custom letter to layout parsing procedure.

    Parameters
    ----------
    letter : str
        Letter to add.
    func : class
        Tensor-processing layer. Must have layer-like signature (both init and call overloaded).
    name : str
        Name of parameter dictionary. Defaults to `letter`.

    Examples
    --------
    Add custom `Q` letter::

        block = ConvBlock('cnap Q', filters=32, custom_params={'key': 'value'})
        block.add_letter('Q', my_func, 'custom_params')
        x = block(x)
    """
    name = name or letter
    ConvBlock.LETTERS_LAYERS.update({letter: name})
    ConvBlock.LAYERS_CLASSES.update({name: func})
    ConvBlock.LETTERS_GROUPS.update({letter: letter})

@add_as_function
class Upsample:
    """ Upsample inputs with a given factor.

    Parameters
    ----------
    factor : int
        An upsamping scale
    shape : tuple of int
        Shape to upsample to (used by bilinear and NN resize)
    layout : str
        Resizing technique, a sequence of:

        - A - use residual connection with bilinear additive upsampling
        - b - bilinear resize
        - B - bilinear additive upsampling
        - N - nearest neighbor resize
        - t - transposed convolution
        - T - separable transposed convolution
        - X - subpixel convolution

        all other :class:`.ConvBlock` layers are also allowed.

    Examples
    --------
    A simple bilinear upsampling::

        x = upsample(shape=(256, 256), layout='b')(x)

    Upsampling with non-linear normalized transposed convolution::

        x = Upsample(factor=2, layout='nat', kernel_size=3)(x)

    Subpixel convolution with a residual bilinear additive connection::

        x = Upsample(factor=2, layout='AX+')(x)
    """
    def __init__(self, factor=None, shape=None, layout='b', name='upsample', **kwargs):
        self.factor, self.shape, self.layout = factor, shape, layout
        self.name, self.kwargs = name, kwargs

    def __call__(self, inputs, *args, **kwargs):
        if np.all(self.factor == 1):
            return inputs

        if 't' in self.layout or 'T' in self.layout:
            if 'kernel_size' not in self.kwargs:
                self.kwargs['kernel_size'] = self.factor
            if 'strides' not in kwargs:
                self.kwargs['strides'] = self.factor

        return ConvBlock(self.layout, factor=self.factor, shape=self.shape,
                         name=self.name, **self.kwargs)(inputs, *args, **kwargs)
<|endoftext|>


<commit_before># -----------------------------------------------------------------------------
# Copyright © 2014-2015 Colin Duquesnoy
# Copyright © 2009- The Spyder Development Team
#
# Licensed under the terms of the MIT License
# (see LICENSE.txt for details)
# -----------------------------------------------------------------------------

"""Provides QtCore classes and functions."""
from typing import TYPE_CHECKING

from . import PYQT6, PYQT5, PYSIDE2, PYSIDE6, QtBindingsNotFoundError

if PYQT5:
    from PyQt5.QtCore import *
    from PyQt5.QtCore import pyqtSignal as Signal
    from PyQt5.QtCore import pyqtBoundSignal as SignalInstance
    from PyQt5.QtCore import pyqtSlot as Slot
    from PyQt5.QtCore import pyqtProperty as Property
    from PyQt5.QtCore import QT_VERSION_STR as __version__

    # For issue #153 and updated for issue #305
    from PyQt5.QtCore import QDateTime
    QDate.toPython = lambda self, *args, **kwargs: self.toPyDate(*args, **kwargs)
    QDateTime.toPython = lambda self, *args, **kwargs: self.toPyDateTime(*args, **kwargs)
    QTime.toPython = lambda self, *args, **kwargs: self.toPyTime(*args, **kwargs)

    # Map missing methods on PyQt5 5.12
    QTextStreamManipulator.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)

    # Those are imported from `import *`
    del pyqtSignal, pyqtBoundSignal, pyqtSlot, pyqtProperty, QT_VERSION_STR

elif PYQT6:
    from PyQt6 import QtCore
    from PyQt6.QtCore import *
    from PyQt6.QtCore import pyqtSignal as Signal
    from PyQt6.QtCore import pyqtBoundSignal as SignalInstance
    from PyQt6.QtCore import pyqtSlot as Slot
    from PyQt6.QtCore import pyqtProperty as Property
    from PyQt6.QtCore import QT_VERSION_STR as __version__

    # For issue #153 and updated for issue #305
    from PyQt6.QtCore import QDate, QDateTime, QTime
    QDate.toPython = lambda self, *args, **kwargs: self.toPyDate(*args, **kwargs)
    QDateTime.toPython = lambda self, *args, **kwargs: self.toPyDateTime(*args, **kwargs)
    QTime.toPython = lambda self, *args, **kwargs: self.toPyTime(*args, **kwargs)

    # For issue #311
    # Seems like there is an error with sip. Without first
    # trying to import `PyQt6.QtGui.Qt`, some functions like
    # `PyQt6.QtCore.Qt.mightBeRichText` are missing.
    if not TYPE_CHECKING:
        try:
            from PyQt6.QtGui import Qt
        except ImportError:
            pass

    # Map missing methods
    QCoreApplication.exec_ = QCoreApplication.exec
    QEventLoop.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
    QThread.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
    QTextStreamManipulator.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)

    QLibraryInfo.location = QLibraryInfo.path

    # Those are imported from `import *`
    del pyqtSignal, pyqtBoundSignal, pyqtSlot, pyqtProperty, QT_VERSION_STR

    # Allow unscoped access for enums inside the QtCore module
    from .enums_compat import promote_enums
    promote_enums(QtCore)
    del QtCore

    # Alias deprecated ItemDataRole enum values removed in Qt6
    Qt.BackgroundColorRole = Qt.ItemDataRole.BackgroundColorRole = Qt.BackgroundRole
    Qt.TextColorRole = Qt.ItemDataRole.TextColorRole = Qt.ForegroundRole
    # Alias for MiddleButton removed in PyQt6 but available in PyQt5, PySide2 and PySide6
    Qt.MidButton = Qt.MiddleButton

elif PYSIDE2:
    from PySide2.QtCore import *

    try:  # may be limited to PySide-5.11a1 only
        from PySide2.QtGui import QStringListModel
    except Exception:
        pass

    import PySide2.QtCore
    __version__ = PySide2.QtCore.__version__

    # Missing QtGui utility functions on Qt
    if getattr(Qt, 'mightBeRichText', None) is None:
        try:
            from PySide2.QtGui import Qt as guiQt
            Qt.mightBeRichText = guiQt.mightBeRichText
            del guiQt
        except ImportError:
            # Fails with PySide2 5.12.0
            pass

elif PYSIDE6:
    from PySide6.QtCore import *
    import PySide6.QtCore
    __version__ = PySide6.QtCore.__version__

    # Missing QtGui utility functions on Qt
    if getattr(Qt, 'mightBeRichText', None) is None:
        from PySide6.QtGui import Qt as guiQt
        Qt.mightBeRichText = guiQt.mightBeRichText
        del guiQt

    # Alias deprecated ItemDataRole enum values removed in Qt6
    Qt.BackgroundColorRole = Qt.ItemDataRole.BackgroundColorRole = Qt.BackgroundRole
    Qt.TextColorRole = Qt.ItemDataRole.TextColorRole = Qt.ForegroundRole
    Qt.MidButton = Qt.MouseButton.MiddleButton = Qt.MiddleButton

    # Map DeprecationWarning methods
    QCoreApplication.exec_ = QCoreApplication.exec
    QEventLoop.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
    QThread.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
    QTextStreamManipulator.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)

else:
    raise QtBindingsNotFoundError()
<commit_msg>Update qtpy/QtCore.py<commit_after># -----------------------------------------------------------------------------
# Copyright © 2014-2015 Colin Duquesnoy
# Copyright © 2009- The Spyder Development Team
#
# Licensed under the terms of the MIT License
# (see LICENSE.txt for details)
# -----------------------------------------------------------------------------

"""Provides QtCore classes and functions."""
from typing import TYPE_CHECKING

from . import PYQT6, PYQT5, PYSIDE2, PYSIDE6, QtBindingsNotFoundError

if PYQT5:
    from PyQt5.QtCore import *
    from PyQt5.QtCore import pyqtSignal as Signal
    from PyQt5.QtCore import pyqtBoundSignal as SignalInstance
    from PyQt5.QtCore import pyqtSlot as Slot
    from PyQt5.QtCore import pyqtProperty as Property
    from PyQt5.QtCore import QT_VERSION_STR as __version__

    # For issue #153 and updated for issue #305
    from PyQt5.QtCore import QDate, QDateTime, QTime
    QDate.toPython = lambda self, *args, **kwargs: self.toPyDate(*args, **kwargs)
    QDateTime.toPython = lambda self, *args, **kwargs: self.toPyDateTime(*args, **kwargs)
    QTime.toPython = lambda self, *args, **kwargs: self.toPyTime(*args, **kwargs)

    # Map missing methods on PyQt5 5.12
    QTextStreamManipulator.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)

    # Those are imported from `import *`
    del pyqtSignal, pyqtBoundSignal, pyqtSlot, pyqtProperty, QT_VERSION_STR

elif PYQT6:
    from PyQt6 import QtCore
    from PyQt6.QtCore import *
    from PyQt6.QtCore import pyqtSignal as Signal
    from PyQt6.QtCore import pyqtBoundSignal as SignalInstance
    from PyQt6.QtCore import pyqtSlot as Slot
    from PyQt6.QtCore import pyqtProperty as Property
    from PyQt6.QtCore import QT_VERSION_STR as __version__

    # For issue #153 and updated for issue #305
    from PyQt6.QtCore import QDate, QDateTime, QTime
    QDate.toPython = lambda self, *args, **kwargs: self.toPyDate(*args, **kwargs)
    QDateTime.toPython = lambda self, *args, **kwargs: self.toPyDateTime(*args, **kwargs)
    QTime.toPython = lambda self, *args, **kwargs: self.toPyTime(*args, **kwargs)

    # For issue #311
    # Seems like there is an error with sip. Without first
    # trying to import `PyQt6.QtGui.Qt`, some functions like
    # `PyQt6.QtCore.Qt.mightBeRichText` are missing.
    if not TYPE_CHECKING:
        try:
            from PyQt6.QtGui import Qt
        except ImportError:
            pass

    # Map missing methods
    QCoreApplication.exec_ = QCoreApplication.exec
    QEventLoop.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
    QThread.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
    QTextStreamManipulator.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)

    QLibraryInfo.location = QLibraryInfo.path

    # Those are imported from `import *`
    del pyqtSignal, pyqtBoundSignal, pyqtSlot, pyqtProperty, QT_VERSION_STR

    # Allow unscoped access for enums inside the QtCore module
    from .enums_compat import promote_enums
    promote_enums(QtCore)
    del QtCore

    # Alias deprecated ItemDataRole enum values removed in Qt6
    Qt.BackgroundColorRole = Qt.ItemDataRole.BackgroundColorRole = Qt.BackgroundRole
    Qt.TextColorRole = Qt.ItemDataRole.TextColorRole = Qt.ForegroundRole
    # Alias for MiddleButton removed in PyQt6 but available in PyQt5, PySide2 and PySide6
    Qt.MidButton = Qt.MiddleButton

elif PYSIDE2:
    from PySide2.QtCore import *

    try:  # may be limited to PySide-5.11a1 only
        from PySide2.QtGui import QStringListModel
    except Exception:
        pass

    import PySide2.QtCore
    __version__ = PySide2.QtCore.__version__

    # Missing QtGui utility functions on Qt
    if getattr(Qt, 'mightBeRichText', None) is None:
        try:
            from PySide2.QtGui import Qt as guiQt
            Qt.mightBeRichText = guiQt.mightBeRichText
            del guiQt
        except ImportError:
            # Fails with PySide2 5.12.0
            pass

elif PYSIDE6:
    from PySide6.QtCore import *
    import PySide6.QtCore
    __version__ = PySide6.QtCore.__version__

    # Missing QtGui utility functions on Qt
    if getattr(Qt, 'mightBeRichText', None) is None:
        from PySide6.QtGui import Qt as guiQt
        Qt.mightBeRichText = guiQt.mightBeRichText
        del guiQt

    # Alias deprecated ItemDataRole enum values removed in Qt6
    Qt.BackgroundColorRole = Qt.ItemDataRole.BackgroundColorRole = Qt.BackgroundRole
    Qt.TextColorRole = Qt.ItemDataRole.TextColorRole = Qt.ForegroundRole
    Qt.MidButton = Qt.MouseButton.MiddleButton = Qt.MiddleButton

    # Map DeprecationWarning methods
    QCoreApplication.exec_ = QCoreApplication.exec
    QEventLoop.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
    QThread.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
    QTextStreamManipulator.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)

else:
    raise QtBindingsNotFoundError()
<|endoftext|>


<commit_before># Copyright (c) 2015 Yubico AB
# All rights reserved.
#
#   Redistribution and use in source and binary forms, with or
#   without modification, are permitted provided that the following
#   conditions are met:
#
#    1. Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#    2. Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import ctypes
import ctypes.util
import os
import sys
import usb.core
import usb.backend.libusb1 as libusb1
import usb.backend.libusb0 as libusb0
import usb.backend.openusb as openusb

def _find_library(libname):
    libpath = os.path.join(os.path.dirname(sys.executable), libname)
    if sys.platform == 'win32':
        libpath += '.dll'
    if os.path.isfile(libpath):
        return libpath
    if sys.platform == 'darwin':
        libpath = os.path.join(os.path.dirname(sys.executable), "../Frameworks", libname)
        if os.path.isfile(libpath):
            return libpath
    return ctypes.util.find_library(libname)

def _load_usb_backend():
    for m in (libusb1, openusb, libusb0):
        backend = m.get_backend(find_library=_find_library)
        if backend is not None:
            return backend

_usb_backend = None

def get_usb_backend():
    global _usb_backend
    _usb_backend = _usb_backend or _load_usb_backend()
    return _usb_backend

class LibUsb1Version(ctypes.Structure):
    _fields_ = [
        ('major', ctypes.c_uint16),
        ('minor', ctypes.c_uint16),
        ('micro', ctypes.c_uint16),
        ('nano', ctypes.c_uint16),
        ('rc', ctypes.c_char_p),
        ('describe', ctypes.c_char_p)
    ]

def get_usb_backend_version():
    backend = get_usb_backend()
    if backend is None:
        return None
    elif isinstance(backend, libusb1._LibUSB):
        lib = backend.lib
        lib.libusb_get_version.restype = ctypes.POINTER(LibUsb1Version)
        version = lib.libusb_get_version().contents
        return 'libusb {0.major}.{0.minor}.{0.micro}'.format(version)
    elif isinstance(backend, openusb._OpenUSB):
        from usb.backend.openusb import _lib as lib
        usb.core.find(True)  # OpenUSB seems to hang if not called.
    elif isinstance(backend, libusb0._LibUSB):
        from usb.backend.libusb0 import _lib as lib
    return lib._name
<commit_msg>Also try working directory when looking for libraries<commit_after># Copyright (c) 2015 Yubico AB
# All rights reserved.
#
#   Redistribution and use in source and binary forms, with or
#   without modification, are permitted provided that the following
#   conditions are met:
#
#    1. Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#    2. Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import ctypes
import ctypes.util
import os
import sys
import usb.core
import usb.backend.libusb1 as libusb1
import usb.backend.libusb0 as libusb0
import usb.backend.openusb as openusb

def _find_library(libname):
    # Look in working directory
    if os.path.isfile(libname):
        return libname
    elif sys.platform == 'win32' and os.path.isfile(libname + '.dll'):
        return libname + '.dll'
    # Look next to executable
    libpath = os.path.join(os.path.dirname(sys.executable), libname)
    if os.path.isfile(libpath):
        return libpath
    elif sys.platform == 'win32' and os.path.isfile(libpath + '.dll'):
        return libpath + '.dll'
    # For .app bundles
    if sys.platform == 'darwin':
        libpath = os.path.join(os.path.dirname(sys.executable), "../Frameworks", libname)
        if os.path.isfile(libpath):
            return libpath
    return ctypes.util.find_library(libname)

def _load_usb_backend():
    for m in (libusb1, openusb, libusb0):
        backend = m.get_backend(find_library=_find_library)
        if backend is not None:
            return backend

_usb_backend = None

def get_usb_backend():
    global _usb_backend
    _usb_backend = _usb_backend or _load_usb_backend()
    return _usb_backend

class LibUsb1Version(ctypes.Structure):
    _fields_ = [
        ('major', ctypes.c_uint16),
        ('minor', ctypes.c_uint16),
        ('micro', ctypes.c_uint16),
        ('nano', ctypes.c_uint16),
        ('rc', ctypes.c_char_p),
        ('describe', ctypes.c_char_p)
    ]

def get_usb_backend_version():
    backend = get_usb_backend()
    if backend is None:
        return None
    elif isinstance(backend, libusb1._LibUSB):
        lib = backend.lib
        lib.libusb_get_version.restype = ctypes.POINTER(LibUsb1Version)
        version = lib.libusb_get_version().contents
        return 'libusb {0.major}.{0.minor}.{0.micro}'.format(version)
    elif isinstance(backend, openusb._OpenUSB):
        from usb.backend.openusb import _lib as lib
        usb.core.find(True)  # OpenUSB seems to hang if not called.
    elif isinstance(backend, libusb0._LibUSB):
        from usb.backend.libusb0 import _lib as lib
    return lib._name
<|endoftext|>