import torch
from torch import distributions, nn
import torch.nn.functional as F
from typing import *

from .conv_blocks import ResidualModel
from ..config import *

class BasicActorCriticNetwork(nn.Module):
    def __init__(
            self,
            block_kwargs: Sequence[Dict],
            use_adaptive_avg_pool: bool = True,
            fc_in_channels: Optional[int] = None,
            value_activation: Optional[nn.Module] = None,
            value_scale: float = 1.,
            value_shift: float = 0.
    ):
        super(BasicActorCriticNetwork, self).__init__()
        raise NotImplementedError('Fix -inf masking')
        self.base = ResidualModel(block_kwargs)
        if use_adaptive_avg_pool:
            self.prepare_for_fc = nn.AdaptiveAvgPool2d((1, 1))
            fc_in_channels = block_kwargs[-1]['out_channels']
        else:
            self.prepare_for_fc = nn.Identity()
            if fc_in_channels is None:
                raise ValueError('If use_adaptive_avg_pool is False, fc_in_channels must be provided')
        self.actor = nn.Linear(fc_in_channels, 4)
        self.critic = nn.Linear(fc_in_channels, 1)
        self.value_activation = nn.Identity() if value_activation is None else value_activation
        self.value_scale = value_scale
        self.value_shift = value_shift

    def forward(self, states: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
        base_out = self.prepare_for_fc(self.base(states))
        base_out = base_out.view(base_out.shape[0], -1)
        logits = self.actor(base_out)
        values = self.critic(base_out).squeeze(dim=-1)
        return logits, self.value_activation(values) * self.value_scale + self.value_shift

    def sample_action(self,
                      states: torch.Tensor,
                      available_actions_mask: Optional[torch.Tensor] = None,
                      train: bool = False):
        if train:
            logits, values = self.forward(states)
        else:
            with torch.no_grad():
                logits, values = self.forward(states)
        if available_actions_mask is not None:
            logits.masked_fill_(~available_actions_mask, float('-inf'))
        # In case all actions are masked, select one at random
        probs = F.softmax(torch.where(
            logits.isneginf().all(axis=-1, keepdim=True),
            torch.zeros_like(logits),
            logits
        ), dim=-1)
        m = distributions.Categorical(probs)
        sampled_actions = m.sample()
        if train:
            return sampled_actions, (logits, values)
        else:
            return sampled_actions

    def choose_best_action(self,
                           states: torch.Tensor,
                           available_actions_mask: Optional[torch.Tensor] = None) -> torch.Tensor:
        with torch.no_grad():
            logits, _ = self.forward(states)
            if available_actions_mask is not None:
                logits.masked_fill_(~available_actions_mask, float('-inf'))
            return logits.argmax(dim=-1)

class FullConvActorCriticNetwork(nn.Module):
    def __init__(
            self,
            cross_normalize_value: bool = True,
            use_separate_action_value_heads: bool = False,
            n_action_value_layers: int = 2,
            preprocessing_layer: Optional[nn.Module] = None,
            value_activation: Optional[nn.Module] = None,
            value_scale: float = 1.,
            value_shift: float = 0.,
            base_model: Optional[nn.Module] = None,
            base_out_channels: Optional[int] = None,
            actor_critic_activation: Optional[nn.Module] = None,
            **residual_model_kwargs
    ):
        super(FullConvActorCriticNetwork, self).__init__()
        self.use_separate_action_value_heads = use_separate_action_value_heads
        self.preprocessing_layer = preprocessing_layer if preprocessing_layer is not None else nn.Identity()
        if base_model is None:
            self.base = ResidualModel(**residual_model_kwargs)
        else:
            self.base = base_model
            assert len(residual_model_kwargs.keys()) == 0, f'Unknown args: {residual_model_kwargs.keys()}'
        if base_model is None:
            self.base_out_channels = residual_model_kwargs['block_kwargs'][-1]['out_channels']
            actor_critic_activation = residual_model_kwargs['block_kwargs'][-1].get('activation', nn.ReLU)
        else:
            self.base_out_channels = base_out_channels
            assert actor_critic_activation is not None
        actor_layers = []
        critic_layers = []
        for i in range(n_action_value_layers - 1):
            actor_layers.append(nn.Linear(self.base_out_channels, self.base_out_channels))
            actor_layers.append(actor_critic_activation())
            critic_layers.append(nn.Linear(self.base_out_channels, self.base_out_channels))
            critic_layers.append(actor_critic_activation())
        if self.use_separate_action_value_heads:
            actor_layers.append(nn.Linear(self.base_out_channels, 4 * N_PLAYERS))
            critic_layers.append(nn.Linear(self.base_out_channels, 1 * N_PLAYERS))
        else:
            actor_layers.append(nn.Linear(self.base_out_channels, 4))
            critic_layers.append(nn.Linear(self.base_out_channels, 1))
        self.actor = nn.Sequential(*actor_layers)
        self.critic = nn.Sequential(*critic_layers)
        self.cross_normalize_value = cross_normalize_value
        if self.cross_normalize_value:
            if value_activation is not None:
                print('WARNING: Setting value_activation has no effect while cross_normalize_value is True')
            if value_scale != 1.:
                print('WARNING: Setting value_scale has no effect while cross_normalize_value is True')
            if value_shift != 0.:
                print('WARNING: Setting value_shift has no effect while cross_normalize_value is True')
            self.value_activation = None
            self.value_scale = None
            self.value_shift = None
        else:
            self.value_activation = nn.Identity() if value_activation is None else value_activation
            self.value_scale = value_scale
            self.value_shift = value_shift

    def forward(self,
                states: torch.Tensor,
                head_locs: torch.Tensor,
                still_alive: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
        """
        @param states: Tensor of shape (batch_size, n_channels, n_rows, n_cols) representing the board
        @param head_locs: Tensor of shape (batch_size, n_geese), containing the integer index locations of the goose
            heads whose actions/values should be returned
        @param still_alive: Boolean tensor of shape (batch_size, n_geese), where True values indicate which geese are
            still alive and taking actions
        @return (policy, value):
             policy_logits: Tensor of shape (batch_size, n_geese, 4), representing the action distribution per goose
             value: Tensor of shape (batch_size, n_geese), representing the predicted value per goose
        """
        batch_size, n_geese = head_locs.shape
        base_out = self.base(self.preprocessing_layer(states))
        if base_out.shape[-2:] != states.shape[-2:]:
            raise RuntimeError(f'Fully convolutional networks must use padding so that the input and output sizes match'
                               f'Got input size: {states.shape} and output size: {base_out.shape}')
        # Reshape to tensor of shape (batch_size, n_channels, n_rows * n_cols)
        # Then, swap axes so that channels are last (batch_size, n_rows * n_cols, n_channels)
        base_out = base_out.reshape(base_out.shape[0], self.base_out_channels, -1).transpose(-2, -1)
        batch_indices = torch.arange(batch_size).repeat_interleave(n_geese)
        head_indices = torch.where(
            still_alive,
            head_locs,
            torch.zeros_like(head_locs)
        ).view(-1).to(dtype=torch.int64)
        # Base_out_indexed (before .view()) is a tensor of shape (batch_size * n_geese, n_channels)
        # After .view(), base_out_indexed has shape (batch_size, n_geese, n_channels)
        base_out_indexed = base_out[batch_indices, head_indices].view(batch_size, n_geese, -1)
        actor_out = self.actor(base_out_indexed)
        critic_out = self.critic(base_out_indexed)
        if self.use_separate_action_value_heads:
            goose_indices = torch.arange(n_geese).repeat(batch_size)
            actor_out = actor_out.view(batch_size, n_geese, n_geese, 4)
            critic_out = critic_out.view(batch_size, n_geese, n_geese, 1)
            actor_out = actor_out[batch_indices, goose_indices, goose_indices].view(batch_size, n_geese, 4)
            critic_out = critic_out[batch_indices, goose_indices, goose_indices].view(batch_size, n_geese, 1)
        logits = torch.where(
            still_alive.unsqueeze(-1),
            actor_out,
            torch.zeros_like(actor_out)
        )
        values = torch.where(
            still_alive.unsqueeze(-1),
            critic_out,
            torch.zeros_like(critic_out)
        ).squeeze(dim=-1)
        if self.cross_normalize_value:
            if n_geese != 4.:
                raise RuntimeError('cross_normalize_value still needs to be implemented for n_geese != 4')
            values = values + torch.where(
                still_alive,
                torch.zeros_like(values),
                torch.zeros_like(values) + float('-inf')
            )
            win_probs = torch.softmax(values, dim=-1)
            remaining_rewards = torch.linspace(0., 1., n_geese, dtype=states.dtype, device=states.device)
            remaining_rewards_min = remaining_rewards[-(still_alive.sum(dim=-1))].unsqueeze(-1)
            remaining_rewards_var = 1. - remaining_rewards_min
            values = remaining_rewards_min + win_probs * remaining_rewards_var
            # TODO: This is a hacky solution - there should be a more elegant way to do this for any n_geese_remaining?
            values = torch.where(
                still_alive.sum(dim=-1, keepdim=True) == 4,
                values * 2.,
                values
            )
            values = torch.where(
                still_alive.sum(dim=-1, keepdim=True) == 3,
                values * 1.2,
                values
            )
            # After the value multiplication, the winning goose may have a value > 1
            # This "excess" value is redistributed evenly among the other geese
            max_vals = values.max(dim=-1, keepdim=True)[0]
            values = values + torch.where(
                max_vals > 1.,
                torch.where(
                    values.detach() == max_vals,
                    -(max_vals - 1.),
                    (max_vals - 1.) / (still_alive.sum(dim=-1, keepdim=True) - 1.)
                ),
                torch.zeros_like(values)
            )
            # Rescale values from the range [0., 1] to the range [-1., 1]
            return logits, 2. * values - 1.
        else:
            return logits, self.value_activation(values) * self.value_scale + self.value_shift

    def sample_action(self,
                      states: torch.Tensor,
                      head_locs: torch.Tensor,
                      still_alive: torch.Tensor,
                      available_actions_mask: Optional[torch.Tensor] = None,
                      train: bool = False):
        if train:
            logits, values = self.forward(states, head_locs, still_alive)
        else:
            with torch.no_grad():
                logits, values = self.forward(states, head_locs, still_alive)
        if available_actions_mask is not None:
            # In case all actions are masked, unmask all actions
            available_actions_mask = torch.where(
                (~available_actions_mask).all(dim=-1, keepdim=True),
                torch.ones_like(available_actions_mask),
                available_actions_mask
            )
            logits = logits + torch.where(
                available_actions_mask,
                torch.zeros_like(logits),
                torch.zeros_like(logits) + float('-inf')
            )
        log_probs = F.log_softmax(logits, dim=-1)
        m = distributions.Categorical(log_probs.exp())
        sampled_actions = m.sample()
        if train:
            return sampled_actions, (log_probs, values)
        else:
            return sampled_actions

    def choose_best_action(self,
                           states: torch.Tensor,
                           head_locs: torch.Tensor,
                           still_alive: torch.Tensor,
                           available_actions_mask: Optional[torch.Tensor] = None) -> torch.Tensor:
        with torch.no_grad():
            logits, _ = self.forward(states, head_locs, still_alive)
            if available_actions_mask is not None:
                logits.masked_fill_(~available_actions_mask, float('-inf'))
            return logits.argmax(dim=-1)

class QModel(nn.Module):
    def __init__(
            self,
            block_kwargs: Sequence[Dict],
            fc_in_channels: int,
            dueling_q: bool = False,
            use_adaptive_avg_pool: bool = True,
            value_activation: Optional[nn.Module] = None,
            value_scale: float = 1.,
            value_shift: float = 0.
    ):
        super(QModel, self).__init__()
        raise NotImplementedError('Fix -inf masking')
        self.base = ResidualModel(block_kwargs)
        self.dueling_q = dueling_q
        if use_adaptive_avg_pool:
            self.prepare_for_fc = nn.AdaptiveAvgPool2d((1, 1))
        else:
            self.prepare_for_fc = nn.Identity()
        fc_out_channels = fc_in_channels // 2
        if self.dueling_q:
            self.value = nn.Sequential(
                nn.Linear(fc_in_channels, fc_out_channels),
                nn.ReLU(),
                nn.Linear(fc_out_channels, 1)
            )
            self.advantage = nn.Sequential(
                nn.Linear(fc_in_channels, fc_out_channels),
                nn.ReLU(),
                nn.Linear(fc_out_channels, 4)
            )
        else:
            self.q = nn.Sequential(
                nn.Linear(fc_in_channels, fc_out_channels),
                nn.ReLU(),
                nn.Linear(fc_out_channels, 4)
            )
        self.value_activation = nn.Identity() if value_activation is None else value_activation
        self.value_scale = value_scale
        self.value_shift = value_shift

    def forward(self, states: torch.Tensor) -> torch.Tensor:
        base_out = self.prepare_for_fc(self.base(states))
        base_out = base_out.view(base_out.shape[0], -1)
        if self.dueling_q:
            values = self.value(base_out)
            advantages = self.advantage(base_out)
            q_values = values + (advantages - advantages.mean(dim=-1, keepdims=True))
        else:
            q_values = self.q(base_out)
        q_values = self.value_activation(q_values) * self.value_scale + self.value_shift
        return q_values

    def get_state_value(self, states: torch.Tensor) -> torch.Tensor:
        if self.dueling_q:
            base_out = self.prepare_for_fc(self.base(states))
            base_out = base_out.view(base_out.shape[0], -1)
            return self.value(base_out)
        else:
            return self.forward(states).max(dim=-1, keepdim=True)[0]

class DeepQNetwork(nn.Module):
    def __init__(self,
                 optimizer_constructor,
                 epsilon: Optional[float] = None,
                 softmax_exploration: bool = False,
                 delayed_updates: bool = False,
                 double_q: bool = False,
                 dueling_q: bool = False,
                 tau: float = 5e-3,
                 *args, **kwargs
                 ):
        super(DeepQNetwork, self).__init__()
        raise NotImplementedError('Fix -inf masking')

        self.epsilon = epsilon
        self.softmax_exploration = softmax_exploration
        self.delayed_updates = delayed_updates
        self.double_q = double_q
        self.dueling_q = dueling_q
        self.tau = tau
        assert 0. < tau < 1.

        self.q_1 = QModel(*args, dueling_q=dueling_q, **kwargs)
        self.q_1_opt = optimizer_constructor(self.q_1.parameters())
        if self.delayed_updates:
            self.target_q_1 = QModel(*args, dueling_q=dueling_q, **kwargs)
            for param, target_param in zip(self.q_1.parameters(), self.target_q_1.parameters()):
                target_param.data.copy_(param)
        if self.double_q:
            self.q_2 = QModel(*args, dueling_q=dueling_q, **kwargs)
            self.q_2_opt = optimizer_constructor(self.q_2.parameters())
            if self.delayed_updates:
                self.target_q_2 = QModel(*args, dueling_q=dueling_q, **kwargs)
                for param, target_param in zip(self.q_2.parameters(), self.target_q_2.parameters()):
                    target_param.data.copy_(param)

    def forward(self, states: torch.Tensor) -> torch.Tensor:
        return self.q_1(states)

    def sample_action(self,
                      states: torch.Tensor,
                      epsilon: Optional[Union[float, torch.Tensor]] = None,
                      available_actions_mask: Optional[torch.Tensor] = None,
                      get_preds: bool = False) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
        epsilon = self.epsilon if epsilon is None else epsilon
        if epsilon is None:
            raise RuntimeError('epsilon and self.epsilon are both None')

        with torch.no_grad():
            q_vals = self.forward(states)
        if available_actions_mask is not None:
            q_vals.masked_fill_(~available_actions_mask, float('-inf'))
        if self.softmax_exploration:
            logits = q_vals
        else:
            logits = torch.where(
                q_vals.isneginf(),
                q_vals,
                torch.zeros_like(q_vals)
            )
        # In case all actions are masked, select one at random
        probs = F.softmax(torch.where(
            logits.isneginf().all(axis=-1, keepdim=True),
            torch.zeros_like(logits),
            logits * 10
        ), dim=-1)
        m = distributions.Categorical(probs)
        sampled_actions = m.sample()
        actions = torch.where(
            torch.rand(size=(q_vals.shape[0], 1), device=states.device) < epsilon,
            sampled_actions.unsqueeze(-1),
            q_vals.argmax(dim=-1, keepdim=True)
        )
        if get_preds:
            return actions, q_vals
        else:
            return actions

    def choose_best_action(self,
                           states: torch.Tensor,
                           available_actions_mask: Optional[torch.Tensor] = None,
                           get_preds: bool = False) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
        return self.sample_action(states, 0., available_actions_mask, get_preds)

    def train_on_batch(self,
                       s_batch: torch.Tensor,
                       a_batch: torch.Tensor,
                       r_batch: torch.Tensor,
                       d_batch: torch.Tensor,
                       next_s_batch: torch.Tensor,
                       gamma: float) -> Dict:
        assert 0. < gamma <= 1.
        a_batch = a_batch.unsqueeze(-1)
        r_batch = r_batch.unsqueeze(-1)
        d_batch = d_batch.unsqueeze(-1)
        q_values = self.q_1(s_batch).gather(-1, a_batch)
        if self.double_q:
            q_values_2 = self.q_2(s_batch).gather(-1, a_batch)
        if self.delayed_updates:
            next_step_q_model = self.target_q_1
            if self.double_q:
                next_step_q_model_2 = self.target_q_2
        else:
            next_step_q_model = self.q_1
            if self.double_q:
                next_step_q_model_2 = self.q_2
        next_q_values = next_step_q_model(next_s_batch)
        if self.double_q:
            next_q_values_2 = next_step_q_model_2(next_s_batch)
            next_q_values = torch.minimum(
                next_q_values.max(dim=-1, keepdims=True)[0],
                next_q_values_2.max(dim=-1, keepdims=True)[0]
            )
        q_target = r_batch + (1 - d_batch) * gamma * next_q_values
        q_target = q_target.detach()

        loss_1 = F.smooth_l1_loss(q_values, q_target, reduction='mean')
        self.q_1_opt.zero_grad()
        loss_1.backward()
        self.q_1_opt.step()
        if self.double_q:
            loss_2 = F.smooth_l1_loss(q_values_2, q_target, reduction='mean')
            self.q_2_opt.zero_grad()
            loss_2.backward()
            self.q_2_opt.step()

        if self.delayed_updates:
            for param, target_param in zip(self.q_1.parameters(), self.target_q_1.parameters()):
                target_param.data.copy_(self.tau * param + (1. - self.tau) * target_param)
            if self.double_q:
                for param, target_param in zip(self.q_2.parameters(), self.target_q_2.parameters()):
                    target_param.data.copy_(self.tau * param + (1. - self.tau) * target_param)

        losses_dict = {
            'Q_1_loss': loss_1
        }
        if self.double_q:
            losses_dict['Q_2_loss'] = loss_2
        return losses_dict


import numpy as np
import os
from astropy.io import fits

from specklepy.logging import logger
from specklepy.exceptions import SpecklepyTypeError
from specklepy.utils.time import default_time_stamp

class Outfile(object):

    def __init__(self, filename, path=None, data=None, shape=None, extensions=None, header=None, cards=None,
                 initialize=True, timestamp=False, header_card_prefix=None, verbose=True):
        """Instantiate a generic outfile.

        Args:
            filename (str):
                Name of the file that is always referred to in the background.
            path (str, optional):
                Target path under which the new file will be stored.
            data (np.ndarray, optional):
                If provided, the file will be initialized with these data and shape argument is ignored. Default is
                None.
            shape (tuple, dtype=int, optional):
                If provided, the file will be initialized with an empty array of this shape. This argument will be
                ignored if data argument is provided. Default is None.
            extensions (list of dict, optional):
                List of dictionaries of names (and data or shapes) for each extension that shall be initialized right
                away. Could look like this:
                [{'name': 'VAR', 'data': array},
                 {'name': 'SUB', 'shape': (1024, 1024)}]
                Default is None.
            header (fits.header, optional):
                Header that will be used to initialize the new Primary HDU. Default is None.
            cards (dict, optional):
                Dictionary of cards that will be added to the fits header. Default is None.
            initialize (bool, optional):
                Set to `False` to suppress creating a new file.
            timestamp (bool, optional):
                Set to True to automatically add a time stamp to the file name. Default is False.
            header_card_prefix (str, optional):
                Prefix of header cards. Default is None.
            verbose (bool, optional):
                Set to False to suppress logger output. Default is True.
        """

        # Input parameters
        if filename is None:
            raise RuntimeError("Outfile did not receive a filename!")
        else:
            self.filename = filename

        if path is None or isinstance(path, str):
            self.path = path
        else:
            raise SpecklepyTypeError('Outfile', argname='path', argtype=type(path), expected='str')

        if data is None or isinstance(data, np.ndarray):
            pass
        else:
            raise SpecklepyTypeError('Outfile', 'data', type(data), 'np.ndarray')

        if shape is None or isinstance(shape, tuple):
            self.shape = shape
        else:
            raise SpecklepyTypeError('Outfile', 'shape', type(shape), 'tuple')

        if shape is not None and data is not None:
            logger.info("Outfile instance ignores shape input as data is provided for initialization!")

        if isinstance(extensions, dict):
            self.extensions = [extensions]
        elif extensions is None or isinstance(extensions, list):
            self.extensions = extensions
        else:
            raise SpecklepyTypeError('Outfile', 'extensions', type(extensions), 'list of dict')

        if cards is None:
            self.cards = {}
        elif isinstance(cards, dict):
            self.cards = cards
        else:
            raise SpecklepyTypeError('Outfile', 'cards', type(cards), 'dict')

        if header is None or isinstance(header, fits.header.Header):
            pass
        else:
            raise SpecklepyTypeError('Outfile', 'header', type(header), 'fits.header')

        if not isinstance(timestamp, bool):
            raise SpecklepyTypeError('Outfile', 'timestamp', type(timestamp), 'bool')
        else:
            if timestamp:
                self.filename = filename.replace('.fits', '_{}.fits'.format(default_time_stamp()))

        if header_card_prefix is None:
            self.header_card_prefix = ""
        elif isinstance(header_card_prefix, str):
            # Assert that there are gaps between prefix and card keywords
            if header_card_prefix[-1] != ' ':
                header_card_prefix = header_card_prefix + ' '
            self.header_card_prefix = header_card_prefix
        else:
            raise SpecklepyTypeError('Outfile', 'header_card_prefix', type(header_card_prefix), 'str')

        if isinstance(verbose, bool):
            self.verbose = verbose
        else:
            raise SpecklepyTypeError('Outfile', 'verbose', type(verbose), 'bool')

        if initialize:
            self.initialize_file()

    def initialize_file(self, header=None, data=None):

        # Initialize primary HDU
        hdu = fits.PrimaryHDU(header=header)
        for key in self.cards:
            hdu.header.set(self.header_card_prefix + key, self.cards[key])
        if self.shape is not None and data is None:
            hdu.data = np.zeros(self.shape)
        if data is not None:
            hdu.data = data
        if 'DATE' not in hdu.header.keys():
            hdu.header.set('DATE', default_time_stamp())

        # Create a HDU list with the primary and write to file
        hdu_list = fits.HDUList([hdu])
        if self.verbose:
            logger.info(f"Initializing file {self.file_path!r}")
        hdu_list.writeto(self.file_path, overwrite=True)

        if self.extensions is not None:
            for extension in self.extensions:
                if 'name' not in extension:
                    raise ValueError(f"Outfile initialization with extensions failed, because extension did not "
                                     f"contain a name!")
                else:
                    name = extension['name']
                if 'data' in extension:
                    data = extension['data']
                elif 'shape' in extension:
                    data = np.empty(extension['shape'])
                else:
                    data = None
                if 'header' in extension:
                    header = extension['header']
                else:
                    header = None
                self.new_extension(name=name, data=data, header=header)

    @classmethod
    def from_file(cls, filename, path=None):
        return cls(filename=filename, path=path, initialize=False)

    @property
    def file_path(self):
        if self.path is None:
            return self.filename
        else:
            return os.path.join(self.path, self.filename)

    @property
    def data(self):
        return fits.getdata(self.file_path)

    @data.setter
    def data(self, data):
        with fits.open(self.file_path, mode='update') as hdu_list:
            hdu_list[0].data = data
            hdu_list[0].header.set('UPDATED', default_time_stamp())
            hdu_list.flush()
        if self.verbose:
            logger.info(f"Updating data in {self.file_path!r}")

    def __getitem__(self, extension):
        return fits.getdata(self.file_path, extension)  # [index]

    def __setitem__(self, extension, data):
        with fits.open(self.file_path, mode='update') as hdu_list:
            hdu_list[extension].data = data
            hdu_list[extension].header.set('UPDATED', default_time_stamp())
            hdu_list.flush()

    def update_frame(self, frame_index, data, extension=None):
        if extension is None:
            extension = 0
        with fits.open(self.file_path, mode='update') as hdu_list:
            hdu_list[extension].data[frame_index] = data
            hdu_list[extension].header.set('UPDATED', default_time_stamp())
            hdu_list.flush()
        # self.data[frame_index] = data

    def new_extension(self, name, data=None, header=None, index=None):
        """Create a new fits extension.

        All arguments are passed to the new HDU in the HDUlist of instances file, i.e. 'self.filename'.

        Args:
            name (str):
                Name of the new extension/ HDU.
            data (array, optional):
                Data array, passed to the new HDU.
            header (fits.header, optional):
                Fits header, passed to the new HDU.
            index (int, optional):
                Index of the extension, before which the new hdu is inserted. None translates into appending the new
                HDU at the end of the HDUlist.
        """

        with fits.open(self.file_path, mode='update') as hdu_list:
            hdu = fits.ImageHDU(data=data, name=name, header=header)
            if index is None:
                hdu_list.append(hdu=hdu)
            else:
                hdu_list.insert(index=index, hdu=hdu)
            hdu_list.flush()

    def update_extension(self, ext_name, data):
        if self.verbose:
            logger.info(f"Updating data in {self.file_path!r}[{ext_name}]")
        with fits.open(self.file_path, mode='update') as hdu_list:
            hdu_list[ext_name].data = data
            hdu_list.flush()

    def has_extension(self, ext_name):
        with fits.open(self.file_path) as hdu_list:
            return ext_name in hdu_list

    @staticmethod
    def extract_frame_shape(header):
        number_axes = header.get('NAXIS')
        if number_axes == 2 or number_axes == 3:
            frame_shape = (header.get('NAXIS1'), header.get('NAXIS2'))
        else:
            raise NotImplementedError(f"Frame shape extraction is not defined for FITS cubes with {number_axes!r} "
                                      f"axes!")
        return frame_shape

    @staticmethod
    def extract_frame_number(header):
        number_axes = header.get('NAXIS')
        if number_axes == 2:
            number_frames = 1
        elif number_axes == 3:
            number_frames = header.get('NAXIS3')
        else:
            raise NotImplementedError(f"Frame number extraction is not defined for FITS cubes with {number_axes!r} "
                                      f"axes!")
        return number_frames


from flask import Flask, render_template, request
# from markupsafe import escape
from os import getcwd

directory = getcwd()
app = Flask(__name__, template_folder='template', static_folder='static')

@app.route('/<username>')
def user_page(username):
    html_page = f' <h1> Hello {username} </h1>'
    return html_page

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        message = request.form.get('UserChat')
        if message:
            print(message)
        else:
            print('message is empty')
        return render_template('index.html')
    elif request.method == 'GET':
        return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=True)


# Calculus
import time

from math import *
# from BetterPrint import bPrint

'''
    python 计算微积分（
    这个类里面所有的方法都有精度 n (默认为 2 ** 25 )
    由于微积分需要用到极限，但在 python 中无法实现极限运算，故选择一个大数以模拟极限情况.
    可以在参数末尾加入 `n = 一个整数` 以改变精度
    注意：n越大，计算时间越久！
    导入时建议使用这个：
    >>> from calculus import Calculus
    >>> calculus = Calculus()
'''

class Calculus:

    '''
        python 计算微积分（
        这个类里面所有的方法都有精度 n (默认为 2 ** 25 )
        由于微积分需要用到极限，但在 python 中无法实现极限运算，故选择一个大数以模拟极限情况.
        可以在参数末尾加入 `n = 一个整数` 以改变精度
        注意：n越大，计算时间越久！
        导入时建议使用这个：
        >>> from calculus import Calculus
        >>> calculus = Calculus()
    '''

    def __init__(self, func: callable = sin):
        self.func: callable = func

    def definite_integral(self, a, b, f = self.func, n = 2 ** 25):
        '''
            定积分/黎曼积分

            使用方法:
            >>> definite_integral(lambda x: 关于x的函数表达式, 积分下限, 积分上限, 精度)
        '''
        __dx = (b - a) / n
        __y = 0
        return self.sum(lambda x: __dx * f(a + x * __dx), 0, n)

    def derivative(self, x, f = self.func, n = 2 ** 25):
        '''
            导数/微分
            在函数上某点的导数值

            使用方法:
            >>> derivative(点的横坐标, lambda x: 关于x的函数表达式, 精度)
        '''
        __dx = 1 / n
        __dy1 = f(x + __dx) - f(x)
        __dy2 = f(x) - f(x - __dx)
        __dy = (__dy1 + __dy2) / 2
        return __dy / __dx

    # 分析函数 f(x) 在区间 (a, b) 的凹凸性
    def convexity(self, f, a, b):
        '''
            分析函数的凹凸性

            使用方法:
            >>> convexity(lambda x: 关于x的函数表述式, 区间下限, 区间上限)
        '''
        __m1 = f((a + b) / 2)
        __m2 = (f(a) + f(b)) / 2

        # 通过凹凸性的定义判断
        if __m1 > __m2:
            return '凸'
        elif __m1 < __m2:
            return '凹'
        else:
            return '无法判断'

    def tangent_line(self, x, f = self.func, n = 2 ** 25):
        '''
            函数 f(x) 在点 (x, f(x)) 处的切线方程

            使用方法:
            >>> tangent_line(切点横坐标, lambda x: 关于x的函数表达式, 精度)
        '''
        __k = self.derivative(f, x, n)
        __m = f(x) - __k * x
        __result = {
            "斜率": __k,
            "y轴截距": __m,
            '直线方程': f'y={__k}x+{__m}'
        }
        return __result

    def normal_line(self, x, f = self.func, n = 2 ** 25):
        '''
            函数 f(x) 在点 (x, f(x)) 处切线的法线方程

            使用方法:
            >>> normal_line(切点横坐标, lambda x: 关于x的函数表达式, 精度)
        '''

        __k = - 1 / self.derivative(f, x, n)
        __m = f(x) - __k * x

        __result = {
            "斜率": __k,
            "y轴截距": __m,
            '法线方程': f'y={__k}x+{__m}'
        }
        return __result

    def sum(self, f, _start=0, _stop=10):
        '''
            sum(lambda x: 关于x的函数表达式, 起始值, 终值)
            不支持无穷大的计算，起始值必须大于终值

            For example:
            1)
                >>> def f(x):
                ...     return 1/x
                ... sum(f, 1, 10)
                2.9289682539682538
            2)
                >>> sum(lambda x: 1 / x, 1, 10)
                2.9289682539682538
        '''
        __sum = 0
        if _start > _stop:
            _start, _stop = _stop, _start
        x = _start

        while x <= _stop:
            __sum += f(x)
            x += 1

        return __sum

# 测试
if __name__ == '__main__':
    def test(f):
        cal = Calculus()
        print(cal.definite_integral(f, 1, 10))
        print(cal.derivative(f, 1, 10))
        print(cal.convexity(f, 1, 10))
        print(cal.tangent_line(f, 1, 10))
        print(cal.normal_line(f, 1, 10))
        print(cal.sum(f, 1, 10))
        print()

    test(lambda x: 1 / x)
    test(lambda x: x ** 2)
    test(lambda x: exp(x))
    test(lambda x: sin(x))
    test(lambda x: cos(x))
    test(lambda x: sqrt(x))
    test(lambda x: log(x))
    test(lambda x: sqrt(x))
    test(lambda x: x)


from modules.IPlugin  import IPlugin

class AddTextFromTargetToDestination(IPlugin):

    def __init__(self):
        super().__init__()
        self.pluginName = "AddTextFromTargetToDestination"
        self.pluginAutor = "Sebastian Rottgardt"
        self.pluginVersion = 0.1
        self.pluginDescription = "Add Text to Destination Column"
        self.pluginCommand = "addText"

    def preExecute(self):
        self.execute()

    def execute(self):
        message = []

        for rowsData in self.commandData.getItems():

            # check targetColumn exists
            if self.commandData.getTargetColumn() in rowsData:
                rowsData[self.commandData.getDestinationColumn()] = rowsData[self.commandData.getTargetColumn()] + str(self.commandData.getOptionsValue())
            else:
                rowsData[self.commandData.getTargetColumn()] = "targetColumn not exists"

            message.append(rowsData)

        if message is not None:
            self.commandData.setItems(message)


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Device',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('temperature', models.DecimalField(max_digits=5, decimal_places=2)),
                ('humidity', models.DecimalField(max_digits=5, decimal_places=2)),
            ],
            options={
            },
            bases=(models.Model,),
        ),
        migrations.CreateModel(
            name='Room',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('name', models.CharField(default=b'', max_length=50)),
                ('description', models.TextField(default=b'')),
            ],
            options={
            },
            bases=(models.Model,),
        ),
        migrations.AddField(
            model_name='device',
            name='room',
            field=models.ForeignKey(to='api.Room'),
            preserve_default=True,
        ),
    ]


import pandas as pd
import numpy as np
import streamlit as st
import datetime
import pickle
from joblib import dump,load
import ast
from sklearn.feature_extraction.text import CountVectorizer
import nltk
from nltk.stem.porter import PorterStemmer
import re

credits=pd.read_csv('tmdb_5000_credits.csv')
movies=pd.read_csv('tmdb_5000_movies.csv')
total_movies=pd.read_csv('movies.csv')
ratings = pd.read_csv('ratings.csv')
links = pd.read_csv('links.csv')
links['id']=links['tmdbId']
ratings = ratings.merge(links, on='movieId')

movies = movies.merge(credits, on='title')
def convert(obj):
    L = []
    for i in ast.literal_eval(obj):
        L.append(i['name'])
    return L

movies['genres'] = movies['genres'].apply(convert)
movies['keywords'] = movies['keywords'].apply(convert)
movies['spoken_languages'] = movies['spoken_languages'].apply(convert)
movies['production_companies'] = movies['production_companies'].apply(convert)
movies['production_countries'] = movies['production_countries'].apply(convert)
movies['cast'] = movies['cast'].apply(convert)
movies['crew'] = movies['crew'].apply(convert)

movies = movies[['movie_id','title','overview','genres','keywords','cast','crew','vote_average','vote_count','popularity']]

## BEST SCORED
C = movies["vote_average"].mean()
m=movies["vote_count"].quantile(0.85)

q_movies = movies.copy().loc[movies['vote_count'] >= m]

def weighted_rating(x, m=m, C=C):
    v = x['vote_count']
    R = x['vote_average']
    # Calculation based on the IMDB formula
    return (v/(v+m) * R) + (m/(m+v) * C)

q_movies['score'] = q_movies.apply(weighted_rating, axis=1)

q_movies[['title', 'vote_count', 'vote_average', 'score','genres']].head(10)

a_movies = q_movies.copy()
a_movies=a_movies[['title', 'vote_count', 'vote_average', 'score','genres']]
def gender_selector(a):
    return a_movies[a_movies['genres'].str.contains(a, regex=False)]

## CONTENT BASE

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf = TfidfVectorizer(stop_words='english')
movies['overview'] = movies['overview'].fillna('')
tfidf_matrix = tfidf.fit_transform(movies['overview'])
from sklearn.metrics.pairwise import linear_kernel
cosine_sim = linear_kernel(tfidf_matrix, tfidf_matrix)
indices = pd.Series(movies.index, index=movies['title']).drop_duplicates()

def get_recommendations(title, cosine_sim=cosine_sim):
    idx = indices[title]
    sim_scores = list(enumerate(cosine_sim[idx]))
    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
    movie_indices = [i[0] for i in sim_scores]
    movies_rec = movies[['title', 'genres']].iloc[movie_indices].copy()
    scores = [i[1] for i in sim_scores]
    movies_rec['con_scores'] = scores

    return movies_rec[['title','genres']].head(10)

##COLLOBRATIVE FILTERING

def clean_title(title):
    return re.sub("[^a-zA-Z0-9 ]","",title)

total_movies['title']=total_movies['title'].apply(clean_title)

def rating_cor_movies(title):
    movie_id = int(total_movies[total_movies['title'] == title]['movieId'].values)
    sim_users = ratings[(ratings["movieId"] == movie_id) & (ratings["rating"] >= 4)]["userId"].unique()
    sim_user_recs = ratings[(ratings["userId"].isin(sim_users) & (ratings["rating"] >= 4))]["movieId"]

    sim_user_recs = sim_user_recs.value_counts(()) / len(sim_users)
    sim_user_recs = sim_user_recs[sim_user_recs > 0.1]

    all_users = ratings[(ratings["movieId"].isin(sim_user_recs.index)) & (ratings["rating"] > 4)]
    all_users_recs = all_users["movieId"].value_counts() / len(all_users["userId"].unique())

    rec_percentages = pd.concat([sim_user_recs, all_users_recs], axis=1)
    rec_percentages.columns = ["similar", "all"]
    rec_percentages["score"] = rec_percentages["similar"] / rec_percentages["all"]

    rec_percentages = rec_percentages.sort_values("score", ascending=False)

    return rec_percentages.head(10).merge(total_movies, left_index=True, right_on="movieId")[["score", "title", "genres"]]

movies['id']=movies['movie_id']
def rating_cor_movies2(title):
    movie_id = int(movies[movies['title'] == title]['id'].values)

    sim_users = ratings[(ratings["movieId"] == movie_id) & (ratings["rating"] >= 4)]["userId"].unique()
    sim_user_recs = ratings[(ratings["userId"].isin(sim_users) & (ratings["rating"] >= 4))]["movieId"]

    sim_user_recs = sim_user_recs.value_counts(()) / len(sim_users)
    sim_user_recs = sim_user_recs[sim_user_recs > 0.1]

    all_users = ratings[(ratings["movieId"].isin(sim_user_recs.index)) & (ratings["rating"] > 4)]
    all_users_recs = all_users["movieId"].value_counts() / len(all_users["userId"].unique())

    rec_percentages = pd.concat([sim_user_recs, all_users_recs], axis=1)
    rec_percentages.columns = ["similar", "all"]
    rec_percentages["score"] = rec_percentages["similar"] / rec_percentages["all"]

    rec_percentages = rec_percentages.sort_values("score", ascending=False)

    return rec_percentages.merge(movies, left_index=True, right_on="id")[["title", "genres", "score"]].head(10)

##Hybrid

def hybrid(title):
    movie_id = int(movies[movies['title'] == title]['id'].values)

    sim_users = ratings[(ratings["movieId"] == movie_id) & (ratings["rating"] >= 4)]["userId"].unique()
    sim_user_recs = ratings[(ratings["userId"].isin(sim_users) & (ratings["rating"] >= 4))]["movieId"]

    sim_user_recs = sim_user_recs.value_counts(()) / len(sim_users)
    sim_user_recs = sim_user_recs[sim_user_recs > 0.1]

    all_users = ratings[(ratings["movieId"].isin(sim_user_recs.index)) & (ratings["rating"] > 4)]
    all_users_recs = all_users["movieId"].value_counts() / len(all_users["userId"].unique())

    rec_percentages = pd.concat([sim_user_recs, all_users_recs], axis=1)
    rec_percentages.columns = ["similar", "all"]
    rec_percentages["score"] = rec_percentages["similar"] / rec_percentages["all"]

    rec_percentages = rec_percentages.sort_values("score", ascending=False)
    rat_cor = rec_percentages.merge(movies, left_index=True, right_on="id")[["title", "genres", "score"]]

    idx = indices[title]
    sim_scores = list(enumerate(cosine_sim[idx]))
    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
    movie_indices = [i[0] for i in sim_scores]
    movies_rec = movies[['title']].iloc[movie_indices].copy()
    scores = [i[1] for i in sim_scores]
    movies_rec['con_scores'] = scores

    hybrid = rat_cor.merge(movies_rec, on='title')

    hybrid['total_scores'] = hybrid['score'] * (10 * hybrid['con_scores'])

    return hybrid.sort_values(by='total_scores', ascending=False)[['title', 'genres', 'total_scores']].head(10)

movies=movies.sort_values(by='movie_id')

##STREAMLIT
st.set_page_config(page_title="MRS")
st.sidebar.image('IMDB_Logo_.jpg')
st.header("Best Scored Movies According to IMDB users")

genre = st.radio("What\'s your favorite movie genre",('Comedy', 'Drama', 'Action','Thriller', 'Science Fiction', 'Mystery'),horizontal=True)

st.write(gender_selector(genre))
st.sidebar.write("You will have 5.000 movie choices")
st.sidebar.image("unnamed.jpg")
movielist = movies['title'].values

col1, col2 = st.columns(2)
with col1:
    st.title("Content Base Movie Recommendation System")
with col2:
    st.image('4c.png',width=200)

liked=st.selectbox("**Beğendiğiniz Film**", movielist)

if st.button('Recommend'):
    st.success('Here are our Recomendations for you', icon="✅")
    st.write(get_recommendations(liked, cosine_sim=cosine_sim))

col3, col4 = st.columns(2)
with col3:
    st.title("Collabrative Movie Recommendation System")
with col4:
    st.image('4a.jpg',width=200)

mliked=st.selectbox("**Beğendiğiniz Film2**", movielist)
if st.button('Recommendd'):
    st.success('Here are our Recomendations for you', icon="✅")
    st.write(rating_cor_movies2(mliked))

st.write('     ')

st.title("Hybrid Movie Recommendation System")
st.image('4b.png',width=500)

hliked=st.selectbox("**Beğendiğiniz Film Hybrid**", movielist)
if st.button('Hybrid Recommendation'):
    st.success('Here are our Recomendations for you', icon="✅")
    st.write(hybrid(hliked))

st.write('   ')
st.write('   ')
st.write('   ')
st.write('   ')
st.write('   ')
st.write('   ')
st.write('   ')
st.write('   ')
st.write('   ')
st.write('   ')
st.write('   ')
st.write('   ')
st.write('   ')


from tkinter import *

root=Tk()

varOpcion=IntVar()#Declara una variable tipo entera en la cual se utiliza los checkbot y radiobutton

#funcion q muesta o impreme el texto en nuestra etiqueta o frame
def  imprimir():
	#print(varOpcion.get())
	#Aqui comprobamos q tipo de datos es y le asignamos a nuesta etiqueta el texto expecificado
	if varOpcion.get() == 1:
		etiqueta.config(text="Has Elegido Masculino")
	elif varOpcion.get() == 2:
		etiqueta.config(text="Has Elegido Femenino")
	else:
		etiqueta.config(text="Has Elegido Otras")

Label(root,text="Genero:").pack()

#Aqui creamos un checkbot Tipo radio con Radiobutton()
#le pasamo en donde se quiere q este, un texto, una variable para asignarle, el valor y q tipo de comando se quiere q se ejecute cuando lo presionamos
Radiobutton(root,text="Masculino",variable=varOpcion,value=1,command=imprimir).pack()
Radiobutton(root,text="Femenino",variable=varOpcion,value=2,command=imprimir).pack()
Radiobutton(root,text="Otras Opciones",variable=varOpcion,value=3,command=imprimir).pack()

#Creamos aqui un label sencillo en el cual nos va a mostrar un texto
etiqueta=Label(root)
etiqueta.pack()

root.mainloop()


total_words = 0
total_lines = 0

with open('example.txt', 'r') as infile:
    for line in infile:
        total_words += len(line.split())
        total_lines += 1

print(f'Total number of words: {total_words}')
print(f'Total number of lines: {total_lines}')
print('Word count per line (line_number >> word_count):')

index = 0

with open('output.txt', 'w') as output:
    output.write(f'Total number of words: {total_words}\n')
    output.write(f'Total number of lines: {total_lines}\n')
    output.write('Word count per line (line_number >> word_count):\n')

    with open('example.txt', 'r') as infile:
        for line in infile:
            index += 1
            num_words = len(line.split())
            output.write(f'Line {index} >> {num_words} words\n')
            print(f"Line {index} >> {num_words} words")


# type: ignore

"""Add role list & anonymous answers

Revision ID: d5d3bface80d
Revises: b9b8f970b67f
Create Date: 2023-03-07 20:41:08.117604

"""
import sqlalchemy as sa

from alembic import op

# revision identifiers, used by Alembic.
revision = "d5d3bface80d"
down_revision = "b9b8f970b67f"
branch_labels = None
depends_on = None

def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column("poll", sa.Column("anonymous_allowed", sa.Boolean(), nullable=True))
    op.add_column("poll", sa.Column("allowed_roles", sa.ARRAY(sa.BigInteger()), nullable=True))
    op.add_column("poll_answer", sa.Column("anonymous", sa.Boolean(), nullable=True))

    op.execute("UPDATE poll SET anonymous_allowed = false")
    op.execute("UPDATE poll SET allowed_roles = '{}'")
    op.execute("UPDATE poll_answer SET anonymous = false")

    op.alter_column("poll", "anonymous_allowed", nullable=False)
    op.alter_column("poll", "allowed_roles", nullable=False)
    op.alter_column("poll_answer", "anonymous", nullable=False)
    # ### end Alembic commands ###

def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_column("poll_answer", "anonymous")
    op.drop_column("poll", "allowed_roles")
    op.drop_column("poll", "anonymous_allowed")
    # ### end Alembic commands ###


import logging
import time

import numpy as np
import theano

import lasagne

from job import Job

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

class Scaffolder(object):
    """
    Object to scaffold network training, validation, test and inference
    """
    PHASE_TRAIN = "phase_train"
    PHASE_VAL = "phase_val"
    PHASE_TEST = "phase_test"

    STATE_SETUP = "state_setup"
    STATE_RUN = "state_run"
    STATE_FINISH = "state_finish"

    def __init__(self, network_type, train_reader=None, val_reader=None, test_reader=None, inference=False, **kwargs):
        if not train_reader and not inference:
            raise AssertionError("Need either a training graph or an inference graph to compile.")

        self._compiled = False

        self.train_inputs = []
        self.val_inputs = []
        self.test_inputs = []
        self.inference_inputs = []

        self.train_outputs = []
        self.val_outputs = []
        self.test_outputs = []
        self.inference_outputs = []

        self.train_cost = None
        self.val_cost = None
        self.test_cost = None

        self.updates = None
        self.lr_schedule = {1: 0.1}

        self.train_fn = None
        self.val_fn = None
        self.test_fn = None
        self.inference_fn = None

        self.train_losses = []
        self.val_losses = []
        self.test_losses = []

        self.network_type = network_type
        self.args = kwargs
        self.network = None
        self.train_reader = train_reader
        self.val_reader = val_reader
        self.test_reader = test_reader
        self.inference = inference

        self.lr = theano.shared(lasagne.utils.floatX(0.01))
        self.momentum = theano.shared(lasagne.utils.floatX(0.9))

        self.setup()

    def setup(self):
        """
        Main routine to setup
        :return:
        """
        raise NotImplementedError()

    def compile(self):
        """
        Compile all expressions needed
        :return:
        """
        if self.train_reader:
            logger.info("Compiling training function.")
            self.train_fn = theano.function(self.train_inputs, self.train_outputs, updates=self.updates)
        if self.val_reader:
            logger.info("Compiling validation function.")
            self.val_fn = theano.function(self.val_inputs, self.val_outputs)
        if self.test_reader:
            logger.info("Compiling test function.")
            self.test_fn = theano.function(self.test_inputs, self.test_outputs)

        if self.inference:
            logger.info("Compiling inference function.")
            self.inference_fn = theano.function(self.inference_inputs, self.inference_outputs)

        self._compiled = True

    def infer(self, inputs):
        """
        Infer predictions from input values
        :param inputs:
        :return:
        """
        return self.inference_fn(inputs)

    def fit(self, n_epochs, job_name=None, snapshot=None, parallelism=1, lr_schedule=None, momentum=None):
        """
        Train the network
        :param n_epochs:
        :param job_name:
        :param snapshot:
        :param parallelism:
        :return:
        """
        if not self._compiled:
            raise AssertionError("Models are not compiled. Call 'compile()' first.")

        current_job = Job(job_name)
        current_job.set("state", Scaffolder.STATE_SETUP)
        if self.train_reader:
            self.train_reader.start_daemons(parallelism=parallelism)
        if self.val_reader:
            self.val_reader.start_daemons()
        if self.test_reader:
            self.test_reader.start_daemons()

        if not lr_schedule:
            lr_schedule = self.lr_schedule
        # Make sure we know the lr to begin with
        assert 1 in lr_schedule

        # Adjust momentum if applicable
        if momentum:
            self.momentum.set_value(lasagne.utils.floatX(momentum))

        current_job.set("state", Scaffolder.STATE_RUN)

        for epoch in range(1, n_epochs + 1):
            current_job.set("epoch", epoch)

            batch_times = 0
            batch_index = 0
            epoch_start = time.time()
            # Adapt LR if necessary
            if epoch in lr_schedule:
                val = lr_schedule[epoch]
                logger.info("Setting LR to " + str(val))
                self.lr.set_value(lasagne.utils.floatX(val))
            logger.info("Training Epoch %i" % (epoch))
            # Train for one epoch
            current_job.set("phase", Scaffolder.PHASE_TRAIN)
            for batch in self.train_reader.iterate():
                inputs, targets = batch
                batch_start = time.time()
                err = self.train_fn(inputs, targets)
                batch_end = time.time()
                batch_times += (batch_end - batch_start)
                batch_index += 1
                self.train_losses.append(err)
                self.on_batch_end(Scaffolder.PHASE_TRAIN)
                if batch_index % 100 == 0:
                    current_job.set("train_losses", self.train_losses)

                if batch_index == 20 and epoch == 1:
                    time_per_batch = batch_times / batch_index
                    total_dur = n_epochs * (time_per_batch * self.train_reader.num_batches())
                    eta = time.time() + total_dur
                    localtime = time.asctime(time.localtime(eta))
                    logger.info("Average time per forward/backward pass: " + str(time_per_batch))
                    logger.info("Expected duration for training: " + str(total_dur) + "s")
                    logger.info("ETA: %s", str(localtime))

            # In case we do have less than 100 batches, write back at the end to make sure we've got values
            current_job.set("train_losses", self.train_losses)

            if self.val_reader:
                current_job.set("phase", Scaffolder.PHASE_VAL)
                for batch in self.val_reader.iterate():
                    inputs, targets = batch
                    err = self.val_fn(inputs, targets)
                    self.val_losses.append(err)
                    self.on_batch_end(Scaffolder.PHASE_VAL)
                current_job.set("val_losses", self.val_losses)

            if self.test_reader:
                current_job.set("phase", Scaffolder.PHASE_TEST)
                for batch in self.test_reader.iterate():
                    inputs, targets = batch
                    err = self.test_fn(inputs, targets)
                    self.test_losses.append(err)
                    self.on_batch_end(Scaffolder.PHASE_TEST)
                current_job.set("test_losses", self.test_losses)

            epoch_end = time.time()
            logger.info("Epoch %i took %f seconds." % (epoch, epoch_end - epoch_start))
            if snapshot:
                logger.info("Saving model state to %s." % snapshot)
                self.save(snapshot)
            self.on_epoch_end()

        # Job done
        current_job.set("state", Scaffolder.STATE_RUN)

    def save(self, filename):
        """
        Store underlying network interface's weights
        :param filename:
        :return:
        """
        logger.info("Saving parameters to file '%s'" % filename)
        if self.network:
            self.network.save(filename)
        else:
            raise AssertionError("Network instance hasn't been create yet.")

    def load(self, filename, strict=True):
        """
        Load underlying network interface's weights from disk
        :param filename: Name of the parameter file
        :param loosely: Do not throw when shapes won't match. Just skip that layer instance
        :return:
        """
        logger.info("Loading parameters from file '%s'" % filename)
        if self.network:
            if not strict:
                self.network.load_non_strict(filename)
            else:
                self.network.load(filename)
        else:
            raise AssertionError("Network instance hasn't been create yet.")

    def on_epoch_end(self):
        """
        Epoch hook
        :return:
        """
        pass

    def on_batch_end(self, phase):
        """
        On batch end hook
        :param phase:
        :return:
        """
        pass

class Network(object):

    TRANSPLANT_MODE_DEFAULT = 1

    def __init__(self, inputs, **kwargs):

        if type(inputs) != list:
            raise AssertionError("Please provide a list of tensor variables as inputs.")

        self.output_layers = []
        self.input_layers = []
        self.last_layer = None
        self.registry = {}
        self.inputs = inputs

        # Weight transplant mode
        self.transplant_mode = Network.TRANSPLANT_MODE_DEFAULT
        if "transplant_mode" in kwargs:
            self.transplant_mode = kwargs["transplant_mode"]

        # In case some sub-class implements this, call it
        self.output_layers = self.init()
        if len(self.output_layers) != 1:
            raise AssertionError("Only one output layer supported at the moment.")
        # Post init setup
        self._post_init()

    def init(self):
        """
        Override this method if you want to generate any network architecture from scratch
        :return:
        """
        raise NotImplementedError()

    def _post_init(self):
        """
        Perform some post init sanity checks
        :return:
        """
        for layer in self.output_layers:
            # Count parameters for outlet
            logger.info(
                "Number of parameters for output '%s': %i" % (
                    layer.name, lasagne.layers.count_params(layer, trainable=True)))

    def save(self, filename):
        """
        Save network weights to disk
        :param filename:
        :return:
        """
        network = self.output_layers[0]
        np.savez(filename, *lasagne.layers.get_all_param_values(network))

    def load(self, filename):
        """
        Load network weights from disk
        :param filename:
        :return:
        """
        # load network weights from model file
        network = self.output_layers[0]
        with np.load(filename) as f:
            param_values = [f['arr_%d' % i] for i in range(len(f.files))]
        lasagne.layers.set_all_param_values(network, param_values)

    def _transplant(self, variable, value):
        """
        Try to transplant values into the target variable even if the shapes won't match
        :param variable: Tensor variable
        :param value: The new weights
        """
        if self.transplant_mode == Network.TRANSPLANT_MODE_DEFAULT:
            # Try to transplant weights
            old_value = variable.get_value()
            # First thing we try is to simply assign the values
            if old_value.shape == value.shape:
                variable.set_value(value)
                return

            # If that didn't work we try to partially assign the weights to the filters
            backup = variable.get_value()
            try:
                assert old_value.ndim == value.ndim
                if old_value.size > value.size:
                    logger.info("Parameter blob with shape %s needs transplant. Trying to fit source weights into target blob." % str(old_value.shape))
                    # We currently only support the case that we can align the old values nicely inside the new blob
                    if old_value.ndim == 4:
                        old_value[0:value.shape[0], 0:value.shape[1], 0:value.shape[2], 0:value.shape[3]] = value
                    elif old_value.ndim == 2:
                        old_value[0:value.shape[0], 0:value.shape[1]] = value
                else:
                    logger.info("Skipping blob with shape %s. Too many source parameters." % str(old_value.shape))

            except Exception as e:
                logger.warn("Something went wrong while trying to transplant filters. Rolling back operation.")
                logger.warn("Original warning: %s " % str(e))
                variable.set_value(backup)

        else:
            raise ValueError("Unsupported transplant mode %s" % str(self.transplant_mode))

    def load_non_strict(self, filename):
        network = self.output_layers[0]
        with np.load(filename) as f:
            values = [f['arr_%d' % i] for i in range(len(f.files))]

        params = lasagne.layers.get_all_params(network)
        if len(params) != len(values):
            raise ValueError("mismatch: got %d values to set %d parameters" %
                         (len(values), len(params)))

        for p, v in zip(params, values):
            if p.get_value().shape != v.shape:
                self._transplant(p, v)
            else:
                p.set_value(v)


import re

import pytest

from utilities import philips_hue, philips_hue_mock

@pytest.fixture
def config():
    configs = {
        'BRIDGE_IP_ADDRESS': '127.0.0.1',
        'USERNAME': 'test-user'
    }
    return configs

@pytest.fixture
def philips_hue_client(config):
    philips_hue_client = philips_hue.PhilipsHueClient(
        config['BRIDGE_IP_ADDRESS'], config['USERNAME'])
    return philips_hue_client

def test_set_color(philips_hue_client, requests_mock):
    bridge_ip_address = philips_hue_client.bridge_ip_address
    username = philips_hue_client.username
    matcher = re.compile(f'http://{bridge_ip_address}/api/{username}')
    requests_mock.register_uri('PUT', matcher,
                               text=philips_hue_mock.mock_hue_put_response)

    response = philips_hue_client.set_color('1', 0)

    assert response.status_code == 200
    assert "{'success': {'/lights/1/state/on': 'true'}}" in response.text
    assert "{'success': {'/lights/1/state/hue': '0'}}" in response.text

def test_set_color_bad_url(philips_hue_client, requests_mock):
    bridge_ip_address = philips_hue_client.bridge_ip_address
    username = philips_hue_client.username
    matcher = re.compile(f'http://{bridge_ip_address}/api/{username}')
    requests_mock.register_uri('PUT', matcher,
                               text=philips_hue_mock.mock_hue_put_response)

    with pytest.raises(philips_hue.BadAPIRequestError) as e:
        assert philips_hue_client.set_color('2', 65535)
    assert str(e.value) == 'invalid Philips Hue url'

def test_get_target_hue_from_incident_invalid_state():
    policy_name = 'unknown_policy'
    incident_state = 'unknown'
    notification = {'incident': {'policy_name': policy_name, "state": incident_state}}
    policy_hue_mapping = {
        'default': {
            'open': 65280,
            'closed': 24432
        }
    }

    with pytest.raises(philips_hue.UnknownIncidentStateError) as e:
        assert philips_hue.get_target_hue_from_monitoring_notification(
            notification, policy_hue_mapping)

    expected_error_value = ("Incident state for Google Cloud alerting policy "
                            "'unknown_policy' must be one of: ['open', "
                            "'closed']; actual: 'unknown'")
    assert str(e.value) == expected_error_value

def test_get_target_hue_with_nondefault_open_incident():
    policy_name = 'policyB'
    incident_state = 'open'
    expected_hue_value = 10126
    notification = {'incident': {'policy_name': policy_name, "state": incident_state}}
    policy_hue_mapping = {
        'policyB': {
            'open': expected_hue_value,
            'closed': 48013
        },
        'default': {
            'open': 65280,
            'closed': 24432
        }
    }

    actual_hue_value = philips_hue.get_target_hue_from_monitoring_notification(
        notification, policy_hue_mapping)

    assert actual_hue_value == expected_hue_value

def test_get_target_hue_with_nondefault_closed_incident():
    policy_name = 'policyB'
    incident_state = 'closed'
    expected_hue_value = 48013
    notification = {'incident': {'policy_name': policy_name, "state": incident_state}}
    policy_hue_mapping = {
        'policyB': {
            'open': 10126,
            'closed': expected_hue_value
        },
        'default': {
            'open': 65280,
            'closed': 24432
        }
    }

    actual_hue_value = philips_hue.get_target_hue_from_monitoring_notification(
        notification, policy_hue_mapping)

    assert actual_hue_value == expected_hue_value

def test_get_target_hue_with_default_open_incident():
    policy_name = 'unknown_policy'
    incident_state = 'open'
    expected_hue_value = 65280
    notification = {'incident': {'policy_name': policy_name, "state": incident_state}}
    policy_hue_mapping = {
        'default': {
            'open': expected_hue_value,
            'closed': 24432
        }
    }

    actual_hue_value = philips_hue.get_target_hue_from_monitoring_notification(
        notification, policy_hue_mapping)

    assert actual_hue_value == expected_hue_value

def test_get_target_hue_with_default_closed_incident():
    policy_name = 'unknown_policy'
    incident_state = 'closed'
    expected_hue_value = 24432
    notification = {'incident': {'policy_name': policy_name, "state": incident_state}}
    policy_hue_mapping = {
        'default': {
            'open': 65280,
            'closed': expected_hue_value
        }
    }

    actual_hue_value = philips_hue.get_target_hue_from_monitoring_notification(
        notification, policy_hue_mapping)

    assert actual_hue_value == expected_hue_value


# Saketh Kamuju, Jonathan King
# NOTE: Until you fill in the TicTacToe class, you will get AttributeErrors. Don't worry
# about those yet––follow the README for exactly what to do, rather than the errors
# you are seeing on the asserts.

class TicTacToeBoard:
    """A tic tac toe board

    Attributes:
        board - a list of '*'s, 'X's & 'O's. 'X's represent moves by player 'X', 'O's
            represent moves by player 'O' and '*'s are spots no one has yet played on
    """

    def __init__(self, board=["*", "*", "*", "*", "*", "*", "*", "*", "*"]):
        self.board = board

    def __str__(self):

        return str(self.board[0:3]) + "\n" + str(self.board[3:6]) + "\n" + str(self.board[6:9])

    def has_won(self, player):

        board = self.board
        win = [player, player, player]

        if board[0:3] == win or board[3:6] == win or board[6:9] == win:
            return True

        elif board[0:9:3] == win or board[1:9:3] == win or board[2:9:3] == win:
            return True

        elif board[0:9:4] == win or board[2:8:2] == win:
            return True

        return False

    def game_over(self):

        game = self

        if TicTacToeBoard.has_won(game, "X") or TicTacToeBoard.has_won(game, "O"):
            return True

        elif "*" not in game.board:
            return True

        return False

    def make_move(self, player, pos):

        if player == "X":
            if self.board[pos] == "*":
                self.board[pos] = "X"

            else:
                return False

        elif player == "O":
            if self.board[pos] == "*":
                self.board[pos] = "O"

            else:
                return False

        # print(self)
        return True

    def clear(self):

        self.board = []
        for i in range(9):
            self.board.append("*")

def play_tic_tac_toe():
    """Uses your class to play TicTacToe"""

    def is_int(maybe_int):
        """Returns True if val is int, False otherwise

        Args:
            maybe_int - string to check if it's an int

        Returns:
            True if maybe_int is an int, False otherwise
        """
        try:
            int(maybe_int)
            return True
        except ValueError:
            return False

    brd = TicTacToeBoard()
    brd.clear()
    players = ["X", "O"]
    turn = 0

    while not brd.game_over():
        print(brd)
        move: str = input(f"Player {players[turn]} what is your move? ")

        if not is_int(move):
            raise ValueError(
                f"Given invalid position {move}, position must be integer between 0 and 8 inclusive"
            )

        if brd.make_move(players[turn], int(move)):
            turn = not turn

    print(f"\nGame over!\n\n{brd}")
    if brd.has_won(players[0]):
        print(f"{players[0]} wins!")
    elif brd.has_won(players[1]):
        print(f"{players[1]} wins!")
    else:
        print(f"Board full, cat's game!")

if __name__ == "__main__":
    # Here are some tests. These are not at all exhaustive tests. You will DEFINITELY
    # need to write some more tests to make sure that your TicTacToeBoard class is behaving
    # proprely.
    brd = TicTacToeBoard()
    brd.make_move("X", 8)
    # print("")
    brd.make_move("O", 7)

    assert brd.game_over() == False
    # print("jello")

    brd.make_move("X", 5)
    brd.make_move("O", 6)
    brd.make_move("X", 2)

    assert brd.has_won("X") == True
    assert brd.has_won("O") == False
    assert brd.game_over() == True
    # print("jello")

    brd.clear()

    assert brd.game_over() == False
    # print("jello")

    brd.make_move("O", 3)
    brd.make_move("O", 4)
    brd.make_move("O", 5)
    # print("")

    assert brd.has_won("X") == False
    assert brd.has_won("O") == True
    assert brd.game_over() == True
    # print("jello")

    brd.clear()

    brd.make_move("X", 0)
    brd.make_move("X", 2)
    brd.make_move("X", 4)
    brd.make_move("X", 7)
    brd.make_move("O", 1)
    brd.make_move("O", 3)
    brd.make_move("O", 5)
    brd.make_move("O", 6)
    brd.make_move("O", 8)
    # print(brd)

    assert brd.has_won("X") == False
    assert brd.has_won("O") == False
    assert brd.game_over() == True
    # print("jello")
    brd.clear()

    print("All tests passed!")

    # uncomment to play!
    # play_tic_tac_toe()


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import random as rnd
import seaborn as sns

from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import Perceptron
from sklearn.linear_model import SGDClassifier

train_df = pd.read_csv('train.csv')
test_df = pd.read_csv('test.csv')
combine = [train_df,test_df]
train_df.shape
test_df.shape
combine[0].shape
combine[1].shape

train_df['Age'].plot()
train_df['Age'].plot(kind='line')
train_df['Age'].plot(kind='scatter')
train_df['Age'].plot(kind='box')

train_df.head()
train_df.tail()
train_df.describe()
train_df.describe(include=['O'])

train_df[['Pclass','Survived']].groupby(['Pclass'],
        as_index=False).mean().sort_values(by='Survived',ascending=True)
train_df[['Sex','Survived']].groupby(['Sex'],
        as_index=False).mean().sort_values(by='Sex',ascending=False)
train_df[['SibSp','Survived']].groupby(['SibSp'],
        as_index=False).mean().sort_values(by='SibSp',ascending=False)
train_df[['Parch','Survived']].groupby(['Parch'],
        as_index=False).mean().sort_values(by='Parch',ascending=False)

g = sns.FacetGrid(train_df,col='Survived')
g.map(plt.hist,'Age',bins=20)
plt.show()
g = sns.FacetGrid(train_df,col='Survived',row='Pclass',size=2.2,aspect=1.6)
g.map(plt.hist,'Age',bins=20)
plt.show()
g = sns.FacetGrid(train_df,row='Embarked',size=2.2,aspect=1.6)
g.map(sns.pointplot,'Pclass','Survived','Sex',palette='deep')
g.add_legend()
g = sns.FacetGrid(train_df,row='Embarked',size=2.2,aspect=1.6)
g.map(sns.barplot,'Sex','Fare',alpha=0.5,ci=None)
g.add_legend()

print('before',train_df.shape,test_df.shape,combine[0].shape,combine[1].shape)
train_df = train_df.drop(['Ticket','Cabin'],axis=1)
test_df = test_df.drop(['Ticket','Cabin'],axis=1)
combine = [train_df,test_df]
print('after',train_df.shape,test_df.shape,combine[0].shape,combine[1].shape)

for dataset in combine:
    dataset['Title'] = dataset.Name.str.extract(' ([A-Za-z]+)\.',expand=False)
print(train_df.shape,test_df.shape,combine[0].shape,combine[1].shape)
pd.crosstab(train_df['Title'],train_df['Sex'])

for dataset in combine:
    dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col',\
           'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'],'Rare')
    dataset['Title'] = dataset['Title'].replace('Mlle','Miss')
    dataset['Title'] = dataset['Title'].replace('Ms','Miss')
    dataset['Title'] = dataset['Title'].replace('Mme','Mrs')
train_df[['Title','Survived']].groupby(['Title'],
        as_index=False).mean().sort_values(by='Survived',ascending=False)

title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}
for dataset in combine:
    dataset['Title'] = dataset['Title'].map(title_mapping)
    dataset['Title'] = dataset['Title'].fillna(0)
train_df.head()

print('before',train_df.shape,test_df.shape,combine[0].shape,combine[1].shape)
train_df = train_df.drop(['Name','PassengerId'],axis=1)
test_df = test_df.drop(['Name'],axis=1)
combine = [train_df,test_df]
print('after',train_df.shape,test_df.shape,combine[0].shape,combine[1].shape)

for dataset in combine:
    dataset['Sex'] = dataset['Sex'].map({'female':1,'male':0}).astype(int)
train_df.head()

g = sns.FacetGrid(train_df,row='Pclass',col='Sex',size=2.2,aspect=1.6)
g.map(plt.hist,'Age',alpha=0.5,bins=20)
g.add_legend()

guess_ages = np.zeros((2,3))
guess_ages

for dataset in combine:
    for i in range(0,2):
        for j in range(0,3):
            guess_df = dataset[(dataset['Sex']==i) &
                               (dataset['Pclass']==j+1)]['Age'].dropna()
            age_guess = guess_df.median()
            guess_ages[i,j] = int( age_guess/0.5 + 0.5) * 0.5
guess_ages
for dataset in combine:
   for i in range(0,2):
       for j in range(0,3):
           dataset.loc[(dataset.Age.isnull()) & (dataset.Sex ==i) & (dataset.Pclass ==j+1),\
                       'Age'] = guess_ages[i,j]
dataset['Age'] = dataset['Age'].astype(int)
train_df.head(10)

train_df['AgeBand'] = pd.cut(train_df['Age'],5)
train_df[['AgeBand','Survived']].groupby(['AgeBand'],
        as_index=False).mean().sort_values(by='Survived',ascending=False)

for dataset in combine:
    dataset.loc[dataset['Age'] <= 16 , 'Age'] = 0
    dataset.loc[(dataset['Age'] > 16) & (dataset['Age'] <= 32),'Age'] = 1
    dataset.loc[(dataset['Age'] > 32) & (dataset['Age'] <= 48),'Age'] = 2
    dataset.loc[(dataset['Age'] > 48) & (dataset['Age'] <= 64),'Age'] = 3
    dataset.loc[dataset['Age'] > 64,'Age']
train_df.head(10)

train_df = train_df.drop(['AgeBand'],axis=1)
combine = [train_df,test_df]

for dataset in combine:
    dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1
train_df[['FamilySize','Survived']].groupby(['FamilySize'],
        as_index=False).mean().sort_values(by='Survived',ascending=False)

for dataset in combine:
    dataset['IsAlone'] = 0
    dataset.loc[dataset['FamilySize']==1,'IsAlone'] = 1
train_df[['IsAlone','Survived']].groupby(['IsAlone'],
        as_index=False).mean().sort_values(by='Survived',ascending=False)

train_df = train_df.drop(['Parch','SibSp','FamilySize'],axis=1)
test_df = test_df.drop(['Parch','SibSp','FamilySize'],axis=1)
combine = [train_df,test_df]

for dataset in combine:
    dataset['Age*Class'] = dataset.Age * dataset.Pclass
train_df.loc[:,['Age*Class','Age','Pclass']].head(10)

freq_port = train_df.Embarked.dropna().mode()[0]
freq_port

for dataset in combine:
    dataset['Embarked'] = dataset['Embarked'].fillna(freq_port)
train_df[['Embarked','Survived']].groupby(['Embarked'],
        as_index=False).mean().sort_values(by='Survived',ascending=False)

for dataset in combine:
    dataset['Embarked'] = dataset['Embarked'].map({'S': 0, 'C': 1, 'Q': 2}).astype(int)
train_df.head()

test_df['Fare'].fillna(test_df['Fare'].dropna().median(),inplace=True)
test_df.head()

train_df['FareBand'] = pd.cut(train_df['Fare'],4)
train_df[['FareBand','Survived']].groupby(['FareBand'],
        as_index=False).mean().sort_values(by='FareBand',ascending=False)

for dataset in combine:
    dataset.loc[ dataset['Fare'] <= 7.91, 'Fare'] = 0
    dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454),'Fare'] = 1
    dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31),'Fare'] = 2
    dataset.loc[(dataset['Fare'] > 31) ,'Fare'] = 3
    dataset['Fare'] = dataset['Fare'].astype(int)
train_df = train_df.drop(['FareBand'],axis=1)
combine = [train_df,test_df]
train_df.shape,test_df.shape

X_train = train_df.drop('Survived',axis=1)
Y_train = train_df['Survived']
X_test = test_df.drop('PassengerId',axis=1).copy()
X_train.shape,Y_train.shape,X_test.shape

from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression()
logreg.fit(X_train,Y_train)
Y_pred = logreg.predict(X_test)
acc_log = round(logreg.score(X_train,Y_train)*100,2)
acc_log

coeff_df = pd.DataFrame(train_df.columns.delete(0))
coeff_df.columns = ['Feature']
coeff_df['correlations'] = pd.Series(logreg.coef_[0])
coeff_df.sort_values(by='correlations',ascending=False)

from sklearn.svm import SVC
svc = SVC()
svc.fit(X_train,Y_train)
Y_pred = svc.predict(X_test)
acc_svc = round(svc.score(X_train,Y_train)*100,2)
acc_svc

from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors = 3)
knn.fit(X_train,Y_train)
Y_pred = knn.predict(X_test)
acc_knn = round(knn.score(X_train,Y_train)*100,2)
acc_knn

from sklearn.naive_bayes import GaussianNB
gaussian = GaussianNB()
gaussian.fit(X_train,Y_train)
Y_pred = gaussian.predict(X_test)
acc_gaussian = round(gaussian.score(X_train,Y_train)*100,2)
acc_gaussian

from sklearn.linear_model import Perceptron
perceptron = Perceptron()
perceptron.fit(X_train,Y_train)
Y_pred = perceptron.predict(X_test)
acc_perceptron = round(perceptron.score(X_train,Y_train)*100,2)
acc_perceptron

from sklearn.svm import LinearSVC
linear_svc = LinearSVC()
linear_svc.fit(X_train,Y_train)
Y_pred = linear_svc.predict(X_test)
acc_linear_svc = round(linear_svc.score(X_train,Y_train)*100,2)
acc_linear_svc

from sklearn.linear_model import SGDClassifier
sgd = SGDClassifier()
sgd.fit(X_train,Y_train)
Y_pred = sgd.predict(X_test)
acc_sgd = round(sgd.score(X_train,Y_train)*100,2)
acc_sgd

from sklearn.tree import DecisionTreeClassifier
decision_tree = DecisionTreeClassifier()
decision_tree.fit(X_train,Y_train)
Y_pred = decision_tree.predict(X_test)
acc_decision_tree = round(decision_tree.score(X_train,Y_train)*100,2)
acc_decision_tree

from sklearn.ensemble import RandomForestClassifier
random_forest = RandomForestClassifier(n_estimators=100)
random_forest.fit(X_train,Y_train)
Y_pred = random_forest.predict(X_test)
acc_random_forest = round(random_forest.score(X_train,Y_train)*100,2)
acc_random_forest

models = pd.DataFrame({
        'Model':['Support Vector Machines', 'KNN', 'Logistic Regression',
                 'Random Forest', 'Naive Bayes', 'Perceptron',
                 'Stochastic Gradient Decent', 'Linear SVC',
                 'Decision Tree'],
         'Score':[acc_svc, acc_knn, acc_log,
                  acc_random_forest, acc_gaussian, acc_perceptron,
                  acc_sgd, acc_linear_svc, acc_decision_tree]})
models.sort_values(by='Score',ascending=False)

from sklearn.model_selection import cross_val_score
accuracies = cross_val_score(estimator = decision_tree, X = X_train, y = Y_train, cv = 10)
meanda = accuracies.mean()
deviationda = accuracies.std()

from sklearn.metrics import make_scorer
from sklearn.model_selection import GridSearchCV
decision_tree = DecisionTreeClassifier()
from sklearn.metrics import f1_score, make_scorer

parameters = {'max_depth':[2,4,6,8,10],
              'min_samples_leaf':[2,4,6,8,10],
              'min_samples_split':[2,4,6,8,10]}

scorer = make_scorer(f1_score)

grid_obj = GridSearchCV(decision_tree,parameters,scoring=scorer)

grid_fit = grid_obj.fit(X_train,Y_train)

best_fit = grid_fit.best_estimator_

best_fit.fit(X_train,Y_train)

best_train_predictions = best_fit.predict(X_train)
best_test_predictions = best_fit.predict(X_test)

from sklearn.metrics import confusion_matrix
best_cn_train = confusion_matrix(Y_train,best_train_predictions)

best_f1score_train = f1_score(Y_train,best_train_predictions)

plot_model(X, y, best_clf)


from collections.abc import Iterable

from ... import opcodes
from ...core import OutputType
from ...serialization.serializables import AnyField
from ..operands import DataFrameOperandMixin, DataFrameOperand
from ..utils import parse_index

class GroupByIndex(DataFrameOperandMixin, DataFrameOperand):
    _op_type_ = opcodes.INDEX
    _op_module_ = "dataframe.groupby"

    _selection = AnyField("selection")

    def __init__(self, selection=None, output_types=None, **kw):
        super().__init__(_selection=selection, _output_types=output_types, **kw)

    @property
    def selection(self):
        return self._selection

    @property
    def groupby_params(self):
        params = self.inputs[0].op.groupby_params
        params["selection"] = self.selection
        return params

    def build_mock_groupby(self, **kwargs):
        groupby_op = self.inputs[0].op
        return groupby_op.build_mock_groupby(**kwargs)[self.selection]

    def __call__(self, groupby):
        indexed = groupby.op.build_mock_groupby()[self.selection]

        if indexed.ndim == 1:
            self.output_types = [OutputType.series_groupby]
            params = dict(
                shape=(groupby.shape[0],),
                name=self.selection,
                dtype=groupby.dtypes[self.selection],
                index_value=groupby.index_value,
                key_dtypes=groupby.key_dtypes,
            )
        else:
            self.output_types = [OutputType.dataframe_groupby]

            if isinstance(self.selection, Iterable) and not isinstance(
                self.selection, str
            ):
                item_list = list(self.selection)
            else:
                item_list = [self.selection]

            params = groupby.params.copy()
            params["dtypes"] = new_dtypes = groupby.dtypes[item_list]
            params["selection"] = self.selection
            params["shape"] = (groupby.shape[0], len(item_list))
            params["columns_value"] = parse_index(new_dtypes.index, store_data=True)

        return self.new_tileable([groupby], **params)

    @classmethod
    def tile(cls, op: "GroupByIndex"):
        in_groupby = op.inputs[0]
        out_groupby = op.outputs[0]

        chunks = []
        for c in in_groupby.chunks:
            if op.output_types[0] == OutputType.series_groupby:
                params = dict(
                    shape=(c.shape[0],),
                    name=op.selection,
                    index=(c.index[0],),
                    dtype=c.dtypes[op.selection],
                    index_value=c.index_value,
                    key_dtypes=c.key_dtypes,
                )
            else:
                params = c.params.copy()
                params["dtypes"] = out_groupby.dtypes
                params["selection"] = op.selection
                params["shape"] = (c.shape[0], len(op.selection))
                params["columns_value"] = out_groupby.columns_value

            new_op = op.copy().reset_key()
            chunks.append(new_op.new_chunk([c], **params))

        new_op = op.copy().reset_key()
        params = out_groupby.params.copy()
        new_nsplits = (
            (in_groupby.nsplits[0], (len(op.selection),))
            if out_groupby.ndim == 2
            else (in_groupby.nsplits[0],)
        )
        params.update(dict(chunks=chunks, nsplits=new_nsplits))
        return new_op.new_tileables([in_groupby], **params)

    @classmethod
    def execute(cls, ctx, op: "GroupByIndex"):
        in_data = ctx[op.inputs[0].key]
        ctx[op.outputs[0].key] = in_data[op.selection]

def df_groupby_getitem(df_groupby, item):
    try:
        hash(item)
        hashable = True
    except TypeError:
        hashable = False

    if hashable and item in df_groupby.dtypes:
        output_types = [OutputType.series_groupby]
    elif isinstance(item, Iterable) and all(it in df_groupby.dtypes for it in item):
        output_types = [OutputType.dataframe_groupby]
    else:
        raise NameError(f"Cannot slice groupby with {item!r}")

    if df_groupby.selection:
        raise IndexError(f"Column(s) {df_groupby.selection!r} already selected")

    op = GroupByIndex(selection=item, output_types=output_types)
    return op(df_groupby)


from __future__ import annotations

from typing import TYPE_CHECKING, Any, MutableMapping, cast

from cleo.exceptions import CleoValueError
from cleo.helpers import argument, option
from poetry.console.commands.command import Command
from poetry.core.version.exceptions import InvalidVersion
from poetry.core.version.pep440.segments import (
    RELEASE_PHASE_ID_ALPHA,
    RELEASE_PHASE_ID_BETA,
    RELEASE_PHASE_ID_DEV,
    RELEASE_PHASE_ID_RC,
    ReleaseTag,
)
from tomlkit.toml_document import TOMLDocument

if TYPE_CHECKING:
    from poetry.core.constraints.version import Version

class DevVersionCommand(Command):
    name = "dev-version"
    description = "Bumps version when a valid."

    arguments = [
        argument(
            "level",
            "The version level.",
            optional=False,
        ),
        argument(
            "build_number",
            "The version level.",
            optional=False,
        ),
    ]
    options = [
        option("short", "s", "Output the version number only"),
        option(
            "dry-run",
            None,
            "Do not update pyproject.toml file",
        ),
        option("local", None, "Add local string", flag=False),
    ]

    help = """\
The development version command bumps the version of
the project and writes the new development version
back to <comment>pyproject.toml</>.

The new development version should ideally be a valid
semver string or a valid bump rule:
rc, alpha, beta, dev.
"""

    RESERVED = {"rc", "alpha", "beta", "dev"}

    def handle(self) -> int:
        level: str = self.argument("level")

        if level not in self.RESERVED:
            raise CleoValueError(f"Unknown level: {level}")

        try:
            build_number: int = int(self.argument("build_number"))
        except ValueError:
            raise CleoValueError(f"Invalid build number: {self.argument('build_number')}")

        version = self.set_development_version(level=level, build_number=build_number, local=self.option("local"))

        if self.option("short"):
            self.line(version.to_string())
        else:
            self.line(
                "Bumping version from" f" <b>{self.poetry.package.pretty_version}</>" f" to <fg=green>{version}</>"
            )

        if not self.option("dry-run"):
            content: dict[str, Any] = self.poetry.file.read()
            poetry_content = cast(MutableMapping[str, MutableMapping[str, Any]], content["tool"])["poetry"]
            poetry_content["version"] = version.text

            assert isinstance(content, TOMLDocument)
            self.poetry.file.write(content)

        return 0

    def set_development_version(
        self,
        *,
        level: str,
        build_number: int,
        local: str | None = None,
        current_version: str | None = None,
    ) -> Version:
        from poetry.core.constraints.version import Version

        map = {
            "rc": RELEASE_PHASE_ID_RC,
            "alpha": RELEASE_PHASE_ID_ALPHA,
            "beta": RELEASE_PHASE_ID_BETA,
            "dev": RELEASE_PHASE_ID_DEV,
        }

        try:
            parsed = Version.parse(current_version or self.poetry.package.pretty_version)
        except InvalidVersion:
            raise ValueError("The project's version doesn't seem to follow semver")

        if level in {"rc", "alpha", "beta"}:
            new = parsed.replace(pre=ReleaseTag(map[level], build_number))
        else:
            new = parsed.replace(dev=ReleaseTag(map[level], build_number))

        if local:
            if "." in local:
                local_tuple: tuple[str | int, ...] = tuple(local.split(".", 1))

            else:
                local_tuple = (local,)
            new = new.replace(local=local_tuple)

        return new


import os
import json
import base64
import cloudscraper
import requests
scraper = cloudscraper.create_scraper()

website_name = "website.com"
Username = "username"
App_pass = "p29W j8qd I0hu pPWs HeNm L7ar"
category = "Your Category Name"
tags = "Tag Name"
status = "draft"  # publish

# Wordpress posting code-----------------
json_url = 'https://'+website_name + '/wp-json/wp/v2'
token = base64.standard_b64encode((Username + ':' + App_pass).encode('utf-8'))  # we have to encode the usr and pw
headers = {'Authorization': 'Basic ' + token.decode('utf-8')}

# Uploading Img for post body image
def image_operation(keyword):
  try:
    media = {'file': open('img/' + keyword + '.jpg', 'rb')}
    image = scraper.post(json_url + '/media', headers=headers, files=media)
    image_title = keyword.replace('-', ' ').split('.')[0]
    post_id = str(json.loads(image.content.decode('utf-8'))['id'])
    source = json.loads(image.content.decode('utf-8'))['guid']['rendered']
    image1 = ''
    image2 = '

'
    image3 = ''
    image_wp = image1 + image2 + image3
    return image_wp
  except:
    return ''

# Creating Tag
def create_tag(tag_name):
  id = 0
  data = {"name":tag_name}
  try:
    tag = requests.post(json_url + '/tags', headers=headers, json=data)
    id = str(json.loads(tag.content.decode('utf-8'))['id'])
  except KeyError:
    tag = requests.get(json_url + '/tags', headers=headers)
    tag_id = json.loads(tag.content.decode('utf-8'))
    for tag in tag_id:
      if tag_name.lower() == tag['name'].lower():
        id = str(tag['id'])
  return id

# Creating Category
def create_category(cat_name):
  id = 0
  data = {"name":cat_name}
  try:
    cat = requests.post(json_url + '/categories', headers=headers, json=data)
    id = str(json.loads(cat.content.decode('utf-8'))['id'])
  except KeyError:
    cat = requests.get(json_url + '/categories', headers=headers)
    cat_id = json.loads(cat.content.decode('utf-8'))
    for cat in cat_id:
      if cat_name.lower() == cat['name'].lower():
        id = str(cat['id'])
  return id

# Feature image
def feature_image(keyword):
  try:
      feature_image = image_operation(keyword)
      imgurl_raw = feature_image.split('id":')[1]
      img_id = imgurl_raw.split(',')[0]
      return int(img_id)
  except:
      return 0

# It will go under a Loop while keyword reading
title = 'keyword'
keyword = 'keyword'.replace(' ', '-')
post_body = 'post_body'
category_id = create_category('keyword')
tag_id = create_tag('keyword')
img_id = feature_image('keyword')

# Post Data
if tag_id != 0 and category_id == 0:
  post = {'title': title,'slug': slug,'status': status,'content': post_body,'tags': [tag_id],'format': 'standard'}
elif tag_id == 0 and category_id != 0:
  post = {'title': title,'slug': slug,'status': status,'content': post_body,'categories': [category_id],'format': 'standard'}
elif tag_id == 0 and category_id == 0:
  post = {'title': title,'slug': slug,'status': status,'content': post_body,'format': 'standard'}
else:
  post = {'title': title,'slug': slug,'status': status,'content': post_body,'categories': [category_id],'tags': [tag_id],'format': 'standard'}

# Posting Request
r = scraper.post(json_url + '/posts', headers=headers, json=post)
if r.status_code == 201:
  print('https://' + website_name + '/' + keyword.replace(' ', '-') + ' Has Been Posted')
else:
  print(r.status_code,'error')


import re
import ast
from setuptools import setup

_version_re = re.compile(r'__version__\s+=\s+(.*)')

with open('boomtime/__init__.py', 'rb') as f:
    version = str(ast.literal_eval(_version_re.search(
        f.read().decode('utf-8')).group(1)))

setup(
    name='boomtime',
    version=version,
    author='lemon24',
    url='https://github.com/lemon24/boomtime',
    packages=['boomtime'],
    install_requires=[
        'pytz',
        'python-dateutil>=2',
        'click>=5',
    ],
    description="",
    classifiers=[
        "License :: OSI Approved :: BSD License",
        "Programming Language :: Python",
        "Programming Language :: Python :: 3",
    ],
)


import os
from typing import Iterable, Iterator

from spectrum_utils.spectrum import MsmsSpectrum

from . import mzxml_io
from . import mgf_io
from . import mzml_io

def get_spectra(filename: str) -> Iterator[MsmsSpectrum]:
    """
    Get the MS/MS spectra from the given file.

    Supported file formats are MGF, MSP, mzML, mzXML.

    Parameters
    ----------
    filename : str
        The file name from which to read the spectra.

    Returns
    -------
    Iterator[MsmsSpectrum]
        An iterator over the spectra in the given file.
    """
    if not os.path.isfile(filename):
        raise ValueError(f'Non-existing peak file {filename}')

    _, ext = os.path.splitext(filename.lower())
    if ext == '.mgf':
        spectrum_io = mgf_io
    elif ext == '.mzml':
        spectrum_io = mzml_io
    elif ext == '.mzxml':
        spectrum_io = mzxml_io
    else:
        raise ValueError(f'Unknown spectrum file type with extension "{ext}"')

    for spec in spectrum_io.get_spectra(filename):
        spec.is_processed = False
        yield spec

def write_spectra(filename: str, spectra: Iterable[MsmsSpectrum]) -> None:
    """
    Write the given spectra to a peak file.

    Supported formats: MGF.

    Parameters
    ----------
    filename : str
        The file name where the spectra will be written.
    spectra : Iterable[MsmsSpectrum]
        The spectra to be written to the peak file.
    """
    ext = os.path.splitext(filename.lower())[1]
    if ext == '.mgf':
        spectrum_io = mgf_io
    else:
        raise ValueError('Unsupported peak file format (supported formats: '
                         'MGF)')

    spectrum_io.write_spectra(filename, spectra)


from math import radians, cos, sin, asin, sqrt
from queue import PriorityQueue

INF = 9999999
R = 100  # Range of LV lines

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance in kilometers between two points
    on the earth (specified in decimal degrees)
    """
    # convert decimal degrees to radians
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

    # haversine formula
    dlon = lon2 - lon1
    dlat = lat2 - lat1
    a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
    c = 2 * asin(sqrt(a))
    r = 6371  # Radius of earth in kilometers. Use 3956 for miles. Determines return value units.
    return c * r * 1000  # Returns in M

class Graph:
    def __init__(self, num_of_vertices):
        self.v = num_of_vertices
        self.edges = [
            [-1 for i in range(num_of_vertices)] for j in range(num_of_vertices)
        ]
        self.visited = []

    def add_edge(self, u, v, weight):
        self.edges[u][v] = weight
        self.edges[v][u] = weight

    def minKey(self, key, mstSet):
        # Initialize min value
        min = INF
        for ve in range(self.v):
            if key[ve] < min and mstSet[ve] is False:
                min = key[ve]
                min_index = ve

        return min_index

    def primMST(self):
        key = [INF] * self.v
        parent = [None] * self.v  # Array to store constructed MST
        # Make key 0 so that this vertex is picked as first vertex
        key[0] = 0
        mstSet = [False] * self.v

        parent[0] = -1  # First node is always the root of

        for cout in range(self.v):

            # Pick the minimum distance vertex from
            # the set of vertices not yet processed.
            # u is always equal to src in first iteration
            u = self.minKey(key, mstSet)

            # Put the minimum distance vertex in
            # the shortest path tree
            mstSet[u] = True

            # Update dist value of the adjacent vertices
            # of the picked vertex only if the current
            # distance is greater than new distance and
            # the vertex in not in the shortest path tree
            for ve in range(self.v):
                if (
                    self.edges[u][ve] > 0
                    and mstSet[ve] == False
                    and key[ve] > self.edges[u][ve]
                ):
                    key[ve] = self.edges[u][ve]
                    parent[ve] = u
        # For Returning
        lis = []
        for i in range(1, self.v):
            ele = [parent[i], i, self.edges[i][parent[i]]]
            lis.append(ele)
        return lis

def dijkstra(graph, start_vertex):
    D = {v: float("inf") for v in range(graph.v)}
    D[start_vertex] = 0

    pq = PriorityQueue()
    pq.put((0, start_vertex))

    while not pq.empty():
        (dist, current_vertex) = pq.get()
        graph.visited.append(current_vertex)

        for neighbor in range(graph.v):
            if graph.edges[current_vertex][neighbor] != -1:
                distance = graph.edges[current_vertex][neighbor]
                if neighbor not in graph.visited:
                    old_cost = D[neighbor]
                    new_cost = D[current_vertex] + distance
                    if new_cost < old_cost:
                        pq.put((new_cost, neighbor))
                        D[neighbor] = new_cost
    return D