<gh_stars>100-1000
# Copyright (c) 1996-2015 PSERC. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

"""Tests of C{qps_pypower} QP solvers.
"""

from numpy import array, zeros, shape, Inf

from scipy.sparse import csr_matrix as sparse

from pypower.ppoption import ppoption
from pypower.cplex_options import cplex_options
from pypower.mosek_options import mosek_options
from pypower.qps_pypower import qps_pypower
from pypower.util import have_fcn

from pypower.t.t_begin import t_begin
from pypower.t.t_is import t_is
from pypower.t.t_end import t_end
from pypower.t.t_ok import t_ok
from pypower.t.t_skip import t_skip

def t_qps_pypower(quiet=False):
    """Tests of C{qps_pypower} QP solvers.

    @author: <NAME> (PSERC Cornell)
    """
    algs = [200, 250, 400, 500, 600, 700]
    names = ['PIPS', 'sc-PIPS', 'IPOPT', 'CPLEX', 'MOSEK', 'Gurobi']
    check = [None, None, 'ipopt', 'cplex', 'mosek', 'gurobipy']

    n = 36
    t_begin(n * len(algs), quiet)

    for k in range(len(algs)):
        if check[k] is not None and not have_fcn(check[k]):
            t_skip(n, '%s not installed' % names[k])
        else:
            opt = {'verbose': 0, 'alg': algs[k]}

            if names[k] == 'PIPS' or names[k] == 'sc-PIPS':
                opt['pips_opt'] = {}
                opt['pips_opt']['comptol'] = 1e-8
            if names[k] == 'CPLEX':
#               alg = 0        ## default uses barrier method with NaN bug in lower lim multipliers
                alg = 2        ## use dual simplex
                ppopt = ppoption(CPLEX_LPMETHOD = alg, CPLEX_QPMETHOD = min([4, alg]))
                opt['cplex_opt'] = cplex_options([], ppopt)

            if names[k] == 'MOSEK':
#                alg = 5        ## use dual simplex
                ppopt = ppoption()
#                ppopt = ppoption(ppopt, MOSEK_LP_ALG = alg)
                ppopt = ppoption(ppopt, MOSEK_GAP_TOL=1e-9)
                opt['mosek_opt'] = mosek_options([], ppopt)

            t = '%s - 3-d LP : ' % names[k]
            ## example from 'doc linprog'
            c = array([-5, -4, -6], float)
            A = sparse([[1, -1,  1],
                        [3,  2,  4],
                        [3,  2,  0]], dtype=float)
            l = None
            u = array([20, 42, 30], float)
            xmin = array([0, 0, 0], float)
            x0 = None
            x, f, s, _, lam = qps_pypower(None, c, A, l, u, xmin, None, None, opt)
            t_is(s, 1, 12, [t, 'success'])
            t_is(x, [0, 15, 3], 6, [t, 'x'])
            t_is(f, -78, 6, [t, 'f'])
            t_is(lam['mu_l'], [0, 0, 0], 13, [t, 'lam.mu_l'])
            t_is(lam['mu_u'], [0, 1.5, 0.5], 9, [t, 'lam.mu_u'])
            t_is(lam['lower'], [1, 0, 0], 9, [t, 'lam.lower'])
            t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper'])

            t = '%s - unconstrained 3-d quadratic : ' % names[k]
            ## from http://www.akiti.ca/QuadProgEx0Constr.html
            H = sparse([
                [ 5, -2, -1],
                [-2,  4,  3],
                [-1,  3,  5]
            ], dtype=float)
            c = array([2, -35, -47], float)
            x0 = array([0, 0, 0], float)
            x, f, s, _, lam = qps_pypower(H, c, opt=opt)
            t_is(s, 1, 12, [t, 'success'])
            t_is(x, [3, 5, 7], 8, [t, 'x'])
            t_is(f, -249, 13, [t, 'f'])
            t_ok(len(lam['mu_l']) == 0, [t, 'lam.mu_l'])
            t_ok(len(lam['mu_u']) == 0, [t, 'lam.mu_u'])
            t_is(lam['lower'], zeros(shape(x)), 13, [t, 'lam.lower'])
            t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper'])

            t = '%s - constrained 2-d QP : ' % names[k]
            ## example from 'doc quadprog'
            H = sparse([[ 1, -1],
                        [-1,  2]], dtype=float)
            c = array([-2, -6], float)
            A = sparse([[ 1, 1],
                        [-1, 2],
                        [ 2, 1]], dtype=float)
            l = None
            u = array([2, 2, 3], float)
            xmin = array([0, 0])
            x0 = None
            x, f, s, _, lam = qps_pypower(H, c, A, l, u, xmin, None, x0, opt)
            t_is(s, 1, 12, [t, 'success'])
            t_is(x, array([2., 4.]) / 3, 7, [t, 'x'])
            t_is(f, -74. / 9, 6, [t, 'f'])
            t_is(lam['mu_l'], [0., 0., 0.], 13, [t, 'lam.mu_l'])
            t_is(lam['mu_u'], array([28., 4., 0.]) / 9, 7, [t, 'lam.mu_u'])
            t_is(lam['lower'], zeros(shape(x)), 8, [t, 'lam.lower'])
            t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper'])

            t = '%s - constrained 4-d QP : ' % names[k]
            ## from http://www.jmu.edu/docs/sasdoc/sashtml/iml/chap8/sect12.htm
            H = sparse([[1003.1,  4.3,     6.3,     5.9],
                        [4.3,     2.2,     2.1,     3.9],
                        [6.3,     2.1,     3.5,     4.8],
                        [5.9,     3.9,     4.8,    10.0]])
            c = zeros(4)
            A = sparse([[   1,       1,       1,       1],
                        [0.17,    0.11,    0.10,    0.18]])
            l = array([1, 0.10])
            u = array([1, Inf])
            xmin = zeros(4)
            x0 = array([1, 0, 0, 1], float)
            x, f, s, _, lam = qps_pypower(H, c, A, l, u, xmin, None, x0, opt)
            t_is(s, 1, 12, [t, 'success'])
            t_is(x, array([0, 2.8, 0.2, 0]) / 3, 5, [t, 'x'])
            t_is(f, 3.29 / 3, 6, [t, 'f'])
            t_is(lam['mu_l'], array([6.58, 0]) / 3, 6, [t, 'lam.mu_l'])
            t_is(lam['mu_u'], [0, 0], 13, [t, 'lam.mu_u'])
            t_is(lam['lower'], [2.24, 0, 0, 1.7667], 4, [t, 'lam.lower'])
            t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper'])

            t = '%s - (dict) constrained 4-d QP : ' % names[k]
            p = {'H': H, 'A': A, 'l': l, 'u': u, 'xmin': xmin, 'x0': x0, 'opt': opt}
            x, f, s, _, lam = qps_pypower(p)
            t_is(s, 1, 12, [t, 'success'])
            t_is(x, array([0, 2.8, 0.2, 0]) / 3, 5, [t, 'x'])
            t_is(f, 3.29 / 3, 6, [t, 'f'])
            t_is(lam['mu_l'], array([6.58, 0]) / 3, 6, [t, 'lam.mu_l'])
            t_is(lam['mu_u'], [0, 0], 13, [t, 'lam.mu_u'])
            t_is(lam['lower'], [2.24, 0, 0, 1.7667], 4, [t, 'lam.lower'])
            t_is(lam['upper'], zeros(shape(x)), 13, [t, 'lam.upper'])

            t = '%s - infeasible LP : ' % names[k]
            p = {'A': sparse([1, 1]), 'c': array([1, 1]), 'u': array([-1]),
                 'xmin': array([0, 0]), 'opt': opt}
            x, f, s, _, lam = qps_pypower(p)
            t_ok(s <= 0, [t, 'no success'])

    t_end()

if __name__ == '__main__':
    t_qps_pypower(quiet=False)


#!/usr/bin/env python3

import numpy as np
import rclpy
import rclpy.qos
from halodi_msgs.msg import (
    ReferenceFrameName,
    TaskSpaceCommand,
    WholeBodyControllerCommand
)
from rclpy.node import Node
from scipy.spatial.transform import Rotation

def generate_task_space_command_msg(
    body_frame_id, expressed_in_frame_id, xyzrpy, z_up=True
):
    """Generates a task space command msg.

    Parameters:
    - body_frame_id (enum): body part to be moved, e.g. ReferenceFrameName.PELVIS
    - expressed_in_frame_id (enum): reference frame for body_frame_id, e.g. ReferenceFrameName.BASE
    - xyzrpy (array of 6 floats): desired pose of body_frame_id relative to expressed_in_frame_id
      , as a list/tuple/1D np.array of [ posX, posY, posZ, rotX, rotY, rotZ ]
    - z_up (bool): whether or not xyzrpy follows the Z-up co-ordinate convention. Default: True

    Returns: TaskSpaceCommand msg
    """

    msg_ = TaskSpaceCommand(express_in_z_up=z_up)
    msg_.body_frame.frame_id = body_frame_id
    msg_.expressed_in_frame.frame_id = expressed_in_frame_id

    msg_.pose.position.x = xyzrpy[0]
    msg_.pose.position.y = xyzrpy[1]
    msg_.pose.position.z = xyzrpy[2]
    quat_ = Rotation.from_euler("xyz", xyzrpy[3:]).as_quat()  # Euler to quaternion
    msg_.pose.orientation.x = quat_[0]
    msg_.pose.orientation.y = quat_[1]
    msg_.pose.orientation.z = quat_[2]
    msg_.pose.orientation.w = quat_[3]

    return msg_

class WholeBodyCommandPublisher(Node):
    """A helper/example class to publish whole body controller messages.
    """

    def __init__(self, whole_body_command_msg=None):
        super().__init__(
            "task_circle"
        )  # initialize the underlying Node with the name hands_position_circle_rt

        # Publisher for WholeBodyControllerCommand, 10 is overloaded for being 10 deep history QoS
        self._publisher = self.create_publisher(
            WholeBodyControllerCommand, "/eve/whole_body_command", 10
        )

        # Keep time for position control
        self.t = 0.0
        self.dt = 0.002

        # Create timer that calls every self.dt
        self.timer = self.create_timer(self.dt, self.timer_callback)

    def timer_callback(self):

        whole_body_command_msg_ = WholeBodyControllerCommand();

        # Append two half circle tracing position control with both hands using some trigioiniometry
        # Don't get too close with hands together because otherwise eve hits herself
        whole_body_command_msg_.task_space_commands.append(generate_task_space_command_msg(
            ReferenceFrameName.RIGHT_HAND,
            ReferenceFrameName.PELVIS,
            [0.4, -np.cos(2*np.pi*self.t/5)/10-0.3, np.sin(2*np.pi*self.t/10)/5+0.2, 0.0, -np.deg2rad(90.0), 0.0]
            ))
        whole_body_command_msg_.task_space_commands.append(generate_task_space_command_msg(
            ReferenceFrameName.LEFT_HAND,
            ReferenceFrameName.PELVIS,
            [0.4, np.cos(2*np.pi*self.t/5)/10+0.3, np.sin(2*np.pi*self.t/10)/5+0.2, 0.0, -np.deg2rad(90.0), 0.0]
            ))

        self.t += self.dt

        self._publisher.publish(whole_body_command_msg_)

def main():

    rclpy.init()

    node = WholeBodyCommandPublisher()

    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass

    rclpy.shutdown()

if __name__ == "__main__":
    main()


""" Noise models. """
import numpy as np
import scipy.stats as stats
from modelmodel.misc import process_prng

def white(N, sigma=1, prng=None):
    """ Create white noise.

    Parameters
    ---------
    N : numeric
        Length of 1d noise array to return
    sigma : numeric
        Standard deviation
    prng : np.random.RandomState, None
        A RandomState instance, or None
    """

    prng = process_prng(prng)

    return prng.normal(loc=0, scale=sigma, size=N), prng

def ar1(N, alpha=0.2, sigma=1, prng=None):
    """ Create AR1 noise.

    Parameters
    ---------
    N : numeric
        Length of 1d noise array to return
    alpha : float
        Degree of autocorrelation
    sigma : numeric
        Standard deviation of white noise
    prng : np.random.RandomState, None
        A RandomState instance, or None

    Alpha of 0.2 was taken from the 'temporalnoise.R' function
    in the R neuRosim package (ver 02-10)
    """

    if (alpha > 1) or (alpha < 0):
        raise ValueError("alpha must be between 0-1.")

    prng = process_prng(prng)

    noise, prng = white(N=N, sigma=sigma, prng=prng)
    arnoise = [noise[0], ]

    [arnoise.append(
            noise[ii] + (alpha * noise[ii-1])
            ) for ii in range(1, len(noise))]

    return arnoise, prng

def physio(N, TR=1, freq_heart=1.17, freq_resp=0.2, sigma=1, prng=None):
    """ Create periodic physiological noise

    Parameters
    ---------
    N : numeric
        Length of 1d noise array to return
    TR : float
        The repetition rate (BOLD signal)
    freq_heart : float
        Frequency of heart rate (s)
    freq_resp : float
        Frequency of respiration (s)
    sigma : numeric
        Standard deviation of white noise
    prng : np.random.RandomState, None
        A RandomState instance, or None

    Note
    ----
    freq_heart and freq_resp defaults were taken from
    the 'temporalnoise.R' function in the R neuRosim
    package (ver 02-10)
    """

    # Calculate rates
    heart_beat = 2 * np.pi * freq_heart * TR
    resp_rate = 2 * np.pi * freq_resp * TR

    # Use rate to make periodic heart
    # and respiration (physio) drift
    # timeseries
    t = np.arange(N)
    hr_drift = np.sin(heart_beat * t) + np.cos(resp_rate * t)

    # Renormalize sigma using the
    # sigma of the physio signals
    hr_weight = sigma / np.std(hr_drift)

    # Create the white noise then
    # add the weighted physio
    noise, prng = white(N=N, prng=prng)
    noise += hr_weight * hr_drift

    return noise, prng

def _gen_drifts(nrow, ncol):
    idx = np.arange(0, nrow)

    drifts = np.zeros((nrow, ncol+1))
    drifts[:,0] = np.repeat(1 / np.sqrt(nrow), nrow)
    for col in range(2, ncol+1):
        drift = np.sqrt(2. / nrow) * 10. * np.cos(
                np.pi * (2. * idx + 1.) * (col - 1.) / (2. * nrow))
        drifts[:, col] = drift

    return drifts

def lowfreqdrift(N, TR=1, sigma=1, prng=None):
    """ Create noise with a low frequency drift (0.002-0.015 Hz)

    Parameters
    ---------
    N : numeric
        Length of 1d noise array to return
    TR : float
        The repetition rate (BOLD signal)
    prng : np.random.RandomState, None
        A RandomState instance, or None

    Note
    ----
    Smith et al (1999), Investigation of the Low Frequency Drift in fMRI
    Signal, NeuroImage 9, 526-533.

    This function was ported form a similar function ('lowfreqdrift.R')
    in the R 'neuRosim' package (ver 02-10):

    http://cran.r-project.org/web/packages/neuRosim/index.html
    """

    prng = process_prng(prng)

    freq = prng.randint(66, 500)
        ## i.e. 0.002-0.015 Hz

    nbasis = int(np.floor(2 * (N * TR) / freq + 1))
    noise = _gen_drifts(N, nbasis)
    noise = noise[:,1:]     ## Drop the first col
    noise = noise.sum(1)    ## Sum the rows, creating
                            ## creating the final noise

    # Now add white noise
    whiten, prng = white(N, sigma=sigma, prng=prng)
    noise += whiten

    return noise, prng

def onef(N, fraction, prng=None):
    """ Simulate the typical 1/f fMRI noise distribution.
    """

    raise NotImplementedError("TODO")


<filename>features/rms.py
import numpy as np
from scipy.signal.windows import hann

from sklearn.utils.validation import check_is_fitted
from sklearn.base import BaseEstimator, TransformerMixin

class RMSFeatures(BaseEstimator, TransformerMixin):
    def __init__(self, window_size=300, shift=15, percentile=0.1):
        self.window_size = window_size
        self.shift = shift
        self.percentile = percentile

    def _get_basal_tones(self, signal):
        basal_tones = []
        for i in range(0, len(signal) - self.window_size + 1, self.shift):
            window = signal[i:i+self.window_size]
            _min, _max = np.min(window), np.max(window)
            base_value = 0.25 * (_max - _min)
            # Take the mean of the 10% smallest values
            mean_smallest_values = np.mean(sorted(window)[:int(self.percentile * len(window))])

            basal_tones.append(mean_smallest_values + base_value)

        basal_tones = np.array(basal_tones)
        basal_tones = np.interp(list(range(len(signal))),
                                list(range(0, len(signal) - self.window_size + 1, self.shift)),
                                basal_tones)
        return basal_tones

    def _rms(self, signal):
        window = hann(self.window_size)
        rms_signal = []
        for i in range(0, len(signal) - self.window_size + 1, self.shift):
            subsignal = signal[i:i+self.window_size] * window
            rms_signal.append(np.sqrt(np.mean(subsignal ** 2)))
        rms_signal = np.array(rms_signal)
        rms_signal = np.interp(list(range(len(signal))),
                               list(range(0, len(signal) - self.window_size + 1, self.shift)),
                               rms_signal)
        return rms_signal

    def fit(self, X, y):
        self.names_ = [
            'RMS_mean',
            'RMS_std',
            'RMS_max',
            'RMS_min',
            'RMS_nr_zeros'
        ]
        return self

    def transform(self, X):
        check_is_fitted(self, ['names_'])
        features = np.zeros((X.shape[0], len(self.names_)))
        for i in range(X.shape[0]):
            signal = X[i, :]
            rms_signal = self._rms(signal)
            basal_signal = self._get_basal_tones(rms_signal)
            length = min(len(rms_signal), len(basal_signal))
            diff_signal = rms_signal[:length] - basal_signal[:length]
            diff_signal[diff_signal < 0] = 0
            features[i, :] =[np.mean(diff_signal), np.std(diff_signal),
                             np.max(diff_signal), np.min(diff_signal),
                             np.sum(diff_signal == 0)]
        return features

    def fit_transform(self, X, y):
        self.fit(X, y)
        return self.transform(X)


import abc
import warnings

import gym
import numpy as np
from scipy.spatial.ckdtree import cKDTree

from gym_guppy.guppies import Agent, Guppy, GlobalTargetRobot
from gym_guppy.tools import Feedback
from gym_guppy.tools.math import is_point_left, normalize, rotation

class AdaptiveAgent(GlobalTargetRobot):
    def action_completed(self) -> bool:
        return True

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self._feedback = Feedback()
        self._state: AdaptiveState = ApproachState()

    @property
    def action_space(self) -> gym.spaces.Box:
        return gym.spaces.Box(high=np.inf, low=-np.inf, shape=tuple())

    def set_action(self, action):
        robot_pose = self._env_state[self.id]
        _, [nn] = self._env_kd_tree.query(robot_pose[:2], k=[2])
        guppy_pose = self._env_state[nn]

        self._feedback.update(guppy_pose, robot_pose)

        self._state = self._state.switch_state()
        self._target = self._state.compute_next_action(self, self._feedback, self._env_state, self._env_kd_tree)

    def compute_next_action(self, state: np.ndarray, kd_tree: cKDTree = None):
        # robot_pose = state[self.id]
        # _, [nn] = kd_tree.query(robot_pose[:2], k=[2])
        # guppy_pose = state[nn]
        #
        # self._feedback.update(guppy_pose, robot_pose)
        #
        # self._state = self._state.switch_state()
        # self._target = self._state.compute_next_action(self, self._feedback, state, kd_tree)
        pass

class AdaptiveState(abc.ABC):
    _dt = 0.01

    @abc.abstractmethod
    def compute_next_action(self, agent: Agent, feedback: Feedback, state: np.ndarray, kd_tree: cKDTree = None) -> \
            np.ndarray:
        pass

    @abc.abstractmethod
    def switch_state(self) -> "AdaptiveState":
        pass

class MillingState(AdaptiveState):
    _mill_diameter = 0.2
    _mill_center = np.array([.0, .0])

    def __init__(self):
        # TODO compute mill points
        self._mill_points = []
        self._mill_index = 0

    def compute_next_action(self, agent: Agent, feedback: Feedback, state: np.ndarray, kd_tree: cKDTree = None):
        # TODO implement
        pass

    def switch_state(self) -> "AdaptiveState":
        # TODO implement
        pass

class ApproachState(AdaptiveState):
    _decision_bound = 0.5
    _learning_rate = 0.075
    _linear_speed_correction = 0.2
    _comfort_zone = 0.12

    def __init__(self):
        super().__init__()

        self._close_enough = False
        self._approach_parameter = 0.5

    def compute_next_action(self, agent: Agent, feedback: Feedback, state: np.ndarray, kd_tree: cKDTree = None):
        # get own position and nearest fish position
        robot_pos = state[agent.id][:2]
        _, [nn] = kd_tree.query(robot_pos, k=[2])
        guppy_pos = state[nn, :2]

        # get fear and compute integrate
        fear = feedback.fear
        integrate = (fear - self._decision_bound) * self._dt * self._learning_rate

        self._approach_parameter += integrate
        self._approach_parameter = min(max(self._approach_parameter, 0.0), 1.0)

        # infer fish motion
        guppy_dir = feedback.infer_guppy_motion_direction(1.0)

        # compute motion target
        guppy_robot_vec = robot_pos - guppy_pos

        if np.linalg.norm(guppy_robot_vec) < self._comfort_zone:
            self._close_enough = True
            return robot_pos

        target = guppy_pos + normalize(guppy_robot_vec) * self._comfort_zone / 2.
        rot_dir = 1 if is_point_left(guppy_pos, guppy_pos + guppy_dir, robot_pos) else -1
        r = rotation(self._approach_parameter * np.pi * .5 * rot_dir)
        return r.dot(target - robot_pos) + robot_pos

    def switch_state(self) -> "AdaptiveState":
        if self._close_enough:
            print('Switching to LeadState')
            return LeadState()
        return self

class LeadState(AdaptiveState):
    _target_radius = 0.05
    _max_lead_dist = 0.1

    _targets = np.array([[0.4, 0.4],
                         [0.4, -0.4],
                         [-0.4, -0.4],
                         [-0.4, 0.4]])

    def __init__(self):
        super().__init__()

        self._waiting_counter = 0
        self._target_idx = None

    def compute_next_action(self, agent: Agent, feedback: Feedback, state: np.ndarray, kd_tree: cKDTree = None):
        robot_pos = state[agent.id, :2]
        _, [nn] = kd_tree.query(robot_pos, k=[2])
        guppy_pos = state[nn, :2]

        # compute next target
        if self._target_idx is None:
            target_dists = np.linalg.norm(self._targets - robot_pos, axis=1)
            self._target_idx = np.argmin(target_dists)

        # check if robot is close enough to target
        if np.linalg.norm(self._targets[self._target_idx] - robot_pos) < self._target_radius:
            self._target_idx += 1
            self._target_idx %= len(self._targets)

        # check if guppy is close enough to robot
        if np.linalg.norm(guppy_pos - robot_pos) > self._max_lead_dist:
            print('Waiting for Guppy')
            self._waiting_counter += 1
            return robot_pos

        self._waiting_counter = 0
        return self._targets[self._target_idx]

    def switch_state(self):
        if self._waiting_counter > 10:
            print('Switching to ApproachState')
            return ApproachState()
        return self


<filename>fisspy/analysis/filter.py
from __future__ import absolute_import, division
import numpy as np
from scipy.fftpack import fft, fftfreq, ifft

__author__= "<NAME>"
__email__ = "<EMAIL>"

def FourierFilter(data, nt, dt, filterRange, axis=0):
    """
    Apply the Fourier bandpass filter.

    Parameters
    ----------
    data: `~numpy.ndarray`
        N-dimensional array.
    nt: `int`
        The number of the time domain.
    dt: `float`
        Bin size of the time domain.
    filterRange: `list`
        Bandpass filter range.
    axis: `int`
        time axis of the data.
    """
    if data.dtype == '>f8':
        data = data.astype(float)
    freq = fftfreq(nt, dt)
    if filterRange[0] == None:
        filterRange[0] = 0
    if filterRange[1] == None:
        filterRange[1] = freq.max()
    filt = np.logical_or(np.abs(freq) < filterRange[0],
                         np.abs(freq) > filterRange[1])
    fdata = fft(data, axis=axis)
    fdata[filt] = 0
    return ifft(fdata, axis=axis).real


<gh_stars>1-10
from collections import defaultdict
import numpy as np
import scipy.optimize

class NashQ:

    def __init__(self, env, config):
        self._env = env

        # Check that we are in a two-player game
        assert env.num_players() == 2, "Nash-Q is only implemented for 2-player games"

        # Get configuration
        self._iteration_episodes = config.get("iteration_episodes", 10)
        self._learning_rate = config.get("learning_rate", 1.0)
        self._initial_value = config.get("initial_value", env.max_payoff())
        self._solver = config.get("solver", "revised simplex")
        self._epsilon = config.get("epsilon", 0.0)

        # Initialize upper and lower value functions
        self._Q = dict()
        self._V = defaultdict(lambda: self._initial_value)

        # Initialize strategies
        self._strategies = dict()

    def _solve_row(self, G):
        N, M = G.shape

        # Objective - maximize game value 'v'
        c = np.zeros(1 + N, dtype=np.float64)
        c[0] = -1.0

        # Find a row-strategy that receives payoff at least 'v' for all column actions
        A_ub = np.concatenate((np.ones((M,1,), dtype=np.float64), -G.T,), axis=1)
        b_ub = np.zeros(M, dtype=np.float64)

        # Ensure that row strategy is a distribution
        A_eq = np.ones((1, 1 + N,), dtype=np.float64)
        A_eq[0, 0] = 0.0
        b_eq = np.ones(1, dtype=np.float64)

        bounds = [(0.0,None,)] * (1 + N)
        bounds[0] = (None, None)

        # Use SciPy to solve the game
        result = scipy.optimize.linprog(c, A_ub, b_ub, A_eq, b_eq, bounds, self._solver)

        # Normalize strategy
        strategy = np.clip(result.x[1:], 0.0, 1.0)
        strategy /= np.sum(strategy)

        if np.isnan(strategy).any():
            print(result)
            exit(1)

        return strategy

    def _solve_nash(self, G):
        row_strategy = self._solve_row(G)
        column_strategy = self._solve_row(-G.T)

        return row_strategy, column_strategy

    def _update_simultaneous(self, state, actions, rewards, next_state):

        # Get number of actions for each player
        row_actions = state.num_actions(0)
        column_actions = state.num_actions(1)

        # Compute learning rate - constant for now
        alpha = self._learning_rate

        # Initialize Q-function for the current state if necessary
        if state not in self._Q:
            self._Q[state] = np.full((row_actions, column_actions,), self._initial_value, dtype=np.float64)

        # Compute Q-target
        q_target = rewards[0]

        if next_state is not None:
            q_target += self._V[next_state]

        # Update Q-function
        self._Q[state][actions[0], actions[1]] = (1.0 - alpha) * self._Q[state][actions[0], actions[1]] + alpha * q_target

        # Recompute strategies
        row_strategy, column_strategy = self._solve_nash(self._Q[state])
        self._strategies[state] = (row_strategy, column_strategy)

        # Recompute value function
        self._V[state] = row_strategy.dot(self._Q[state]).dot(column_strategy)

    def _update_turn_based(self, state, actions, rewards, next_state):

        # Get current player ID
        player_id = state.active_players()[0]

        # Get number of actions for current player
        num_actions = state.num_actions(player_id)

        # Compute learning rate - constant for now
        alpha = self._learning_rate

        # Initialize Q-bounds the current state if necessary
        if state not in self._Q:
            self._Q[state] = np.full(num_actions, self._initial_value, dtype=np.float64)

        # Compute Q-target
        q_target = rewards[0]

        if next_state is not None:
            q_target += self._V[next_state]

        # Update Q-function
        self._Q[state][actions[0]] = (1.0 - alpha) * self._Q[state][actions[0]] + alpha * q_target

        # Recompute strategy
        q_function = self._Q[state]

        if 0 == player_id:
            q_target = np.max(q_function)
        else:
            q_target = np.min(q_function)

        strategy = np.zeros(num_actions, dtype=np.float64)

        for action in range(num_actions):
            if q_function[action] == q_target:
                strategy[action] = 1.0

        strategy = strategy / np.sum(strategy)
        self._strategies[state] = strategy

        # Recompute value function
        self._V[state] = np.sum(q_function * strategy)

    def _actions(self, state):
        if len(state.active_players()) == 1:
            num_actions = state.num_actions(state.active_players()[0])

            if state not in self._strategies or np.random.random() < self._epsilon:
                strategy = np.ones(num_actions, dtype=np.float64) / num_actions
            else:
                strategy = self._strategies[state]

            return [np.random.choice(num_actions, p=strategy)]
        else:
            row_actions = state.num_actions(0)
            column_actions = state.num_actions(1)

            if state not in self._strategies or np.random.random() < self._epsilon:
                row_strategy = np.ones(row_actions, dtype=np.float64) / row_actions
                column_strategy = np.ones(column_actions, dtype=np.float64) / column_actions
            else:
                row_strategy, column_strategy = self._strategies[state]

            row_action = np.random.choice(row_actions, p=row_strategy)
            column_action = np.random.choice(column_actions, p=column_strategy)

            return [row_action, column_action]

    def train(self):

        # Step counter
        total_steps = 0

        for _ in range(self._iteration_episodes):

            # Reset environment
            current_state = self._env.reset()

            # Initialize history
            state_history = []
            action_history = []
            reward_history = []

            while current_state is not None:

                # Append current state to state history
                state_history.append(current_state)

                # Get actions for all active players
                current_action = self._actions(current_state)
                action_history.append(current_action)

                # Take joint action in environment
                current_state, rewards = self._env.step(current_action)

                # Append payoffs to payoff history
                reward_history.append(rewards)

            # Update step count
            total_steps += len(state_history)

            # Do updates for each player - work forward through history
            for step in range(len(state_history)):
                state = state_history[step]
                actions = action_history[step]
                rewards = reward_history[step]

                if step + 1 < len(state_history):
                    next_state = state_history[step + 1]
                else:
                    next_state = None

                if len(state.active_players()) == 1:
                    self._update_turn_based(state, actions, rewards, next_state)
                else:
                    self._update_simultaneous(state, actions, rewards, next_state)

        # Return number of steps and episodes sampled, and episode statistics
        return total_steps, self._iteration_episodes, self._env.pull_stats()

    def strategy(self, state, player_id):
        if state not in self._strategies:
            num_actions = state.num_actions(player_id)
            return np.ones(num_actions, dtype=np.float64) / num_actions
        elif len(state.active_players()) == 1:
            return self._strategies[state]
        else:
            return self._strategies[state][player_id]


import unittest
import numpy as np
from pyapprox.low_rank_multifidelity import *
from functools import partial
from scipy.stats import uniform
import pyapprox as pya

from scipy.special import jv as bessel_function
class OscillatoryPolyLowFidelityModel(object):
    def __init__( self, mesh_dof=100, num_terms=35 ):
        self.mesh = np.linspace( -1.,1., mesh_dof )
        self.num_terms = num_terms

        variable = [uniform(-1,2)]
        var_trans = pya.AffineRandomVariableTransformation(variable)
        self.poly = pya.PolynomialChaosExpansion()
        poly_opts = pya.define_poly_options_from_variable_transformation(
            var_trans)
        self.poly.configure(poly_opts)
        self.poly.set_indices(pya.compute_hyperbolic_indices(
            1,self.num_terms-1))

    def basis_matrix(self):
        # compute vandermonde matrix, i.e. all legendre polynomials up
        # at most degree self.num_terms
        basis_matrix = self.poly.basis_matrix(
            self.mesh.reshape(1,self.mesh.shape[0]))
        return basis_matrix

    def compute_abs_z(self,z):
        abs_z = np.absolute(z)
        return abs_z

    def __call__(self,samples):
        z = samples[0,:]
        # z in [0,10*pi]

        basis_matrix = self.basis_matrix()

        coeffs = np.zeros((self.num_terms,samples.shape[1]) ,float )
        abs_z = self.compute_abs_z(z)
        for k in range( self.num_terms ):
            ck = np.exp( np.sign( z )*1j )*1j**k
            ck = ck.real
            gk = ck * np.sqrt( np.pi*(2.*k+1.)/ abs_z )*\
                bessel_function( k+.5, abs_z )
            # gk not defined for z=0
            coeffs[k,:] = gk
            # must divide by sqrt(2), due to using orthonormal basis with
            # respect to w=1/2, but needing orthonormal basis with respect
            # to w=1
            coeffs[k,:] /= np.sqrt(2)

        result = np.dot(basis_matrix, coeffs).T
        return result

    def generate_samples(self,num_samples):
        num_vars = 1
        return np.random.uniform(0,10.*np.pi,(num_vars,num_samples))

class OscillatoryHighFidelityModel(OscillatoryPolyLowFidelityModel):
    def __init__(self,mesh_dof=100,num_terms=35,eps=1e-3):
        super().__init__(mesh_dof,num_terms)
        self.eps = eps

    def compute_abs_z(self,z):
        abs_z = np.absolute(z+self.eps*z**2)
        return abs_z

class OscillatorySinLowFidelityModel(OscillatoryPolyLowFidelityModel):
    def __init__(self,mesh_dof=100,num_terms=35,eps=1e-3):
        super().__init__(mesh_dof,num_terms)
        self.eps = eps

    def basis_matrix(self):
        kk = np.arange(self.num_terms)[np.newaxis,:]
        basis_matrix = np.sin(np.pi*(kk+1)*self.mesh[:,np.newaxis])
        return basis_matrix

class TestLowRankMultiFidelity(unittest.TestCase):
    def setUp(self):
        np.random.seed(1)

    def test_select_nodes(self):
        A = numpy.array([[1.,1.,1 ],[1.,2.,5.5],[1.,3.,13.]])
        A = np.random.normal(0,1,(3,3))
        G = numpy.dot( A.T, A )
        pivots, L = select_nodes( A.copy(), A.shape[1] )
        numpy_L = numpy.linalg.cholesky( G )
        P = numpy.eye(pivots.shape[0])[pivots,:]
        assert numpy.allclose( numpy.dot(P,numpy.dot(G,P.T)),
                                   numpy.dot(L,L.T))
        assert numpy.allclose(numpy.dot(P.T,numpy.dot(numpy.dot(L,L.T),P)),G)

        A = numpy.random.normal( 0.,1., (4, 3) )
        G = numpy.dot( A.T, A )
        pivots, L = select_nodes( A.copy(), A.shape[1] )
        P = numpy.eye(pivots.shape[0])[pivots,:]
        numpy_L = numpy.linalg.cholesky( G )
        assert numpy.allclose( numpy.dot(P,numpy.dot(G,P.T)),
                                   numpy.dot(L,L.T))
        assert numpy.allclose(numpy.dot(P.T,numpy.dot(numpy.dot(L,L.T),P)),G)

    def test_select_nodes_cholesky(self):
        A = numpy.array([[1.,1.,1 ],[1.,2.,5.5],[1.,3.,13.]])
        A = np.random.normal(0,1,(3,3))
        G = numpy.dot( A.T, A )
        pivots, L = select_nodes_cholesky( A, A.shape[1] )
        numpy_L = numpy.linalg.cholesky( G )
        P = pya.get_pivot_matrix_from_vector(pivots,G.shape[0])
        assert np.allclose(P.dot(G).dot(P.T),L.dot(L.T))

        A = numpy.random.normal( 0.,1., (4, 3) )
        G = numpy.dot( A.T, A )
        pivots, L = select_nodes_cholesky( A, A.shape[1] )
        numpy_L = numpy.linalg.cholesky( G )
        P = pya.get_pivot_matrix_from_vector(pivots,G.shape[0])
        assert np.allclose(P.dot(G).dot(P.T),L.dot(L.T))

    def test_select_nodes_update(self):
        A = numpy.random.normal( 0.,1., (5, 4) )
        G = numpy.dot( A.T, A )
        pivots, L = select_nodes( A.copy(), A.shape[1], order=[1,3,0] )
        assert numpy.allclose(pivots,[1,3,0,2])
        P = numpy.eye(pivots.shape[0])[pivots,:]
        numpy_L = numpy.linalg.cholesky( G )
        assert numpy.allclose( numpy.dot(P,numpy.dot(G,P.T)),
                                   numpy.dot(L,L.T))
        assert numpy.allclose(numpy.dot(P.T,numpy.dot(numpy.dot(L,L.T),P)),G)

    def test_oscillatory_model(self):
        eps = 1.e-3
        mesh_dof=100
        K=35
        lf_model1 = OscillatoryPolyLowFidelityModel(mesh_dof,K)
        lf_model2 = OscillatorySinLowFidelityModel(mesh_dof,K)
        hf_model  = OscillatoryHighFidelityModel(mesh_dof,100,eps)
        lf_model  = lf_model2

        # for tutorial
        # samples = np.array([[5]])
        # import matplotlib.pyplot as plt
        # fig,axs=plt.subplots(1,2,figsize=(2*8,6))
        # hf_model.eps=1e-2
        # axs[0].plot(hf_model.mesh,hf_model(samples)[0,:],label='$u_0$')
        # hf_model.eps=1e-3
        # axs[0].plot(hf_model.mesh,lf_model1(samples)[0,:],label='$u_1$')
        # axs[0].plot(hf_model.mesh,lf_model2(samples)[0,:],label='$u_2$')
        # axs[0].legend()

        # samples = np.linspace(0.01,np.pi*10-0.1,101)[np.newaxis,:]
        # hf_model.eps=1e-2
        # axs[1].plot(samples[0,:],hf_model(samples)[:,50],label='$u_0$')
        # hf_model.eps=1e-3
        # axs[1].plot(samples[0,:],lf_model1(samples)[:,50],label='$u_1$')
        # axs[1].plot(samples[0,:],lf_model2(samples)[:,50],label='$u_2$')

        # plt.show()
        # assert False

        # number of quantities of interest/outputs
        num_QOI = mesh_dof
        # number of random paramters/inputs
        num_dims = 1
        # number of initial candidates/snapshots for low-fidelity model
        num_lf_candidates = int(1e4)
        # number of interpolations nodes/high-fidelity runs
        num_hf_runs = 20

        num_test_samples = int(1e3)
        test_samples = hf_model.generate_samples(num_test_samples)
        hf_test_values = hf_model( test_samples )
        lf_test_values = lf_model( test_samples )

        mf_model = BiFidelityModel(lf_model,hf_model)
        mf_model.build(num_hf_runs,hf_model.generate_samples,
                       num_lf_candidates)

        # regression test. To difficult to compute a unit test
        mf_test_values = mf_model( test_samples )

        error_mf = compute_mean_l2_error(hf_test_values,
                                         mf_test_values)[1]
        assert error_mf<1e-4#3.0401959914364483e-05)

        return
        # for tutorial
        hf_runs = [i*2 for i in range(1,11)]
        error_mf = numpy.empty((len(hf_runs)))
        error_lf = numpy.empty((len(hf_runs)))
        error_nodes = numpy.empty((len(hf_runs)))
        condition = numpy.empty((len(hf_runs)))

        for j in range(len(hf_runs)):
            num_hf_runs = hf_runs[j]

            mf_model = BiFidelityModel(lf_model,hf_model)
            mf_model.build(num_hf_runs,hf_model.generate_samples,
                           num_lf_candidates)

            mf_test_values = mf_model( test_samples )

            error_mf[j] = compute_mean_l2_error(hf_test_values,
                                                mf_test_values)[1]
            error_lf[j] = compute_mean_l2_error(hf_test_values,
                                                lf_test_values)[1]
            print ("|hf-lf|", error_lf[j])
            print ("|hf-mf|", error_mf[j])

        # plt.semilogy(hf_runs,error_mf,label=f'$K={K}$')
        # plt.show()

if __name__== "__main__":
    low_rank_mf_test_suite = unittest.TestLoader().loadTestsFromTestCase(
         TestLowRankMultiFidelity)
    unittest.TextTestRunner(verbosity=2).run(low_rank_mf_test_suite)


import logging
import os
import random
import sys

import hydra
import numpy as np
import torch
from omegaconf import OmegaConf
from scipy.spatial.distance import cdist
from torch.backends import cudnn
from tqdm import tqdm

sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))
os.chdir(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))

from configs.configs import Config
from dataloader import get_RMFD_target_dataloader, get_target_dataloader
from utils.utils import Scheduler, AverageMeter, Entropy, cal_acc_target_oda
from networks import network

device = 'cuda' if torch.cuda.is_available() else 'cpu'

def change_model_require_grad(model: torch.nn.Module, true_or_false: bool):
    for k, v in model.named_parameters():
        v.requires_grad = true_or_false

def obtain_label(loader, netF, netB, netC, cfg):
    start_test = True
    with torch.no_grad():
        iter_test = iter(loader)
        for _ in range(len(loader)):
            data = iter_test.next()
            inputs = data[0]
            labels = data[1]
            inputs = inputs.cuda()
            feas = netB(netF(inputs))
            outputs = netC(feas)
            if start_test:
                all_fea = feas.float().cpu()
                all_output = outputs.float().cpu()
                all_label = labels.float()
                start_test = False
            else:
                all_fea = torch.cat((all_fea, feas.float().cpu()), 0)
                all_output = torch.cat((all_output, outputs.float().cpu()), 0)
                all_label = torch.cat((all_label, labels.float()), 0)

    all_output = torch.nn.Softmax(dim=1)(all_output)
    _, predict = torch.max(all_output, 1)
    before_acc = torch.sum(torch.squeeze(predict).float() == all_label).item() / float(all_label.size()[0])
    if cfg.model.distance == 'cosine':
        all_fea = torch.cat((all_fea, torch.ones(all_fea.size(0), 1)), 1)
        all_fea = (all_fea.t() / torch.norm(all_fea, p=2, dim=1)).t()

    ent = torch.sum(-all_output * torch.log(all_output + cfg.model.epsilon), dim=1) / np.log(cfg.dataset.class_num)
    ent = ent.float().cpu()

    from sklearn.cluster import KMeans
    kmeans = KMeans(2, random_state=0).fit(ent.reshape(-1, 1))
    labels = kmeans.predict(ent.reshape(-1, 1))

    idx = np.where(labels == 1)[0]
    iidx = 0
    if ent[idx].mean() > ent.mean():
        iidx = 1
    known_idx = np.where(kmeans.labels_ != iidx)[0]

    all_fea = all_fea[known_idx, :]
    all_output = all_output[known_idx, :]
    predict = predict[known_idx]
    all_label_idx = all_label[known_idx]
    ENT_THRESHOLD = (kmeans.cluster_centers_).mean()

    all_fea = all_fea.float().cpu().numpy()
    K = all_output.size(1)
    aff = all_output.float().cpu().numpy()
    initc = aff.transpose().dot(all_fea)
    initc = initc / (1e-8 + aff.sum(axis=0)[:, None])
    cls_count = np.eye(K)[predict].sum(axis=0)
    labelset = np.where(cls_count > cfg.train.threshold)
    labelset = labelset[0]

    dd = cdist(all_fea, initc[labelset], cfg.model.distance)
    pred_label = dd.argmin(axis=1)
    pred_label = labelset[pred_label]

    for round in range(1):
        aff = np.eye(K)[pred_label]
        initc = aff.transpose().dot(all_fea)
        initc = initc / (1e-8 + aff.sum(axis=0)[:, None])
        dd = cdist(all_fea, initc[labelset], cfg.model.distance)
        pred_label = dd.argmin(axis=1)
        pred_label = labelset[pred_label]

    guess_label = cfg.dataset.class_num * np.ones(len(all_label), )
    guess_label[known_idx] = pred_label

    after_acc = np.sum(guess_label == all_label.float().numpy()) / len(all_label_idx)
    log_str = f'PseudoLabeling: Threshold = {ENT_THRESHOLD:.2f}, Accuracy = {before_acc * 100:.2f}% -> {after_acc * 100:.2f}%'

    logging.info(log_str)

    return guess_label.astype('int'), ENT_THRESHOLD

def get_mem_label(cfg, netF, netB, netC, test_loader):
    netF.eval()
    netB.eval()
    mem_label, ENT_THRESHOLD = obtain_label(test_loader, netF, netB, netC, cfg)
    mem_label = torch.from_numpy(mem_label).cuda()

    return mem_label, ENT_THRESHOLD

def op_copy(optimizer):
    for param_group in optimizer.param_groups:
        param_group['lr0'] = param_group['lr']
    return optimizer

def init_seed(seed):
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    np.random.seed(seed)
    random.seed(seed)
    cudnn.benchmark = True

def init_dataset_name(cfg):
    specific_name_dict = {
        "office-home": ['Art', 'Clipart', 'Product', 'RealWorld'],
        "RMFD": ['AFDB_face_dataset', 'AFDB_masked_face_dataest']
    }

    cfg.dataset.name_src = specific_name_dict[cfg.dataset.name][cfg.dataset.s]
    cfg.dataset.name_tar = specific_name_dict[cfg.dataset.name][cfg.dataset.t]

def train(epoch, train_loader, netF, netB, netC, criterion, optimizer, scheduler, mem_label, cfg):
    losses = AverageMeter()
    epoch_sum = epoch * len(train_loader)
    netF.train()
    netB.train()
    for i, data in enumerate(tqdm(train_loader, total=len(train_loader), leave=False, dynamic_ncols=True)):
        optimizer.zero_grad()
        scheduler(optimizer, epoch_sum + i + 1)
        x, tar_idx = data[0].to(device), data[2].to(device)

        pred = mem_label[tar_idx]
        features_test = netB(netF(x))
        outputs_test = netC(features_test)

        softmax_out = torch.nn.Softmax(dim=1)(outputs_test)
        outputs_test_known = outputs_test[pred < cfg.dataset.class_num, :]
        pred = pred[pred < cfg.dataset.class_num]

        if len(pred) == 0:
            del features_test
            del outputs_test
            continue

        if cfg.train.cls_par > 0:
            loss = criterion(outputs_test_known, pred)
            loss *= cfg.train.cls_par
        else:
            loss = torch.tensor(0.0).to(device)

        if cfg.train.ent:
            softmax_out_known = torch.nn.Softmax(dim=1)(outputs_test_known)
            entropy_loss = torch.mean(Entropy(softmax_out_known))
            if cfg.train.gent:
                msoftmax = softmax_out.mean(dim=0)
                gentropy_loss = torch.sum(-msoftmax * torch.log(msoftmax + cfg.model.epsilon))
                entropy_loss -= gentropy_loss
            loss += entropy_loss * cfg.train.ent_par

        losses.update(loss, x.size(0))

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

    log_str = f'Train: Loss = {losses.avg:.3f}'
    return log_str

def validate(valid_loader, netF, netB, netC, cfg):
    netF.eval()
    netB.eval()
    acc_os1, acc_os2, acc_unknown = cal_acc_target_oda(valid_loader, netF, netB, netC, cfg, True)
    log_str = f'Valid_Accuracy OS2 = {acc_os2:.2f}%, OS1 = {acc_os1:.2f}%, Unknown = {acc_unknown:.2f}%'

    return acc_os1, acc_os2, acc_unknown, log_str

@hydra.main(config_path='configs', config_name='config')
def main(cfg: Config) -> None:
    init_seed(cfg.train.seed)
    init_dataset_name(cfg)

    logging.info(OmegaConf.to_yaml(cfg))
    if cfg.da.type != 'oda':
        raise ValueError(f"This python file doesn't match {cfg.da.type}")

    if cfg.dataset.name == "RMFD":
        train_loader, test_loader = get_RMFD_target_dataloader(cfg)
    else:
        train_loader, test_loader = get_target_dataloader(cfg)

    netF = network.ResBase('resnet50').to(device)
    netB = network.feat_bootleneck(netF.in_features, cfg.model.bottleneck_dim, cfg.model.classifier).to(device)
    netC = network.feat_classifier(cfg.dataset.num_class, cfg.model.bottleneck_dim, cfg.model.layer).to(device)

    netF.load_state_dict(torch.load(os.path.join(cfg.train.saved_model_path, 'source_F.pt')))
    netB.load_state_dict(torch.load(os.path.join(cfg.train.saved_model_path, 'source_B.pt')))
    netC.load_state_dict(torch.load(os.path.join(cfg.train.saved_model_path, 'source_C.pt')))

    netC.eval()
    change_model_require_grad(netC, False)

    params = list()

    if cfg.train.lr_decay1 > 0:
        params.append({"params": netF.parameters(), "lr": cfg.train.lr * cfg.train.lr_decay1})
    else:
        change_model_require_grad(netF, False)

    if cfg.train.lr_decay2 > 0:
        params.append({"params": netB.parameters(), "lr": cfg.train.lr * cfg.train.lr_decay2})
    else:
        change_model_require_grad(netB, False)

    optimizer = torch.optim.SGD(params)
    optimizer = op_copy(optimizer)

    criterion = torch.nn.CrossEntropyLoss()
    scheduler = Scheduler(cfg.train.max_epoch * len(train_loader))

    best_acc = 0
    best_netF = None
    best_netB = None
    best_netC = None
    mem_label = None
    interval = cfg.train.max_epoch // 15
    for epoch in range(cfg.train.max_epoch):

        if epoch % interval == 0 and cfg.train.cls_par > 0:
            mem_label, _ = get_mem_label(cfg, netF, netB, netC, test_loader)

        train_log = train(epoch, train_loader, netF, netB, netC, criterion, optimizer, scheduler, mem_label, cfg)

        if epoch % interval == 0 or epoch == cfg.train.max_epoch:
            acc_os1, acc_os2, acc_unknown, val_log = validate(test_loader, netF, netB, netC, cfg)

            if acc_os2 >= best_acc:
                best_acc = acc_os2
                best_netF = netF.state_dict()
                best_netB = netB.state_dict()
                best_netC = netC.state_dict()

            logging.info(f"[{epoch + 1}/{cfg.train.max_epoch}] {train_log} {val_log}")
        else:
            logging.info(f"[{epoch + 1}/{cfg.train.max_epoch}] {train_log}")

    torch.save(best_netF, "target_F.pt")
    torch.save(best_netB, "target_B.pt")
    torch.save(best_netC, "target_C.pt")

    logging.info(f"{cfg.dataset.name_src}=>{cfg.dataset.name_tar} Best Accuracy: {best_acc}")

if __name__ == '__main__':
    main()


import os
import argparse
import numpy as np
import csv
from scipy import stats

import hydra
from omegaconf import DictConfig
from hydra import slurm_utils

@hydra.main(config_path='/h/nng/conf/robust/config.yaml', strict=False)
def display_bias(cfg: DictConfig):

    if cfg.extra:
        cfg.display.dir.name.append(cfg.extra)

    if cfg.gen.seed is not None:
        cfg.display.dir.name[3] = '_'.join(cfg.display.dir.name[3].split('_')[:-1])

    base_path = os.path.join('/h/nng/data', cfg.data.task, cfg.compare.name, cfg.data.tdset)
    csv_file = os.path.join(base_path, 'orig', cfg.eval.split + '.csv')

    # properties for each line
    bias_prop = []

    # possible values for each property
    prop_list = [[] for _ in range(len(cfg.display.props))]

    with open(csv_file, 'r') as csv_f:
        reader = csv.reader(csv_f)
        header = next(reader)
        for row in reader:
            res = []
            if cfg.display.prop_split == 'Race' and  row[header.index('Race')] == '':
                continue
            for i in range(len(cfg.display.props)):
                prop = cfg.display.props[i]
                if prop == "Person":
                    prop_val = row[header.index(prop)] if row[header.index("Race")] == "" else ""
                else:
                    prop_val = row[header.index(cfg.display.props[i])]
                res.append(prop_val)
                if prop_val not in prop_list[i]:
                    prop_list[i].append(prop_val)
            bias_prop.append(res)

    compare_idx = cfg.display.props.index(cfg.display.prop_split)

    if len(prop_list[compare_idx]) != 2:
        raise Exception("Can only compare 2 values")

    cfg.display.dir.name[2] = cfg.data.fdset
    cfg.display.dir.name[5] = cfg.data.tdset

    cfg.display.dir.name[4] = cfg.gen.seed
    t_tests = []
    for seed in empty_to_list(cfg.display.seed):
        cfg.display.dir.name[6] = seed

        display_dir = os.path.join('/h/nng/slurm', cfg.display.dir.date, slurm_utils.resolve_name(cfg.display.dir.name), 'log')
        fnames = sorted(os.listdir(display_dir))[::-1]
        for fname in fnames:
            if 'err' in fname:
                continue
            res = open(os.path.join(display_dir, fname), 'r').readlines()
            if res == [] or 'Accuracy' not in res[-1]:
                continue
            probs = []
            for line in res:
                line = line.strip()
                if line[0] == '[' and line[-1] == ']':
                    probs.append([float(val) for val in line[1:-1].split(',')])
            break

        x_dim_size = tuple(len(prop_l) for prop_l in prop_list)
        sums = np.zeros(x_dim_size)
        nums = np.zeros(x_dim_size)

        for i in range(len(bias_prop)):
            props = bias_prop[i]
            prop_idxs = [[prop_list[j].index(props[j])] for j in range(len(props))]
            sums[np.ix_(*prop_idxs)] += probs[i][0]
            nums[np.ix_(*prop_idxs)] += 1

        avgs = np.divide(sums, nums)

        avg_0 = avgs.take(0, axis=compare_idx).flatten()
        avg_1 = avgs.take(1, axis=compare_idx).flatten()

        avg_0 = avg_0[~np.isnan(avg_0)]
        avg_1 = avg_1[~np.isnan(avg_1)]

        t_tests.append(stats.ttest_ind(avg_0, avg_1))

    print(t_tests)

def empty_to_list(l):
    if l is None:
        return [None]
    else:
        return list(l)

if __name__ == "__main__":
    display_bias()


<filename>util.py<gh_stars>10-100
"""Utility functions."""
import torch
from torch_geometric.utils import degree, softmax, subgraph
from torch_sparse import SparseTensor
from torch_geometric.utils import remove_self_loops, add_self_loops
import sys, os
import os.path as osp
sys.path.append(os.path.join(os.path.dirname("__file__"), '..'))
sys.path.append(os.path.join(os.path.dirname("__file__"), '..', '..'))
from GIB.pytorch_net.util import to_np_array
from GIB.DeepRobust.deeprobust.graph.defense import GCN
import scipy.sparse as sp
import numpy as np
import pdb
import pickle

def get_root_dir():
    dirname = os.getcwd()
    dirname_split = dirname.split("/")
    index = dirname_split.index("GIB")
    dirname = "/".join(dirname_split[:index + 1])
    return dirname

GIB_PATH = get_root_dir() + "/results"

COLOR_LIST = ["b", "r", "g", "y", "c", "m", "skyblue", "indigo", "goldenrod", "salmon", "pink",
                  "silver", "darkgreen", "lightcoral", "navy", "orchid", "steelblue", "saddlebrown",
                  "orange", "olive", "tan", "firebrick", "maroon", "darkslategray", "crimson", "dodgerblue", "aquamarine"]
COLOR_LIST = COLOR_LIST * 2

LINESTYLE_LIST = ["-", "--", "-.", ":", (0, (5, 10))]

def get_reparam_num_neurons(out_channels, reparam_mode):
    if reparam_mode is None or reparam_mode == "None":
        return out_channels
    elif reparam_mode == "diag":
        return out_channels * 2
    elif reparam_mode == "full":
        return int((out_channels + 3) * out_channels / 2)
    else:
        raise "reparam_mode {} is not valid!".format(reparam_mode)

def sample_lognormal(mean, sigma=None, sigma0=1.):
    """
    Samples from a log-normal distribution using the reparametrization
    trick so that we can backprogpagate the gradients through the sampling.
    By setting sigma0=0 we make the operation deterministic (useful at testing time)
    """
    e = torch.randn(mean.shape).to(sigma.device)
    return torch.exp(mean + sigma * sigma0 * e)

def scatter_sample(src, index, temperature, num_nodes=None):
    gumbel = torch.distributions.Gumbel(torch.tensor([0.]).to(src.device),
            torch.tensor([1.0]).to(src.device)).sample(src.size()).squeeze(-1)
    log_prob = torch.log(src+1e-16)
    logit = (log_prob + gumbel) / temperature
    return softmax(logit, index, num_nodes)

def uniform_prior(index):
    deg = degree(index)
    deg = deg[index]
    return 1./deg.unsqueeze(1)

def add_distant_neighbors(data, hops):
    """Add multi_edge_index attribute to data which includes the edges of 2,3,... hops neighbors."""
    assert hops > 1
    edge_index, _ = remove_self_loops(data.edge_index)
    edge_index, _ = add_self_loops(edge_index,
                                   num_nodes=data.x.size(0))
    one_hop_set = set([tuple(x) for x in edge_index.transpose(0, 1).tolist()])
    row, col = edge_index
    adj = SparseTensor(row=row, col=col)
    multi_adj = adj
    for _ in range(hops - 1):
        multi_adj = multi_adj @ adj
    row, col, _ = multi_adj.coo()
    multi_edge_index = torch.stack([row, col], dim=0)
    multi_hop_set = set([tuple(x) for x in multi_edge_index.transpose(0, 1).tolist()])
    multi_hop_set = multi_hop_set - one_hop_set
    multi_edge_index = torch.LongTensor(list(multi_hop_set)).transpose(0, 1)
    data.multi_edge_index = multi_edge_index
    return

def compose_log(metrics, key, spaces=0, tabs=0, newline=False):
    string = "\n" if newline else ""
    return string + "\t" * tabs + " " * spaces + "{}: ({:.4f}, {:.4f}, {:.4f})".format(key, metrics["train_{}".format(key)], metrics["val_{}".format(key)], metrics["test_{}".format(key)])

def edge_index_2_csr(edge_index, size):
    """Edge index (PyG COO format) transformed to csr format."""
    csr_matrix = sp.csr_matrix(
        (np.ones(edge_index.shape[1]), to_np_array(edge_index)),
        shape=(size, size))
    return csr_matrix

def process_data_for_nettack(data):
    data.features = sp.csr_matrix(to_np_array(data.x))
    data.adj = edge_index_2_csr(data.edge_index, size=data.x.shape[0])
    data.labels = to_np_array(data.y)
    data.idx_train = np.where(to_np_array(data.train_mask))[0]
    data.idx_val = np.where(to_np_array(data.val_mask))[0]
    data.idx_test = np.where(to_np_array(data.test_mask))[0]
    return data

def to_tuple_list(edge_index):
    """Transform a coo-format edge_index to a list of edge tuples."""
    return [tuple(item) for item in edge_index.T.cpu().numpy()]

def classification_margin(output, true_label):
    '''probs_true_label - probs_best_second_class'''
    probs = torch.exp(output)
    probs_true_label = probs[true_label].clone()
    probs[true_label] = 0
    probs_best_second_class = probs[probs.argmax()]
    return (probs_true_label - probs_best_second_class).item()

def select_nodes(data, info, data_type, num=10, seed=None):
    '''
    selecting nodes as reported in nettack paper:
    (i) the 10 nodes with highest margin of classification, i.e. they are clearly correctly classified,
    (ii) the 10 nodes with lowest margin (but still correctly classified) and
    (iii) 20 more nodes randomly
    '''
    attack_path = osp.join(get_root_dir(), 'experiments/attack_data', data_type)
    if not os.path.exists(attack_path):
        os.makedirs(attack_path)
    filename = os.path.join(attack_path, "test-node_n:{}_seed_{}.pkl".format(num, seed))
    try:
        with open(filename, 'rb') as f:
            node_ids = pickle.load(f)
            print("Load previous attacked node_ids saved in {}.".format(filename))
    except:
        raise
        device = data.x.device
        gcn = GCN(nfeat=info["num_features"],
                  nclass=info["num_classes"],
                  nhid=16,
                  dropout=0.5, device=device).to(device)
        gcn.fit(data.features, data.adj, data.labels, data.idx_train)
        gcn.eval()
        output = gcn.predict()

        margin_dict = {}
        for idx in data.idx_test:
            margin = classification_margin(output[idx], data.labels[idx])
            if margin < 0: # only keep the nodes correctly classified
                continue
            margin_dict[idx] = margin
        sorted_margins = sorted(margin_dict.items(), key=lambda x:x[1], reverse=True)
        high = [x for x, y in sorted_margins[: num]]
        low = [x for x, y in sorted_margins[-num: ]]
        other = [x for x, y in sorted_margins[num: -num]]
        other = np.random.choice(other, num * 2, replace=False).tolist()
        node_ids = other + low + high
        pickle.dump(node_ids, open(filename, "wb"))
        print("Save attacked node_ids to {}:test-node_n:{}.pkl.".format(attack_path, num))
    return node_ids

def to_inductive(data):
    mask = data.train_mask | data.val_mask
    data.x = data.x[mask]
    data.y = data.y[mask]
    data.train_mask = data.train_mask[mask]
    data.val_mask = data.val_mask[mask]
    data.test_mask = None
    data.edge_index, _ = subgraph(mask, data.edge_index, None,
                                  relabel_nodes=True, num_nodes=data.num_nodes)
    data.num_nodes = mask.sum().item()
    return data

def parse_filename(filename, is_adversarial=False, **kwargs):
    """Parse the filename of the experment result file into a dictionary of settings.

    Args:
        filename: a string of filename
        is_adversarial: whether the file is from experiments/GIB_node_adversarial_attack.
    """
    if is_adversarial:
        return parse_filename_adversarial(filename, **kwargs)
    else:
        return parse_filename_standard(filename)

def parse_filename_standard(filename):
    """Parse the filename of the standard experment result file into a dictionary of settings."""
    parse_dict = {}
    filename_split = filename.split("_")
    parse_dict["data_type"] = filename_split[0]
    parse_dict["model_type"] = filename_split[1]

    baseline = parse_dict["model_type"] in ['GCNSVD', 'GCNJaccard', 'RGCN']

    parse_dict["train_fraction"] = eval(filename_split[filename_split.index("tr") + 1]) if "tr" in filename_split else 1
    parse_dict["added_edge_fraction"] = eval(filename_split[filename_split.index("ed") + 1]) if "ed" in filename_split else 0
    parse_dict["feature_noise_ratio"] = eval(filename_split[filename_split.index("ed") + 2]) if filename_split[filename_split.index("ed") + 2] != "beta" else 0
    parse_dict["beta1"] = eval(filename_split[filename_split.index("beta") + 1])
    parse_dict["beta2"] = eval(filename_split[filename_split.index("beta") + 2])
    parse_dict["latent_size"] = int(filename_split[filename_split.index("lat") + 1])
    parse_dict["sample_size"] = int(filename_split[filename_split.index("samp") + 1])
    parse_dict["num_layers"] = int(filename_split[filename_split.index("lay") + 1]) if "lay" in filename_split else 2
    parse_dict["is_anneal_beta"] = eval(filename_split[filename_split.index("anl") + 1])
    parse_dict["val_use_mean"] = eval(filename_split[filename_split.index("mean") + 1])
    parse_dict["reparam_all_layers"] = eval(filename_split[filename_split.index("reall") + 1])
    parse_dict["epochs"] = int(filename_split[filename_split.index("epochs") + 1])
    parse_dict["lr"] = eval(filename_split[filename_split.index("lr") + 1]) if "lr" in filename_split else -1
    parse_dict["weight_decay"] = eval(filename_split[filename_split.index("weight_decay") + 1]) if "weight_decay" in filename_split else -1
    parse_dict["seed"] = int(filename_split[filename_split.index("seed") + 1])
    parse_dict["idx"] = filename_split[filename_split.index("id") + 1][:-2]
    if baseline:
        parse_dict["threshold"] = float(filename_split[filename_split.index("threshold") + 1])
        parse_dict["gamma"] = float(filename_split[filename_split.index("gamma") + 1]) if "gamma" in filename_split else None
    else:
        parse_dict["reparam_mode"] = filename_split[filename_split.index("reparam") + 1]
        parse_dict["prior_mode"] = filename_split[filename_split.index("prior") + 1]
        parse_dict["struct_dropout_mode"] = filename_split[filename_split.index("sdrop") + 1] if "sdrop" in filename_split else "(standard,0.6)"
    return parse_dict

def parse_filename_adversarial(filename, baseline=False):
    """Parse the filename of the adversarial experment result file into a dictionary of settings."""
    parse_dict = {}
    filename_split = filename.split("_")
    parse_dict["data_type"] = filename_split[0]
    parse_dict["model_type"] = filename_split[1]
    parse_dict["direct_attack"] = eval(filename_split[filename_split.index("dire") + 1])
    parse_dict["attacked_nodes"] = filename_split[filename_split.index("nodes") + 1]
    parse_dict["n_perturbations"] = eval(filename_split[filename_split.index("pert") + 1])
    parse_dict["latent_size"] = int(filename_split[filename_split.index("lat") + 1])
    parse_dict["sample_size"] = int(filename_split[filename_split.index("samp") + 1])
    parse_dict["num_layers"] = eval(filename_split[filename_split.index("l") + 1]) if "l" in filename_split else 2
    parse_dict["is_anneal_beta"] = eval(filename_split[filename_split.index("anl") + 1])
    parse_dict["val_use_mean"] = eval(filename_split[filename_split.index("mean") + 1])
    parse_dict["reparam_all_layers"] = filename_split[filename_split.index("reall") + 1]
    parse_dict["lr"] = eval(filename_split[filename_split.index("lr") + 1]) if "lr" in filename_split else -1
    parse_dict["weight_decay"] = eval(filename_split[filename_split.index("l2") + 1]) if "l2" in filename_split else -1
    parse_dict["epochs"] = int(filename_split[filename_split.index("epochs") + 1])
    parse_dict["seed"] = int(filename_split[filename_split.index("seed") + 1])
    parse_dict["cuda"] = filename_split[filename_split.index("id") - 1]
    parse_dict["idx"] = filename_split[filename_split.index("id") + 1][:-2]
    if not baseline:
        parse_dict["beta1"] = eval(filename_split[filename_split.index("beta") + 1])
        parse_dict["beta2"] = eval(filename_split[filename_split.index("beta") + 2])
        parse_dict["reparam_mode"] = filename_split[filename_split.index("reparam") + 1]
        parse_dict["prior_mode"] = filename_split[filename_split.index("prior") + 1]
        parse_dict["struct_dropout_mode"] = filename_split[filename_split.index("sdrop") + 1]
    else:
        parse_dict["gamma"] = eval(filename_split[filename_split.index("gamma") + 1])
        parse_dict["threshold"] = eval(filename_split[filename_split.index("threshold") + 1][:-2])
    return parse_dict


params = [
    { "start": 34.77,  "attr": "Ra",        "low": 5.0, "high": 100.0, "lists": ["all"] },
    { "start": 2.706,   "attr": "cm",        "low": 0.1, "high": 4.0, "lists": ["all"] },
    { "start": 49.95,  "attr": "ena",       "low": 40.0, "high": 50.0, "lists": ["all"] },
    { "start": -70.03,  "attr": "ek",        "low": -100.0, "high": -70.0, "lists": ["all"] },
    { "start": -64.42,  "attr": "e_pas",     "low": -70.0, "high": -50.0, "lists": ["all"] },
    { "start": 0.0005955, "attr": "g_pas",     "low": 0, "high": 0.00003, "lists": ["all"] },
    { "start": 0.5955,  "attr": "sh_Na",     "low": 0, "high": 10, "lists": ["all"] },
    { "start": 10,  "attr": "tau_CaPool",     "low": 1, "high": 500, "lists": ["all"] },

    { "start":  0.87485,  "attr": "gbar_Na",     "low": 0, "high": 0.05, "lists": ["all"] },
    { "start": 0.0297,  "attr": "gbar_Kd",     "low": 0, "high": 0.04, "lists": ["all"] },
    { "start": 0.000264,  "attr": "gbar_Kslow",  "low": 0, "high": 0.004, "lists": ["all"] },
    { "start": 0.07215,  "attr": "gbar_KA",     "low": 0, "high": 0.005, "lists": ["all"] },
    { "start": 0.001,  "attr": "gbar_KCa",    "low": 0, "high": 0.004, "lists": ["all"] },
    { "start": 0.00081441,  "attr": "gbar_LCa",  "low": 0, "high": 0.001, "lists": ["all"] },

    { "start": -30.805,  "attr": "eh",       "low": -40.0, "high": -25.0, "lists": ["apical"] },
    { "start": 0.00335,  "attr": "gbar_Ih",    "low": 0, "high": 0.00003, "lists": ["apical"] },
    { "start": 0.000107,  "attr": "gbar_CaT",    "low": 0, "high": 18e-3, "lists": ["apical"] },
]

top = [[34.40577448714667,
  1.7746337170486868,
  48.600061083126825,
  -73.37824874831657,
  -52.149512474246556,
  2.8689454891603497e-05,
  7.600064936952291,
  6.513661312706145,
  0.01835806177392501,
  0.012685911771409467,
  0.001009786028927451,
  0.003485358049971202,
  0.0009111182551995163,
  0.0006405838020076363,
  -36.191181538089175,
  2.6308088272967942e-06,
  0.009520566435955282],
 [54.371057327671025,
  1.343586187918468,
  44.40845548134062,
  -81.17397852577881,
  -52.149512474246556,
  2.8689454891603497e-05,
  7.600064936952291,
  12.492102024675049,
  0.01835806177392501,
  0.012243090987314832,
  0.001009786028927451,
  0.0025920677224618473,
  0.0006458839218994715,
  0.0006437525063628547,
  -36.474771746065244,
  1.480641964136122e-06,
  0.009384267411892713],
 [34.40577448714667,
  1.7746337170486868,
  48.25121832219984,
  -85.83988610793635,
  -52.149512474246556,
  2.9121194317970837e-05,
  7.600064936952291,
  11.469065054901318,
  0.01835806177392501,
  0.012685911771409467,
  0.001009786028927451,
  0.003485358049971202,
  0.0009111182551995163,
  0.0006405838020076363,
  -36.191181538089175,
  4.9750908402217285e-06,
  0.009520566435955282],
 [34.40577448714667,
  1.7746337170486868,
  48.25121832219984,
  -73.37824874831657,
  -52.149512474246556,
  2.8689454891603497e-05,
  7.600064936952291,
  11.99833703626091,
  0.01835806177392501,
  0.012685911771409467,
  0.001009786028927451,
  0.003485358049971202,
  0.0009111182551995163,
  0.0006405838020076363,
  -36.191181538089175,
  4.9750908402217285e-06,
  0.009520566435955282],
 [34.40577448714667,
  1.7746337170486868,
  48.25121832219984,
  -73.37824874831657,
  -52.149512474246556,
  2.8689454891603497e-05,
  7.600064936952291,
  12.492102024675049,
  0.01835806177392501,
  0.012685911771409467,
  0.001009786028927451,
  0.003485358049971202,
  0.0009111182551995163,
  0.0006405838020076363,
  -36.191181538089175,
  4.9750908402217285e-06,
  0.009520566435955282],
 [30.15666549418986,
  1.7746337170486868,
  44.40845548134062,
  -81.17397852577881,
  -52.149512474246556,
  2.8689454891603497e-05,
  7.600064936952291,
  12.492102024675049,
  0.01835806177392501,
  0.012243090987314832,
  0.001009786028927451,
  0.0025920677224618473,
  0.0006458839218994715,
  0.0006437525063628547,
  -36.474771746065244,
  4.9750908402217285e-06,
  0.009384267411892713],
 [30.15666549418986,
  1.7746337170486868,
  47.11501790497679,
  -81.17397852577881,
  -52.149512474246556,
  2.8689454891603497e-05,
  7.600064936952291,
  12.492102024675049,
  0.01835806177392501,
  0.012243090987314832,
  0.001009786028927451,
  0.0025920677224618473,
  0.0006458839218994715,
  0.0006437525063628547,
  -36.474771746065244,
  4.9750908402217285e-06,
  0.009384267411892713],
 [34.40577448714667,
  1.7746337170486868,
  48.25121832219984,
  -85.83988610793635,
  -52.149512474246556,
  2.8689454891603497e-05,
  7.600064936952291,
  12.492102024675049,
  0.01835806177392501,
  0.012685911771409467,
  0.001009786028927451,
  0.003485358049971202,
  0.0009111182551995163,
  0.0006405838020076363,
  -36.191181538089175,
  4.9750908402217285e-06,
  0.009520566435955282]]

from olfactorybulb.database import *
import os,sys
from neuronunit.tests.olfactory_bulb.publications import *
from neuronunit.tests.olfactory_bulb.tests import *
from neuronunit.models.neuron_cell import NeuronCellModel
from sciunit.suites import TestSuite
from pandas import DataFrame
import quantities as pq
from neuronunit.tests.olfactory_bulb.utilities import cache
from linetimer import CodeTimer
import string, math
from scipy import optimize
import numpy as np
import matplotlib.pyplot as plt
#import smt
#from smt.surrogate_models.genn import GENN, load_smt_data
from scipy import optimize
import linetimer
import multiprocessing
from multiprocessing import Pool, TimeoutError
from sciunit.scores import ZScore

cell_type = 'mc'

# Load tests
measurements = Measurement\
    .select(Measurement)\
    .join(Property)\
    .switch(Measurement)\
    .join(Source)\
    .where((Measurement.property.type == "Electrophysiology") & (Measurement.property.id.startswith(cell_type+'_')))\
    .order_by(Measurement.property.id)

properties = {}

for m in measurements:
    test_generic = str(m.property.test_class_generic)
    pub = str(m.source.publication_class).strip()
    class_name = test_generic+pub

    if test_generic not in properties:
        properties[test_generic] = []

    globals()[class_name] = type(class_name,
                                 (eval(pub), eval(test_generic)),
                                 {})

    print('creating specific test class: ' + class_name)

    test_instance = eval(class_name)(observation={"mean": m.mean * eval(m.property.units), "std": m.std * eval(m.property.units), "n": m.n})

    properties[test_generic].append(test_instance)

# Load model classes
model_classes = list(CellModel\
                    .select(CellModel)\
                    .where(CellModel.cell_type == cell_type.upper())
                     )
for i, m in enumerate(model_classes):
    nmsp = string.join(m.isolated_model_class.split('.')[:-1],'.')
    cls = m.isolated_model_class.split('.')[-1]

    import_cmd = 'from '+nmsp+' import '+cls+' as Model'+str(i)
    print(import_cmd)
    exec(import_cmd)

# Create work item list
work_items = []

for model in model_classes:
    work_items.append({"model_class": model.isolated_model_class })

def get_suite_score(item):
    results = item
    results["properties"] = {}
    results["model_score"] = 0

    import prev_ob_models
    exec('cell = '+ str(item["model_class"]) +'()')

    from neuron import h
    ind = item["param_values"]

    for pi, pv in enumerate(ind):
        if params[pi]["attr"] == "tau_CaPool":
            setattr(h, params[pi]["attr"], pv)
        else:
            for param_list in params[pi]["lists"]:
                for sec in getattr(cell.cell, param_list):
                    setattr(sec, params[pi]["attr"], pv)

    model = NeuronCellModel(cell.soma(0.5),name=cell.__class__.__module__+'.'+cell.__class__.__name__+'|'+str(ind))

    for prop in properties.keys():

        if prop not in results["properties"]:
            results["properties"][prop] = { "tests": {}, "total_n": 0, "z_score_combined": None}

        prop_tests = properties[prop]

        for prop_test in prop_tests:

            prop_test_result = {}
            results["properties"][prop]["tests"][prop_test.__class__.__name__] = prop_test_result

            try:
                #print('Starting', item, prop_test)
                prediction = prop_test.generate_prediction(model)
                #print('Finished', item, prop_test, prediction)

            except:
                import traceback
                prediction = traceback.format_exc()
                print(prediction)

            prop_test_result["observation"] = prop_test.observation
            prop_test_result["prediction"] = prediction

            if type(prediction) != str:
                z_score = (prediction - prop_test.observation["mean"])/prop_test.observation["std"]
                z_score = z_score.simplified
            else:
                z_score = 6.0 # errors are treated as 6 std deviation

            z_weighed = z_score * prop_test.observation["n"]

            prop_test_result["z_score"] = z_score
            prop_test_result["z_score_weighed"] = z_weighed

            results["properties"][prop]["total_n"] += prop_test.observation["n"]

        results["properties"][prop]["z_score_combined"] = sum([i["z_score_weighed"] for i in results["properties"][prop]["tests"].values()])
        results["properties"][prop]["z_score_combined"] /= results["properties"][prop]["total_n"]

        results["model_score"] += results["properties"][prop]["z_score_combined"].magnitude**2

    import math
    results["model_score"] = math.sqrt(results["model_score"])

    return results

def evaluate(ind):
    def do_work():
        from prev_ob_models.Birgiolas2020.isolated_cells import MC
        score = get_suite_score({
            "model_class": "prev_ob_models.Birgiolas2020.isolated_cells.MC",
            "param_values": ind
        })

        return score["model_score"],

    from multiprocess import Pool, TimeoutError
    pool = Pool(processes = 1)

    try:
        result = pool.apply_async(do_work).get(timeout=4*60)
    except TimeoutError:
        print('Simulation timed out')
        pool.terminate()
        result = 9*10.0,
    except:
        print('Error in simulation')
        import traceback
        print(traceback.format_exc())
        pool.terminate()
        result = 9*10.999,

    return result

class NoDaemonProcess(multiprocessing.Process):
    # make 'daemon' attribute always return False
    def _get_daemon(self):
        return False
    def _set_daemon(self, value):
        pass
    daemon = property(_get_daemon, _set_daemon)

# We sub-class multiprocessing.pool.Pool instead of multiprocessing.Pool
# because the latter is only a wrapper function, not a proper class.
class MyPool(multiprocessing.pool.Pool):
    Process = NoDaemonProcess

def GA(suggested_pop=None, n=30, NGEN=30):
    #genn.options['print_global'] = False

    from deap import base, creator
    import math

    creator.create("FitnessMin", base.Fitness, weights=(-1,))
    creator.create("Individual", list, fitness=creator.FitnessMin)

    import random
    from deap import tools

    def random_indiv():
        result = [random.random()] * len(params)
        for i, pv in enumerate(result):
            result[i] = (params[i]["high"]-params[i]["low"])*pv+params[i]["low"]

        return creator.Individual(result)

    toolbox = base.Toolbox()
    toolbox.register("individual", random_indiv)
    toolbox.register("population", tools.initRepeat, list, toolbox.individual)

    def evaluate_surrogate(individual):
        return genn.predict_values(np.array([individual])).flatten()[0],

    lows = [p["low"] for p in params]
    highs = [p["high"] for p in params]

    toolbox.register("mate", tools.cxSimulatedBinaryBounded, eta=0.1, low=lows, up=highs)
    toolbox.register("mutate", tools.mutPolynomialBounded, eta=0.1, low=lows, up=highs, indpb=0.1)
    toolbox.register("evaluate", evaluate)

    toolbox.register("select", tools.selNSGA2, k=int(n*0.2))
    if suggested_pop is None:
        pop = toolbox.population(n=n)
    else:
        pop = [creator.Individual(i) for i in suggested_pop]

    CXPB, MUTPB = 1, 1
    F_DIVERSITY = 0.5

    # Evaluate the entire population
    processes = 15
    pool = MyPool(processes = processes, maxtasksperchild=1)
    fitnesses = pool.map(toolbox.evaluate, pop)
    pool.terminate()
    pool.join()

    for ind, fit in zip(pop, fitnesses):
        ind.fitness.values = fit

    for g in range(NGEN):
        # Select the parents
        elite = toolbox.select(pop)

        random_offspring = toolbox.population(n=int(n*F_DIVERSITY/2.0))
        diversity_offspring = random_offspring + tools.selRandom(pop, int(n*F_DIVERSITY/2.0))
        elite_offspring = tools.selRandom(elite, n-len(elite)-len(diversity_offspring))

        offspring = random_offspring + diversity_offspring + elite_offspring

        # Clone the selected individuals
        offspring = map(toolbox.clone, offspring)

        # Apply crossover and mutation on the offspring
        for child1, child2 in zip(offspring[::2], offspring[1::2]):
            if random.random() < CXPB:
                toolbox.mate(child1, child2)
                del child1.fitness.values
                del child2.fitness.values

        for mutant in offspring:
            if random.random() < MUTPB:
                toolbox.mutate(mutant)
                del mutant.fitness.values

        # Evaluate the individuals with an invalid fitness
        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]

        processes = max(1, multiprocessing.cpu_count()-1)
        pool = MyPool(processes = processes, maxtasksperchild=1)
        fitnesses = pool.map(toolbox.evaluate, invalid_ind)
        pool.terminate()
        pool.join()

        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit

        # The population is entirely replaced by the parents + offspring
        pop[:] = elite + offspring

        print("Generation",g,"out of",NGEN,"COMPLETE")
        print(np.min([i.fitness.values[0] for i in pop]))

    return pop, pop[0], toolbox.evaluate(pop[0])

pop, pop0, sur_fit = GA(top, n=max(5,multiprocessing.cpu_count()-1), NGEN=1)

import deap
top = deap.tools.selNSGA2(pop,8)
top


"""

 module to calculate welch t-statistics
 see copyright below

"""

import warnings;
warnings.simplefilter("ignore",DeprecationWarning)

from math import log;
from scipy import std;
from scipy import mean;
from math import sqrt;
from sys import stderr

def stddev(arr):
	N=len(arr);
	return sqrt((std(arr)**2)*N/(N-1));

import numpy as n;
import scipy;
import scipy.stats;
#from numpy.testing import NumpyTest, NumpyTestCase

def welchs_approximate_ttest(n1, mean1, sem1, \
                            n2, mean2, sem2):  #, alpha
#    '''Welch''s approximate t-test for the difference of two means of
#heteroscedasctic populations.

#Implemented from Biometry, Sokal and Rohlf, 3rd ed., 1995, Box 13.4

#:Parameters:
#    n1 : int
#        number of variates in sample 1
#    n2 : int
#        number of variates in sample 2
#    mean1 : float
#        mean of sample 1
#    mean2 : float
#        mean of sample 2
#    sem1 : float
#        standard error of mean1
#    sem2 : float
#        standard error of mean2
#    alpha : float
#        desired level of significance of test

#:Returns:
#    significant : bool
#        True if means are significantly different, else False
#    t_s_prime : float
#        t_prime value for difference of means
#    t_alpha_prime : float
#        critical value of t_prime at given level of significance

#Copyright (c) 2007, <NAME>

#All rights reserved.

#Redistribution and use in source and binary forms, with or without
#modification, are permitted provided that the following conditions are met:

 #   * Redistributions of source code must retain the above copyright
 #   notice, this list of conditions and the following disclaimer.
 #   * 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.
 #   * Neither the name of the University of Auckland, New Zealand nor
 #   the names of its contributors may be used to endorse or promote
 #   products derived from this software without specific prior written
 #   permission.

#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
#OWNER 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.'''
    svm1 = sem1**2 * n1
    svm2 = sem2**2 * n2
    meandiff=mean1-mean2;
    t_s_prime = meandiff/n.sqrt(svm1/n1+svm2/n2)
    sv1=sem1**2;
    sv2=sem2**2;
    upper=(sv1+sv2)**2
    lower=(sv1**2)/(n1-1)+(sv2**2)/(n2-1)

    df=int(upper/lower);

    pval=scipy.stats.t.cdf(t_s_prime, df);
    if(pval>0.5):
	pval=1.0-pval;
    #t_alpha_df1 = scipy.stats.t.ppf(1-alpha/2, n1 - 1)
    #t_alpha_df2 = scipy.stats.t.ppf(1-alpha/2, n2 - 1)
    #t_alpha_prime = (t_alpha_df1 * sem1**2 + t_alpha_df2 * sem2**2) / \
     #               (sem1**2 + sem2**2)
    return meandiff, df, t_s_prime, pval*2#, t_alpha_prime, abs(t_s_prime) > t_alpha_prime

#and a test class as well...

def welchs_approximate_ttest_sd(n1, mean1, sd1,\
                            n2, mean2, sd2): #, alpha
	return welchs_approximate_ttest(n1, mean1, sd1/n.sqrt(n1), \
                            n2, mean2, sd2/n.sqrt(n2)); #, alpha

def welchs_approximate_ttest_arr(arr1,arr2): #,alpha
	n1=len(arr1);
	n2=len(arr2);
	mean1=mean(arr1);
	mean2=mean(arr2);
	sd1=stddev(arr1);
	sd2=stddev(arr2);
	return welchs_approximate_ttest_sd(n1,mean1,sd1,n2,mean2,sd2); #,alpha

def ttest(arr1, arr2):
    return welchs_approximate_ttest_arr(arr1, arr2)[3]


#srun --pty --mem=4000mb --gres=gpu:1  python saliency.py  > ~/logs/sal.log 2>&1 &

from get_params import get_params
import sys, scipy.io, getopt
import os
import numpy as np
import matplotlib.pylab as plt
import pickle
#import cv2, glob
import glob

def main(argv):

    params = get_params() # check get_params.py in the same directory to see the parameters

    try:
      opts, args = getopt.getopt(argv,"hr:o:s:c:g:",["root=","out=","saliency_model=","caffe_path=", "gpu="])
    except getopt.GetoptError:
      print 'ERROR'
      sys.exit(2)
    for opt, arg in opts:
        if opt == '-h':
              print 'saliency.py -r <root> -o <out> -s <saliency_model> -c <caffe_path> -g <gpu>'
              sys.exit()
        elif opt in ("-r", "--root"):
              params['root'] = arg
        elif opt in ("-o", "--out"):
              params['out'] = arg
        elif opt in ("-s", "--saliency_model"):
              params['saliency_model'] = arg
        elif opt in ("-c", "--caffe_path"):
              params['caffe_path'] = arg
        elif opt in ("-g", "--gpu"):
              params['gpu'] = arg;

    sys.path.insert(0,os.path.join(params['caffe_path'],'python'))
    import caffe

    compute = 'True' # sys.argv[1] # write 'true' or 'false' in case you want to compute or just visualize

    if compute== 'true' or compute =='True':

        deploy_file = os.path.join(params['saliency_model'],'deploy.prototxt')
        model_file = os.path.join(params['saliency_model'],'model.caffemodel')
        # I am using the mean file from caffenet...but I guess we could use a grey image as well ?
        mean_file = '/media/HDD_2TB/mcarne/keyframe-extractor/src/Saliency/deep/meanfile.npy'

        if params['gpu'] == True:
            caffe.set_mode_gpu()
            print 'GPU mode selected'
        else:
            caffe.set_mode_cpu()
            print 'CPU mode selected'

        net = caffe.Classifier(deploy_file, model_file, mean=np.load(mean_file).mean(1).mean(1), channel_swap=(2,1,0),raw_scale=255)
        if not os.path.exists(params['out']):
            os.makedirs(params['out'])

        for imagepath in glob.glob(params['root']+"/*.jpg"):
            print "Procressing image..."
            scores = net.predict([caffe.io.load_image(imagepath)])
            feat = net.blobs['deconv1'].data
            #feat = np.reshape(feat, (10,4096))
            print feat, np.shape(feat)
            #meanfeat = np.average( feat, axis = 0 )
            # saves to disk
            fout = params['out']+'/'+os.path.splitext(os.path.basename(imagepath))[0];
            pickle.dump(feat,open(fout+'.p','wb'))
            scipy.io.savemat(fout+'.mat', mdict={'isal': feat})

if __name__ == "__main__":
   main(sys.argv[1:])
#else:

    #feat = pickle.load(open('saliency.p','rb'))
    #im = cv2.imread(imagepath)
    #print np.shape(im)
    #plt.imshow(np.array(feat).squeeze())

    #feat = np.resize(feat,(576,768) )
    #plt.show()