def my_model(X,y,is_training):
    # setup variables
    Wconv1 = tf.get_variable("Wconv1", shape=[3, 3, 3, 64])
    bconv1 = tf.get_variable("bconv1", shape=[64])
    Wconv2 = tf.get_variable("Wconv2", shape=[5, 5, 64, 32])
    bconv2 = tf.get_variable("bconv2", shape=[32])
    W1 = tf.get_variable("W1", shape=[33600, 1024])
    b1 = tf.get_variable("b1", shape=[1024])
    W2 = tf.get_variable("W2", shape=[1024, 512])
    b2 = tf.get_variable("b2", shape=[512])
    W3 = tf.get_variable("W3", shape=[512, 128])
    b3 = tf.get_variable("b3", shape=[128])
    W4 = tf.get_variable("W4", shape=[128, 10])
    b4 = tf.get_variable("b4", shape=[10])

    # first conv layer (with relu and bn)
    a1 = tf.nn.conv2d(X, Wconv1, strides=[1,1,1,1], padding="VALID") + bconv1
    h1 = tf.nn.relu(a1)
    h2 = tf.contrib.layers.batch_norm(h1, center=True, scale=True, is_training=is_training, scope='bn')

    # second conv layer (with only relu)
    a11 = tf.nn.conv2d(h2, Wconv2, strides=[1,1,1,1], padding="VALID") + bconv2
    h11 = tf.nn.relu(a11)

    # pool layer
    h3 = tf.layers.max_pooling2d(inputs=h11, pool_size=[2, 2], strides=2)

    # three affine layers
    h3_flat = tf.reshape(h3,[-1,33600])
    h4 = tf.matmul(h3_flat,W1) + b1
    h5 = tf.nn.relu(h4)

    h5_flat = tf.reshape(h5,[-1,1024])
    h6 = tf.matmul(h5_flat,W2) + b2
    h7 = tf.nn.relu(h6)

    h7_flat = tf.reshape(h7,[-1,512])
    h8 = tf.matmul(h7_flat,W3) + b3
    h9 = tf.nn.relu(h8)

    # output layer (softmax)
    h9_flat = tf.reshape(h9,[-1,128])
    y_out = tf.matmul(h9_flat,W4) + b4

    return y_out


from textwrap import dedent
from unittest import mock

from django.contrib.auth.models import User
from django.test import TestCase
from django_dynamic_fixture import get

from readthedocs.config.tests.test_config import get_build_config
from readthedocs.doc_builder.environments import DockerBuildEnvironment
from readthedocs.projects.models import Project
from readthedocs.telemetry.collectors import BuildDataCollector

@mock.patch.object(BuildDataCollector, "run")
class TestBuildDataCollector(TestCase):
    def setUp(self):
        self.user = get(User)
        self.project = get(Project, slug="test", users=[self.user])
        self.version = self.project.versions.first()

        config = get_build_config({})
        config.validate()

        self.environment = DockerBuildEnvironment(
            version=self.version,
            project=self.project,
            build={"id": 1},
            config=config,
            api_client=mock.MagicMock(),
        )
        self.collector = BuildDataCollector(self.environment)

    def test_get_operating_system(self, run):
        run.return_value = (0, "Description:\tUbuntu 20.04.3 LTS", "")
        out = self.collector._get_operating_system()
        self.assertEqual(out, "Ubuntu 20.04.3 LTS")

    def test_get_python_version(self, run):
        run.return_value = (0, "Python 3.8.12", "")
        out = self.collector._get_python_version()
        self.assertEqual(out, "3.8.12")

    def test_get_all_conda_packages(self, run):
        out = dedent(
            """
            [
                {
                    "base_url": "https://conda.anaconda.org/conda-forge",
                    "build_number": 0,
                    "build_string": "py_0",
                    "channel": "conda-forge",
                    "dist_name": "alabaster-0.7.12-py_0",
                    "name": "alabaster",
                    "platform": "noarch",
                    "version": "0.7.12"
                },
                {
                    "base_url": "https://conda.anaconda.org/conda-forge",
                    "build_number": 0,
                    "build_string": "pyh9f0ad1d_0",
                    "channel": "conda-forge",
                    "dist_name": "asn1crypto-1.4.0-pyh9f0ad1d_0",
                    "name": "asn1crypto",
                    "platform": "noarch",
                    "version": "1.4.0"
                }
            ]
            """
        )
        run.return_value = (0, out, "")
        self.assertEqual(
            self.collector._get_all_conda_packages(),
            [
                {
                    "name": "alabaster",
                    "channel": "conda-forge",
                    "version": "0.7.12",
                },
                {
                    "name": "asn1crypto",
                    "channel": "conda-forge",
                    "version": "1.4.0",
                },
            ],
        )

    def test_get_user_pip_packages(self, run):
        self.collector.config = get_build_config(
            {"python": {"install": [{"requirements": "docs/requirements.txt"}]}}
        )
        self.collector.config.validate()
        out = dedent(
            """
            requests-mock==1.8.0
            requests-toolbelt==0.9.1
            rstcheck==3.3.1
            Sphinx>=5  # >= specs
            requests   # no specs
            """
        )
        run.return_value = (0, out, "")
        self.assertEqual(
            self.collector._get_user_pip_packages(),
            [
                {"name": "requests-mock", "version": "1.8.0"},
                {"name": "requests-toolbelt", "version": "0.9.1"},
                {"name": "rstcheck", "version": "3.3.1"},
                {"name": "sphinx", "version": "unknown"},  # >= specs
                {"name": "requests", "version": "undefined"},  # no specs
            ],
        )

    def test_get_all_pip_packages(self, run):
        out = dedent(
            """
            [
                {
                    "name": "requests-mock",
                    "version": "1.8.0"
                },
                {
                    "name": "requests-toolbelt",
                    "version": "0.9.1"
                },
                {
                    "name": "rstcheck",
                    "version": "3.3.1"
                }
            ]
            """
        )
        run.return_value = (0, out, "")
        self.assertEqual(
            self.collector._get_all_pip_packages(),
            [
                {"name": "requests-mock", "version": "1.8.0"},
                {"name": "requests-toolbelt", "version": "0.9.1"},
                {"name": "rstcheck", "version": "3.3.1"},
            ],
        )

    def test_get_all_apt_packages(self, run):
        out = dedent(
            """
            apt 1.6.14
            base-files 10.1ubuntu2.11
            base-passwd 3.5.44
            bash 4.4.18-2ubuntu1.2
            bsdutils 1:2.31.1-0.4ubuntu3.7
            coreutils 8.28-1ubuntu1
            """
        )
        run.return_value = (0, out, "")
        self.assertEqual(
            self.collector._get_all_apt_packages(),
            [
                {
                    "name": "apt",
                    "version": "1.6.14",
                },
                {
                    "name": "base-files",
                    "version": "10.1ubuntu2.11",
                },
                {
                    "name": "base-passwd",
                    "version": "3.5.44",
                },
                {
                    "name": "bash",
                    "version": "4.4.18-2ubuntu1.2",
                },
                {
                    "name": "bsdutils",
                    "version": "1:2.31.1-0.4ubuntu3.7",
                },
                {
                    "name": "coreutils",
                    "version": "8.28-1ubuntu1",
                },
            ],
        )

    def test_get_user_apt_packages(self, run):
        self.collector.config = get_build_config(
            {
                "build": {
                    "os": "ubuntu-22.04",
                    "tools": {
                        "python": "3",
                    },
                    "apt_packages": ["cmake", "libclang"],
                }
            }
        )
        self.collector.config.validate()
        self.assertEqual(
            self.collector._get_user_apt_packages(),
            [
                {
                    "name": "cmake",
                    "version": "",
                },
                {"name": "libclang", "version": ""},
            ],
        )


import sys
import cv2
import math
from skimage import draw
import numpy as np
from typing import List
from pathlib import Path
import logging
import argparse

def alpha_blur(img, alpha_mask, kernel_size=10):
    """
    Blur image proportional to the given mask
    :param img:
    :param alpha_mask:
    :param kernel_size:
    :return:
    """
    # apply morphology open to smooth the outline
    # kernel_size = max(2, (10 // (i + 1)))
    # kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (kernel_size, kernel_size))
    # blurred_img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
    # kernel_size = max(20, (150 // (i + 1)))

    #blurred_img = cv2.bilateralFilter(img, 9, 5, 5)
    blurred_img = cv2.GaussianBlur(img, (21, 21), 11)

    if alpha_mask is not None:
        if alpha_mask.ndim == 3 and alpha_mask.shape[-1] == 3:
            alpha = alpha_mask / 255.0
        else:
            alpha = cv2.cvtColor(alpha_mask, cv2.COLOR_GRAY2BGR) / 255.0
        blurred_img = cv2.convertScaleAbs(blurred_img * (1 - alpha) + img * alpha)

    return blurred_img

def positive_sharpen(i, overblur=False, coeff=8.):
    # emphasize the edges
    blurred = cv2.blur(i,(5,5))
    sharpened = i + (i - blurred) * coeff
    if overblur:
        return cv2.blur(np.maximum(sharpened,i),(11,11))
    return cv2.blur(np.maximum(sharpened,i),(3,3))

def sample_color(img, x, y, neighbor_size):
    # sample color from image => converges faster.
    color = img[max(0, y - neighbor_size):y + neighbor_size,
               max(0, x - neighbor_size):x + neighbor_size].mean(axis=(0,1))

    return color

def get_phase_and_magnitude(img, sobel_kernel_size=7, magnitude_power=0.3):
    """
    Calculate phase/rotation angle from image gradient
    :param img: image to compute phase from
    :param sobel_kernel_size:
    :return: phase in float32 radian
    """
    # grayify
    img_gray = img.astype('float32') #cv2.cvtColor(img, cv2.COLOR_BGR2GRAY).astype('float32')

    # gradient (along x and y axis)
    xg = cv2.Sobel(img_gray, cv2.CV_32F, 1, 0, ksize=sobel_kernel_size)
    yg = - cv2.Sobel(img_gray, cv2.CV_32F, 0, 1, ksize=sobel_kernel_size)

    # calculates the rotation angle of the 2D vectors gradients
    phase = cv2.phase(xg, yg)

    # calculates the magnitude of the 2D vectors gradients
    magnitude = cv2.magnitude(xg, yg)
    magnitude = magnitude / magnitude.max()  # normalize to [0, 1] range

    # make magnitude more uniform
    magnitude = np.power(magnitude, magnitude_power)

    return phase, magnitude

def get_point_angle_and_magnitude(x, y, phase_map, magnitude_map,
                                  phase_neighbor_size: int, magnitude_neighbor_size: int):
    # get gradient orientation info from phase map (phase should be between [0,2pi))
    # compute an average phase around the point, for an area proportional to brush size
    phase = phase_map[max(0, y - phase_neighbor_size):y + phase_neighbor_size,
            max(0, x - phase_neighbor_size):x + phase_neighbor_size].mean()
    # choose direction perpendicular to gradient
    angle = (((phase / math.pi) * 180) + 90) % 360

    magnitude = magnitude_map[max(0, y - magnitude_neighbor_size):y + magnitude_neighbor_size,
                max(0, x - magnitude_neighbor_size):x + magnitude_neighbor_size].mean()

    return angle, magnitude

def get_edges(img, img_blur_size=5, min_hyst_val=100, max_hyst_val=200, edges_blur_size=5):
    """
    Detect image edges
    :param img:
    :param img_blur_size: kernel for gaussian-blur on image
    :param min_hyst_val: hysteresis min threshold (canny edge detection)
    :param max_hyst_val: hysteresis max threshold (canny edge detection)
    :param edges_blur_size: blur size applied to edge results
    :return: norm blurred edges and uint8 original edges images
    """
    # remove noise to improve edge detection results
    blurred_img = cv2.GaussianBlur(img, (img_blur_size, img_blur_size), 0)

    # canny edge detection
    edges = cv2.Canny((blurred_img * 255).astype('uint8'), min_hyst_val, max_hyst_val)

    # blur edges
    blurred_edges = cv2.blur(edges, (edges_blur_size, edges_blur_size)).astype('float32') / 255

    norm_edges = blurred_edges / blurred_edges.sum()  # normalize to probabilities

    return norm_edges, edges

def get_distance_map(src_img):
    """
    Get distance values for given image. Distance is the closest zero pixel for each pixel of the source image.
    :param src_img: grayscale image
    :return: distance map
    """
    # use simple euclidean distance and a 3×3 mask for a fast, coarse distance estimation
    dist = cv2.distanceTransform(255 - src_img, cv2.DIST_L2, 3)

    # normalize distance image between 0.0 and 1.0
    cv2.normalize(dist, dist, 0, 1.0, cv2.NORM_MINMAX)

    return dist

def get_min_radius_to_edge(dist_img, start_pos, end_pos, dist_threshold=0.01):
    # get lines coordinates
    line = np.transpose(np.array(draw.line(start_pos[0], start_pos[1], end_pos[0], end_pos[1])))
    line = np.array([[x, y] for [x, y] in line if (0 <= x < dist_img.shape[1] and 0<= y < dist_img.shape[0])])
    # get dist values overlapping the line
    data = dist_img[line[:, 1], line[:, 0]]

    # find first index below threshold
    radius = np.argmax(data < dist_threshold)

    return radius

def add_border_to_img(img, border_size: int):
    border_img = cv2.copyMakeBorder(img, border_size, border_size, border_size, border_size, cv2.BORDER_CONSTANT,
                                    value=[255] * 3)
    border_img = border_img.astype('float32') / 255  # convert to float32

    img = cv2.copyMakeBorder(img, border_size // 2, border_size // 2, border_size // 2, border_size // 2,
                             cv2.BORDER_CONSTANT, value=[255] * 3)
    img = cv2.resize(img, border_img.shape[:2][::-1])
    img = img.astype('float32') / 255  # convert to float32

    return img, border_img

def combine_salience_images(input_dir: Path, salience_paths: List[Path], weights: List[float], output_dir: Path):
    main_imgs = list(input_dir.glob('*.png')) + list(input_dir.glob('*.jpg'))

    output_dir.mkdir(exist_ok=True, parents=True)

    # for each image in out target input folder, compute composed salience image
    for img_path in main_imgs:
        main_img = cv2.imread(str(img_path), cv2.IMREAD_GRAYSCALE).astype('float32') / 255
        composed_salience_img = np.zeros(main_img.shape, dtype='float32')

        salience_img_name = img_path.stem
        for i, salience_path in enumerate(salience_paths):
            salience_img_ext = None
            for ext in ['.jpg', '.png']:
                if (salience_path / (salience_img_name + ext)).exists():
                    salience_img_ext = ext
                    break
            if salience_img_ext is None:
                continue

            salience_img_path = str(salience_path / (salience_img_name + ext))
            salience_img = cv2.imread(str(salience_img_path), cv2.IMREAD_GRAYSCALE)
            salience_img = salience_img.astype('float32') / 255  # convert to float32
            salience_img = salience_img.clip(0.)
            composed_salience_img = composed_salience_img + (weights[i] * salience_img)

        composed_salience_img = composed_salience_img / composed_salience_img.max()

        cv2.imwrite(str(output_dir / f'{salience_img_name}.png'), composed_salience_img * 255)

def main(_=None):
    logging.getLogger().setLevel(logging.INFO)

    parser = argparse.ArgumentParser(description='Image Utils')

    parser.add_argument('-i', '--input-path', required=True)
    parser.add_argument('-o', '--output-path', required=True)
    parser.add_argument('-s', '--salience-paths', type=str, nargs='+',)

    args = parser.parse_args()
    input_path = Path(args.input_path)
    output_path = Path(args.output_path)
    salience_paths = [Path(p) for p in args.salience_paths]
    weights = [1. for p in salience_paths]

    combine_salience_images(input_path, salience_paths=salience_paths, weights=weights, output_dir=output_path)

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


import numpy as np
import pandas as pd
import math
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA

data = pd.read_csv('../data/result.csv')
feature_names = ['vendor_id','passenger_count','pickup_longitude',
                'pickup_latitude','dropoff_longitude','dropoff_latitude',
                'trip_duration','total_distance','total_travel_time',
                'number_of_steps','pick_month','hour','week_of_year','day_of_year',
                'day_of_week','hvsine_pick_drop','manhtn_pick_drop','bearing',
                'pickup_pca0','pickup_pca1','dropoff_pca0','dropoff_pca1',
                'havsine_pick_drop','speed_hvsn','speed_manhtn','label_pick','label_drop',
                'centroid_pick_long','centroid_pick_lat','centroid_drop_long',
                'centroid_drop_lat','hvsine_pick_cent_p','hvsine_drop_cent_d',
                'hvsine_cent_p_cent_d','manhtn_pick_cent_p','manhtn_drop_cent_d',
                'manhtn_cent_p_cent_d','bearing_pick_cent_p','bearing_drop_cent_p',
                'bearing_cent_p_cent_d']

y = np.log(data['trip_duration'].values + 1)
Xtr, Xv, ytr, yv = train_test_split(data[feature_names].values, y, test_size = 0.2, random_state = 1987)
dtrain = xgb.DMatrix(Xtr, label = ytr)
dvalid = xgb.DMatrix(Xv, label = yv)
dtest = xgb.DMatrix(data[feature_names].values)
watchlist = [(dtrain, 'train'), (dvalid, 'valid')]

xgb_pars = {'min_child_weight':50, 'eta':0.3, 'colsample_bytree': 0.3, 'max_depth':10,
            'subsample':0.8, 'lamba': 1, 'ntherad':-1, 'booster': 'gbtree', 'silent':1,
            'eval_metric':'rmse', 'objective':'reg:linear'}
model = xgb.train(xgb_pars, dtrain, 15, watchlist, early_stopping_rounds = 2, maximize = False, verbose_eval = 1)
print('Modeling RMSLE %.5f' % model.best_score)


import numpy as np
import opt_einsum as oe
import torch

from .antenna_arrays import UniformLinearArray
from .ofdmchannel import MultiPathChannelConfig, OFDMBeamSpaceChannel, OFDMConfig
from .prepare_sim import get_prior_cov, get_scale_matrix_J
from .utils import db2lin, herm

def fim_c_xi(
    mpc_configs: MultiPathChannelConfig,
    ofdm_configs: OFDMConfig,
    tx_array: UniformLinearArray,
    rx_array: UniformLinearArray,
    w: torch.Tensor,
    channel_mat: torch.Tensor,
    sig2_noise: float = 1,
    wavelength: float = 1,
) -> tuple[torch.Tensor, torch.Tensor]:
    num_ant_rx, num_ant_tx, num_carriers, num_symbols = channel_mat.shape
    assert (num_ant_rx == rx_array.num_antennas) and (num_ant_tx == tx_array.num_antennas)
    if not isinstance(sig2_noise, torch.Tensor):
        sig2_noise = torch.ones((num_carriers, num_symbols), dtype=torch.complex128) * sig2_noise
    assert sig2_noise.shape == (num_carriers, num_symbols)

    At = torch.from_numpy(tx_array.steering_matrix(grid=mpc_configs.aods, wavelength=wavelength, axis=1)).clone()
    Dt = torch.from_numpy(tx_array.steering_mat_der(grid=mpc_configs.aods, wavelength=wavelength, axis=1)).clone()

    Ar = torch.from_numpy(rx_array.steering_matrix(grid=mpc_configs.aoas, wavelength=wavelength, axis=1)).clone()
    Dr = torch.from_numpy(rx_array.steering_mat_der(grid=mpc_configs.aoas, wavelength=wavelength, axis=1)).clone()

    At = At.conj()
    Dt = Dt.conj()

    tgrid, fgrid = torch.meshgrid(
        torch.arange(num_symbols) * ofdm_configs.symbol_time,
        torch.arange(num_carriers) * ofdm_configs.subcarrier_spacing,
        indexing="xy",
    )
    tgrid_ = oe.contract("nk,l->nkl", tgrid, torch.as_tensor(mpc_configs.doppler_shifts))
    fgrid_ = oe.contract("nk,l->nkl", fgrid, torch.as_tensor(mpc_configs.path_delays))
    Omega_nk = torch.exp(1j * 2 * torch.pi * (tgrid_ - fgrid_))
    G_nk = oe.contract("...nk,...nkl->...nkl", -1j * 2 * torch.pi * fgrid, Omega_nk)
    F_nk = oe.contract("...nk,...nkl->...nkl", 1j * 2 * torch.pi * tgrid, Omega_nk)
    path_gains = torch.as_tensor(mpc_configs.path_gains)

    C_x = w @ herm(w)

    BG_nk = oe.contract("nkl, l -> nkl", G_nk, path_gains)
    BF_nk = oe.contract("nkl, l -> nkl", F_nk, path_gains)
    BO_nk = oe.contract("nkl, l -> nkl", Omega_nk, path_gains)

    Lambda_nk = torch.concat((Omega_nk, 1j * Omega_nk, BG_nk, BF_nk, BO_nk, BO_nk), dim=-1)

    T = torch.concat((At, At, At, At, At, Dt), dim=1)
    R = torch.concat((Ar, Ar, Ar, Ar, Dr, Ar), dim=1)

    term1 = oe.contract(
        "nk, nkl, lt, ti, ij, nkj -> lj",
        2 / sig2_noise,
        Lambda_nk.conj(),
        herm(T),
        C_x.conj(),
        T,
        Lambda_nk,
    )
    term2 = herm(R) @ R
    fim_mat = torch.mul(term1, term2).real

    return fim_mat

def fim_c_s(w, HH, sig2_noise):
    nt, ns = w.shape
    M = np.prod(HH.shape[2:])
    wHHw = oe.contract("rm, rtnk, ts -> msnk", w.conj(), HH, w).reshape(ns, ns, -1)
    fim_complex = wHHw.permute(2, 0, 1) / sig2_noise * 2
    fim_real = torch.zeros((M, 2 * ns, 2 * ns))
    for i in range(M):
        temp = fim_complex[i]
        fim_real[i, :ns, :ns] = temp.real
        fim_real[i, :ns, ns:] = (1j * temp).real
        fim_real[i, ns:, :ns] = (-1j * temp).real
        fim_real[i, ns:, ns:] = temp.real

    return fim_complex, fim_real

def fim_p(C_xi, C_s):
    Gamma = torch.linalg.inv(C_xi)
    I_s = torch.linalg.inv(C_s)
    return Gamma, I_s

def obj_bfim(X, params_list, mpc_configs, cfg):
    ofdm_configs = OFDMConfig(
        subcarrier_spacing=cfg.subcarrier_spacing,
        num_guard_carriers=(0, 0),
        Nfft=cfg.num_carriers,
    )

    snrlin = db2lin(cfg.snrdb)
    power_noise = cfg.power_signal / snrlin
    noise_sigma2 = power_noise

    tx_array = UniformLinearArray(num_antennas=cfg.num_ant_tx)
    rx_array = UniformLinearArray(num_antennas=cfg.num_ant_rx)

    w = X * np.sqrt(cfg.power_signal)
    expec_HH = 0
    expec_fimc_xi = 0

    new_br, new_bi, new_tau, new_fD, new_aoas, new_aods = params_list
    new_tau = abs(new_tau)  # if sampled delay is negative, make it positive
    num_samples = len(new_br)
    new_b = new_br + 1j * new_bi

    scale_matrix_J = get_scale_matrix_J(cfg)

    for i in range(num_samples):
        newmpc = MultiPathChannelConfig(
            path_gains=new_b[i].numpy(),
            path_delays=new_tau[i].numpy(),
            doppler_shifts=new_fD[i].numpy(),
            aoas=new_aoas[i].numpy(),
            aods=new_aods[i].numpy(),
        )
        ofdmbschann = OFDMBeamSpaceChannel(
            mpc_configs=newmpc,
            ofdm_config=ofdm_configs,
            tx_array=tx_array,
            rx_array=rx_array,
        )
        Hf = ofdmbschann.get_channel(num_carriers=cfg.num_carriers, num_symbols=cfg.num_symbols)
        Hf_tensor = torch.from_numpy(Hf).clone()
        Hf_tensor = torch.fft.ifftshift(Hf_tensor, dim=-2)
        expec_HH = expec_HH + torch.einsum("rt..., rm... -> tm...", Hf_tensor.conj(), Hf_tensor)

        fimc_xi = fim_c_xi(
            mpc_configs=newmpc,
            ofdm_configs=ofdm_configs,
            tx_array=tx_array,
            rx_array=rx_array,
            w=w,
            channel_mat=Hf_tensor,
            sig2_noise=noise_sigma2,
        )
        expec_fimc_xi = expec_fimc_xi + fimc_xi

    if not num_samples:
        ofdmbschann = OFDMBeamSpaceChannel(
            mpc_configs=mpc_configs,
            ofdm_config=ofdm_configs,
            tx_array=tx_array,
            rx_array=rx_array,
        )
        Hf = ofdmbschann.get_channel(num_carriers=cfg.num_carriers, num_symbols=cfg.num_symbols)
        Hf_tensor = torch.from_numpy(Hf).clone()
        Hf_tensor = torch.fft.ifftshift(Hf_tensor, dim=-2)
        expec_HH = torch.einsum("rt..., rm... -> tm...", Hf_tensor.conj(), Hf_tensor)
        fimc_xi = fim_c_xi(
            mpc_configs=mpc_configs,
            ofdm_configs=ofdm_configs,
            tx_array=tx_array,
            rx_array=rx_array,
            w=w,
            channel_mat=Hf_tensor,
            sig2_noise=noise_sigma2,
        )
        expec_fimc_xi = fimc_xi
        num_samples = 1

    C_xi, C_s = get_prior_cov(cfg)
    Gamma, I_s = fim_p(C_xi, C_s)
    expec_fim_xi = expec_fimc_xi / num_samples + Gamma
    expec_HH = expec_HH / num_samples
    fim_complex, fim_real = fim_c_s(w, expec_HH, noise_sigma2)

    num_re = cfg.num_carriers * cfg.num_symbols
    term1 = torch.logdet(herm(scale_matrix_J) @ expec_fim_xi @ scale_matrix_J)
    term2 = torch.linalg.slogdet(fim_complex + I_s)[1].real.sum() * 2
    return term1, term2, (cfg.multi_obj_factor * term1 + (1 - cfg.multi_obj_factor) / num_re * term2)


import sys
from dust.extensions.multiplex.lite_multiplex_socket import *
from dust.core.util import getPublicIP
from dust.crypto.keys import KeyManager

ipv=sys.argv[1]
if ipv=='4':
  v6=False
else:
  v6=True
inport=int(sys.argv[2])
outport=int(sys.argv[3])

host=getPublicIP(v6)
dest=host

keys=KeyManager()

msock=lite_multiplex_socket(keys)
msock.bind((host, inport))
msock.connect((dest, outport))
msock.connectToService('chat')

msg=''
while msg!='.':
  print('>> ', end='')
  msg=sys.stdin.readline().strip()
  msock.msend(msg.encode('ascii'))


"""
Misc functions
Creation of colors and directories

"""
# misc
import os.path
from matplotlib.colors import LinearSegmentedColormap

# define colors and colormaps
mblue = (0.098,0.18,0.357)
mred = (0.902,0.4157,0.0196)
mgreen = (0.,0.455,0.247)
mpurple = (0.5804,0.2157,0.9412)
mgray = (0.5012,0.5012,0.5012)
myellow = (0.8,0.8,0)
mwhite = (1.,1.,1.)
cmap = LinearSegmentedColormap.from_list('beamer_cmap', [mwhite, mred])
colors = [mblue, mred, mgreen, myellow, mpurple, mgray]
rainbow = ['magenta', 'darkviolet', 'darkblue', 'blue', \
            'deepskyblue', 'cyan', 'springgreen', 'greenyellow', \
            'gold', 'orange', 'red', 'maroon']

# define directory function
def directory(file):
    if os.path.exists(file):
        return
    else:
        os.mkdir(file)
    return


import sys
from PyQt4 import QtCore, QtGui

from simpleViewerGUI import Ui_MainWindow

import psio

import json

class MyForm(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        openfile = QtGui.QAction(QtGui.QIcon('open.png'), 'Open', self)
        openfile.setShortcut('Ctrl+O')
        openfile.setStatusTip('Open new File')
        openfile.triggered.connect(self.showDialog)

        self.ui.uvw.addAction(openfile)

    def showDialog(self):

        fname = str(QtGui.QFileDialog.getOpenFileName(self, 'Open file',
                '.'))

        if (fname == ''):
            return
        io = psio.dataHandler.DataHandler()
        io.create_reader(fname)
        #self.head = io.getHeader()
        #info = json.dumps(self.head)
        #self.ui.xyz.setText(info)

        self.nda = None
        for d in io:
            self.nda = d
            self.ui.displaypart.setImage(self.nda)

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = MyForm()
    myapp.show()
    sys.exit(app.exec_())


#coding=utf-8
from ast import IsNot
from types import NoneType
from bs4 import BeautifulSoup
from selenium import webdriver
import time
import re
import unicodedata
from csv import DictWriter
import os
import requests
import traceback
options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors')   #主要是该条
options.add_argument('--ignore-ssl-errors')
chromeOptions = webdriver.ChromeOptions()
class DoubanParser:
    driver = webdriver.Chrome()
    records = []
    records_error = []
    def get_proxy(Any):
        return requests.get("http://127.0.0.1:5010/get/").json()

    def delete_proxy(proxy,Any):
        requests.get("http://127.0.0.1:5010/delete/?proxy={}".format(proxy))

# your spider code

    def getHtml(self,url):
    # ....
        retry_count = 5
        proxy = self.get_proxy().get("proxy")
        chromeOptions.add_argument("--proxy-server=http://"+proxy)
        browser = webdriver.Chrome(chrome_options = chromeOptions)
        while retry_count > 0:
            try:
                self.driver.get(url)
                # 使用代理访问
                html = self.driver.page_source
                return html
            except Exception:
                retry_count -= 1
        # 删除代理池中代理
        self.delete_proxy(proxy)
        return None

    def parse(self,page_url):
        try:
            html = self.getHtml(page_url)
            while(html == None):
                html = self.getHtml(page_url)
            page_soup = BeautifulSoup(html,features='lxml')
            movie_titles = page_soup.find('div',{'id':'wrapper'})
            title = movie_titles.h1.span.string##title : #wrapper > h1 > span

            book_rating = page_soup.find('div',{'class':'rating_self clearfix'})##interest_sectl > div > div.rating_self.clearfix > strong
            rating =  book_rating.strong.get_text();

            author = page_soup.find('div',{'id':'info'}).select('span')[0].a##info > span:nth-child(1) > a
            book_summary = page_soup.find('div',{'id':'link-report'})
            summary = ""
            if book_summary.find('span',{'class':'all hidden'}) is not None:
                for string in book_summary.find('span',{'class':'all hidden'}).stripped_strings:
                    summary += string #link-report > span.all.hidden > div > div > p
            elif book_summary.find('span',{'class':'short'}) is not None:
                 #link-report > span.short > div > p:nth-child(1)
                for string in book_summary.find('span',{'class':'short'}).stripped_strings:
                    summary += string;
            else:
                #link-report > div > div > p
                for string in book_summary.stripped_strings:
                    summary += string
            #link-report > div > div > p:nth-child(1)
            #summary = ''.join(summary.split())##剔除空格与换行符
            #summary = summary.replace([' ','\n','\u3000'],'')
            author_summary=""
            preauthor = page_soup.find('div',{'class':'related_info'})
            q = preauthor.select('div')[4]
            if preauthor.select('div')[4].find('span',{'class':'all hidden'}) is not None:
                for string in preauthor.select('div')[4].find('span',{'class':'all hidden'}).stripped_strings:
                    author_summary += string#content > div > div.article > div.related_info > div:nth-child(5) > span.all.hidden > div > p
            elif preauthor.select('div')[4].find('span',{'class':'short'}) is not None:
                #content > div > div.article > div.related_info > div:nth-child(5) > span.short > div > p
                for string in  preauthor.select('div')[4].find('span',{'class':'short'}).stripped_strings:
                    author_summary += string
            else:
                #content > div > div.article > div.related_info > div:nth-child(5) > div > div > p:nth-child(1)
                for string in preauthor.select('div')[4].stripped_strings:
                    author_summary += string
            movie_dict = {'book':title,'rating':rating,'link':page_url,'book summary':summary,'author summary':author_summary}##content > div > div.article > div.related_info > div:nth-child(5) > div > div > p
            self.records.append(movie_dict)
        except:
            print(traceback.format_exc())
            #movie_dict = {'book':"ERROR",'rating':"ERROR",'link':page_url,'book summary':traceback.format_exc(),'author summary':"ERROR"}
            #self.records_error.append(movie_dict)
    def read_txt(self):
        num = 1
        f = open("D:/360MoveData/Users/admin/Desktop/coursework/web_info/lab/lab1/Book_id.txt")
        byt = f.readlines()
        for line in byt:
            url = "https://book.douban.com/subject/"+line
            self.parse(url)
            print(num,"has been resolved")
            num =num + 1
        '''url = "https://book.douban.com/subject/1400707"'''
        self.parse(url)
        if os.path.exists("douban_book.csv"):
            os.remove("douban_book.csv")
        with open('douban_book.csv','w', newline='', encoding='utf-8-sig') as file:
            headers = [key for key in self.records[0].keys()]
            csv_writer = DictWriter(file, fieldnames=headers)
            csv_writer.writeheader()
            for record in self.records:
                csv_writer.writerow(record)
        if self.records_error != []:
            with open('douban_book_ERROR.csv','w', newline='', encoding='utf-8-sig') as file:
                headers = [key for key in self.records_error[0].keys()]
                csv_writer = DictWriter(file, fieldnames=headers)
                csv_writer.writeheader()
                for record in self.records_error:
                    csv_writer.writerow(record)

parser=DoubanParser()
parser.read_txt()


import matplotlib.pyplot as plt
from matplotlib import rc
from matplotlib.ticker import ScalarFormatter

dpi = 100
tick_size = 20
label_size = 24
line_width = 3
title_size = 15

def plot_distances_graph(timestamps, min_distances, radiations, title=""):
    # unified plotting settings

    rc('font', **{'family': 'serif', 'serif': ['Palatino']})
    plt.rc('text', usetex=True)
    fig = plt.figure(figsize=(8, 6), dpi=dpi)
    ax = fig.add_subplot(111)

    timestamps = [float(timestamp) - float(min(timestamps))
                  for timestamp in timestamps]

    for idx, source in enumerate(radiations):
        label = f"Source {idx + 1} [{', '.join([f'{coord:.1f}' for coord in source])}]"
        ax.plot(timestamps, min_distances[idx], linewidth=line_width, label=label)

    ax.legend(loc='best', fontsize=tick_size)
    ax.set_xlabel(r"Time [s]", fontsize=label_size)
    ax.set_ylabel(r"Minimum distance [m]", fontsize=label_size)
    ax.tick_params(labelsize=tick_size)
    plt.tick_params(labelsize=tick_size)

    ax.grid(which="major")
 # Set y-axis scale to logarithmic
    ax.set_yscale('log')   # set y-axis scale to logarithmic
    ax.set_yticks([0.1,1.0,10])
   # plt.ylim(1, 16,1)
    ax.yaxis.set_major_formatter(ScalarFormatter())
    ax.get_yaxis().get_major_formatter().labelOnlyBase = False

    #ax.ticklabel_format(axis='y', style='sci', scilimits=(0, 0))
    #plt.title(title, fontsize=title_size)
    plt.tight_layout()
    plt.show(block=False)

# Commented out unused code
    # ax.yaxis.set_major_formatter(plt.ScalarFormatter(useMathText=True))
    # set x-axis ticks at every 11th timestamp
    # n_ticks = 11
    # tick_indices = np.linspace(0, len(timestamps) - 1, n_ticks).astype(int)
    # tick_labels = [f"{float(timestamps[i]):.0f}" for i in tick_indices]
    # ax.set_xticks([timestamps[i] for i in tick_indices])
   # ax.set_xticklabels(tick_labels, rotation=45)

def plot_points_graph(timestamps, estimations, title=""):

    # use latex text renderer
    # count the number of points for each timestamp
    point_counts = [len(points) for points in estimations]

    # create a list of x-values and y-values for each edge
    x_edges = [float(timestamps[0])]
    y_edges = [0]
    for i in range(len(timestamps)-1):
        x_edges.append(float(timestamps[i]))
        x_edges.append(float(timestamps[i+1]))
        y_edges.append(point_counts[i])
        y_edges.append(point_counts[i])
    x_edges.append(float(timestamps[-1]))
    y_edges.append(point_counts[-1])
    x_edges.append(float(timestamps[-1]))
    y_edges.append(0)

    # use latex text renderer
    rc('font', **{'family': 'serif', 'serif': ['Palatino']})
    plt.rc('text', usetex=True)

    fig = plt.figure(figsize=(8, 6), dpi=dpi)
    ax = fig.add_subplot(111)
    ax.plot(x_edges, y_edges, linewidth=line_width)
    ax.fill_between(x_edges, y_edges, color='lightblue')
    ax.set_xlabel("Time [s]", fontsize=label_size)
    ax.set_ylabel("Estimated number of sources", fontsize=label_size)
    ax.tick_params(labelsize=tick_size)
    plt.tick_params(labelsize=tick_size)
    ax.grid(which='major')
    plt.tight_layout()
    #plt.title(title, fontsize=title_size)

    # n_ticks = 11
    # tick_indices = np.linspace(0, len(timestamps) - 1, n_ticks).astype(int)
    # tick_labels = [f"{float(timestamps[i]):.1f}" for i in tick_indices]
    # ax.set_xticks([timestamps[i] for i in tick_indices])
    # ax.set_xticklabels(tick_labels, rotation=45)
    plt.show()


import time
import traceback
import sharedfunc
from dbClass import dbCalls
from dbPGClass import dbPGCalls
from tnClass import tnCalls
from otherClass import otherCalls
from verification import verifier

class OtherChecker(object):
    def __init__(self, config, db = None):
        self.config = config

        if db == None:
            if self.config['main']['use-pg']:
                self.db = dbPGCalls(config)
            else:
                self.db = dbCalls(config)
        else:
            self.db = db

        self.tnc = tnCalls(config, self.db)
        self.verifier = verifier(config, self.db)
        self.otc = otherCalls(config, self.db)

        self.lastScannedBlock = self.db.lastScannedBlock("Other")

    def run(self):
        #main routine to run continuesly
        #print('INFO: started checking Other blocks at: ' + str(self.lastScannedBlock))

        while True:
            try:
                self.lastScannedBlock = self.otc.currentBlock()
                self.checkBlock()
                self.db.updHeights(self.lastScannedBlock, "Other")
            except Exception as e:
                self.lastScannedBlock -= 1
                print('ERROR: Something went wrong during Other block iteration: ' + str(traceback.TracebackException.from_exception(e)))

            time.sleep(self.config['other']['timeInBetweenChecks'])

    def checkBlock(self):
        block = self.otc.getBlock()
        for transaction in block:
            targetAddress = self.otc.checkTx(transaction)

            if targetAddress is not None:
                if targetAddress != "No attachment":
                    transaction['recipient'] = targetAddress
                    transaction['sender'] = 'unknown'

                    if not(self.tnc.validateAddress(targetAddress)):
                        self.faultHandler(transaction, "txerror")
                    else:
                        amount = float(transaction['amount'])
                        amount *= pow(10, self.config['tn']['decimals'])
                        amount = int(round(amount))

                        amountCheck = amount / pow(10, self.config['tn']['decimals'])

                        if amountCheck < self.config['main']['min'] or amountCheck > self.config['main']['max']:
                            self.faultHandler(transaction, "senderror", e='outside amount ranges')
                        else:
                            try:
                                txId = None
                                self.db.insTunnel('sending', 'unknown', targetAddress)
                                txId = self.tnc.sendTx(targetAddress, amount, 'thank you for using our service.')

                                if 'error' in txId:
                                    self.faultHandler(transaction, "senderror", e=txId['message'])
                                    self.db.updTunnel("error", 'unknown', targetAddress, statusOld="sending")
                                else:
                                    print("INFO: send tx: " + str(txId))

                                    self.db.insExecuted('unknown', targetAddress, transaction['txid'], txId['id'], amountCheck, self.config['tn']['fee'])
                                    print('INFO: send tokens from other to tn!')

                                    self.db.updTunnel("verifying", 'unknown', targetAddress, statusOld='sending')
                            except Exception as e:
                                self.faultHandler(transaction, "txerror", e=e)
                                continue

                            if txId is None:
                                if targetAddress != 'invalid address':
                                    self.db.insError('unknown', targetAddress, transaction['id'], '', amountCheck, 'tx failed to send - manual intervention required')
                                    print("ERROR: tx failed to send - manual intervention required")
                                    self.db.updTunnel("error", 'unknown', targetAddress, statusOld="sending")
                            else:
                                self.tnc.verifyTx(txId, 'unknown', targetAddress)
                else:
                    self.faultHandler(transaction, 'noattachment')

    def faultHandler(self, tx, error, e=""):
        #handle transfers to the gateway that have problems
        amount = float(tx['amount'])
        timestampStr = sharedfunc.getnow()

        if error == "noattachment":
            self.db.insError('unknown', '', '', tx['txid'], amount, 'empty memo field')
            print("ERROR: " + timestampStr + " - Error: empty memo field " + tx['sender'] + " - check errors table.")

        if error == "notunnel":
            self.db.insError(tx['sender'], '', '', tx['txid'], amount, 'no tunnel found for sender')
            print("ERROR: " + timestampStr + " - Error: no tunnel found for transaction from " + tx['sender'] + " - check errors table.")

        if error == "txerror":
            targetAddress = tx['recipient']
            self.db.insError(tx['sender'], targetAddress, '', tx['txid'], amount, 'tx error, possible incorrect address', str(e))
            print("ERROR: " + timestampStr + " - Error: on outgoing transaction for transaction from " + tx['sender'] + " - check errors table.")

        if error == "senderror":
            targetAddress = tx['recipient']
            self.db.insError(tx['sender'], targetAddress, '', tx['txid'], amount, 'tx error, check exception error', str(e))
            print("ERROR: " + timestampStr + " - Error: on outgoing transaction for transaction from " + tx['sender'] + " - check errors table.")


N = int(input())
cnt = 0
a = {}
if N > 100 :
    print('Error')
num = list(map(int,input().split()))
for i in num:
    if i in a :
        cnt += 1
    if i not in a :
        a[i] = 1
print(cnt)


## started with a copy from https://github.com/keatontaylor/alexa-actions VERSION 0.8.2

# UPDATE THESE VARIABLES WITH YOUR CONFIG
HOME_ASSISTANT_URL                = 'https://yourhainstall.com'       # REPLACE WITH THE URL FOR YOUR HA FRONTEND
VERIFY_SSL                        = True                              # SET TO FALSE IF YOU DO NOT HAVE VALID CERTS
TOKEN                             = ''                                # ADD YOUR LONG LIVED TOKEN IF NEEDED OTHERWISE LEAVE BLANK

### NO NEED TO EDIT ANYTHING UNDER THE LINE ###
import logging
import urllib3
import json
import isodate
import prompts
from datetime import datetime

import ask_sdk_core.utils as ask_utils
from ask_sdk_core.skill_builder import SkillBuilder
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.dispatch_components import AbstractExceptionHandler
from ask_sdk_core.dispatch_components import AbstractRequestInterceptor
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_model import SessionEndedReason
from ask_sdk_model.slu.entityresolution import StatusCode
from ask_sdk_model import Response

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

INPUT_TEXT_ENTITY = "input_text.alexa_ha_report"

class Borg:
    """Borg MonoState Class for State Persistence."""
    _shared_state = {}
    def __init__(self):
        self.__dict__ = self._shared_state

class HomeAssistant(Borg):
    """HomeAssistant Wrapper Class."""
    def __init__(self, handler_input=None):
        Borg.__init__(self)
        if handler_input:
            self.handler_input = handler_input

        self.token = self._fetch_token() if TOKEN == "" else TOKEN

        if not hasattr(self, 'ha_state') or self.ha_state is None:
            self.get_ha_state()

    def _clear_state(self):
        self.ha_state = None

    def _fetch_token(self):
        return ask_utils.get_account_linking_access_token(self.handler_input)

    def _check_response_errors(self, response):
        data = self.handler_input.attributes_manager.request_attributes["_"]
        if response.status == 401:
            logger.error("401 Error", response.data)
            speak_output = "Error 401 " + data[prompts.ERROR_401]
            return speak_output
        elif response.status == 404:
            logger.error("404 Error", response.data)
            speak_output = "Error 404 " + data[prompts.ERROR_404]
            return speak_output
        elif response.status >= 400:
            logger.error("{response.status} Error", response.data)
            speak_output = "Error {response.status} " + data[prompts.ERROR_400]
            return speak_output

        return None

    def get_ha_state(self):
        """Get State from HA."""

        http = urllib3.PoolManager(
            cert_reqs='CERT_REQUIRED' if VERIFY_SSL else 'CERT_NONE',
            timeout=urllib3.Timeout(connect=10.0, read=10.0)
        )

        response = http.request(
            'GET',
            '{}/api/states/{}'.format(HOME_ASSISTANT_URL, INPUT_TEXT_ENTITY),
            headers={
                'Authorization': 'Bearer {}'.format(self.token),
                'Content-Type': 'application/json'
            },
        )

        errors = self._check_response_errors(response)
        if not errors:
            self.ha_state = {
                "error": True,
                "text": errors
            }

        decoded_response = json.loads(response.data.decode('utf-8'))['state']

        self.ha_state = {
            "error": False,
            "text": json.loads(decoded_response)['text']
        }

class LaunchRequestHandler(AbstractRequestHandler):
    """Handler for Skill Launch."""
    def can_handle(self, handler_input):
        return (ask_utils.is_request_type("LaunchRequest")(handler_input) or
                ask_utils.is_intent_name("ReportIntent")(handler_input))

    def handle(self, handler_input):
        home_assistant_object = HomeAssistant(handler_input)
        speak_output = home_assistant_object.ha_state['text']

        return (
            handler_input.response_builder
            .speak(speak_output)
            .response
        )

class CancelOrStopIntentHandler(AbstractRequestHandler):
    """Single handler for Cancel and Stop Intent."""
    def can_handle(self, handler_input):
        return (ask_utils.is_intent_name("AMAZON.CancelIntent")(handler_input) or
                ask_utils.is_intent_name("AMAZON.StopIntent")(handler_input))

    def handle(self, handler_input):
        print("CancelOrStopIntentHandler")
        data = handler_input.attributes_manager.request_attributes["_"]
        speak_output = data[prompts.STOP_MESSAGE]

        return (
            handler_input.response_builder
                .speak(speak_output)
                .response
        )

class SessionEndedRequestHandler(AbstractRequestHandler):
    """Handler for Session End."""
    def can_handle(self, handler_input):
        return ask_utils.is_request_type("SessionEndedRequest")(handler_input)

    def handle(self, handler_input):
        home_assistant_object = HomeAssistant(handler_input)
        if handler_input.request_envelope.request.reason == SessionEndedReason.EXCEEDED_MAX_REPROMPTS:
            home_assistant_object.post_ha_event(RESPONSE_NONE, RESPONSE_NONE)

        return handler_input.response_builder.response

class CatchAllExceptionHandler(AbstractExceptionHandler):
    """Generic error handling to capture any syntax or routing errors. If you receive an error
    stating the request handler chain is not found, you have not implemented a handler for
    the intent being invoked or included it in the skill builder below.
    """
    def can_handle(self, handler_input, exception):
        return True

    def handle(self, handler_input, exception):
        print("CatchAllExceptionHandler")
        logger.error(exception, exc_info=True)
        home_assistant_object = HomeAssistant()

        data = handler_input.attributes_manager.request_attributes["_"]
        if hasattr(home_assistant_object, 'ha_state') and home_assistant_object.ha_state != None and 'text' in home_assistant_object.ha_state:
            speak_output = data[prompts.ERROR_ACOUSTIC].format(home_assistant_object.ha_state['text'])
            return (
                handler_input.response_builder
                    .speak(speak_output)
                    .ask('')
                    .response
            )
        else:
            speak_output = data[prompts.ERROR_CONFIG].format(home_assistant_object.ha_state['text'])
            return (
                handler_input.response_builder
                    .speak(speak_output)
                    .response
            )

class LocalizationInterceptor(AbstractRequestInterceptor):
    """Add function to request attributes, that can load locale specific data."""

    def process(self, handler_input):
        locale = handler_input.request_envelope.request.locale
        logger.info("Locale is {}".format(locale[:2]))

        # localized strings stored in language_strings.json
        with open("language_strings.json") as language_prompts:
            language_data = json.load(language_prompts)
        # set default translation data to broader translation
        data = language_data[locale[:2]]
        # if a more specialized translation exists, then select it instead
        # example: "fr-CA" will pick "fr" translations first, but if "fr-CA" translation exists,
    #          then pick that instead
        if locale in language_data:
            data.update(language_data[locale])
        handler_input.attributes_manager.request_attributes["_"] = data

# The SkillBuilder object acts as the entry point for your skill, routing all request and response
# payloads to the handlers above. Make sure any new handlers or interceptors you've
# defined are included below. The order matters - they're processed top to bottom.

sb = SkillBuilder()

# register request / intent handlers
sb.add_request_handler(LaunchRequestHandler())

# register exception handlers
sb.add_exception_handler(CatchAllExceptionHandler())

# register response interceptors
sb.add_global_request_interceptor(LocalizationInterceptor())

lambda_handler = sb.lambda_handler()


# Rosen Gradient Projection Method
# Ref:《最优化理论与算法》陈宝林，Chapter 12
# Author: Stella

import numpy as np
from scipy.optimize import minimize_scalar

#minmize problem
#min 2*x[0]**2 + 2*x[1]**2 -2*x[0]*x[1] - 4*x[0] - 6*x[1]
#s.t.
# -x[0]-x[1]>=-2,
# -x[0]-5*x[1]>=-5,
# x[0]>=0, x[1]>=0

n=2
#Coefficient matrix
A = np.array([[-1, -1], [-1, -5], [1, 0], [0, 1]])
b = np.array([-2, -5, 0, 0]).reshape((1, len(A)))

#Objective function
def fun(x):
    ff = 2*x[0]**2 + 2*x[1]**2 -2*x[0]*x[1] - 4*x[0] - 6*x[1]
    return ff

#left hand side
def func_eval(x, A, b):
    con_left = A @ x - b
    return con_left

def gradient(x):
    g_1 = 4*x[0]-2*x[1]-4
    g_2 = 4*x[1]-2*x[0]-6
    gg  = np.array([g_1,g_2])
    return gg

def func(lambda_o):
    find_min_f = fun(x + lambda_o * d)
    find_min_f = np.int(find_min_f)
    return find_min_f

x=np.array([0,0])

number = 1
while number < 10000:
    con_left = func_eval(x,A,b)
    suoyin_1 = np.where(con_left == 0)[1]
    suoyin_2 = np.where(con_left >0)[1]
    A1 = A[suoyin_1]
    A2 = A[suoyin_2]
    b1 = np.transpose(np.transpose(b)[suoyin_1])
    b2 = np.transpose(np.transpose(b)[suoyin_2])

    N = A1.T @ (np.linalg.inv(A1 @ A1.T)) @ A1
    I = np.eye(len(N))
    P = I - N
    G = gradient(x)
    d = -1 * P @ G

    count = 1
    while count < 100:
        if d.any() == 0 or all([v < 1e-5 for v in d]):
            W = (np.linalg.inv(A1 @ A1.T)) @ A1 @ G
            if (W>=0).all():
                print('The K-T point is', x)
                judge = 1
                break
            else:
                print('Continue searching')
                judge = 0
                suoyin_3 = np.argmin(W)
                A1 = np.delete(A1, suoyin_3, axis=0)
                N = A1.T @ (np.linalg.inv(A1 @ A1.T)) @ A1
                I = np.eye(len(N))
                P = I - N
                G = gradient(x)
                d = -1 * P @ G
                count = count + 1
        else:
            break
        d = d

    b_hat = b2 - A2 @ x
    d_hat = A2 @ d
    d_hat_u = d_hat.reshape((1, len(d_hat)))
    d_hat_0 = np.array(np.where(d_hat < 0))
    lieshu = (d_hat_0.shape)[1]
    lamb = []
    for i in range(lieshu):
        k = d_hat_0[0, i]
        lam = b_hat[0, k] / d_hat_u[0, k]
        lamb.append(lam)
    lamb = np.array(lamb, dtype=float)
    lambda_max = np.min(lamb)
    a_bound = 0

    ## if the objective function is not concave,convex or expressed:
    # search = 50000
    # fi = []
    # for i in range(search):
    #     ki = i * 1/search
    #     fii = fun(x+ki*lambda_max*d)
    #     fi.append(fii)
    #     i = i+1
    # fi = np.array(fi, dtype = float)
    # suoyin_4 = np.argmin(fi)
    # lambda_op = (1+suoyin_4) * (1/search) *lambda_max

    #if the objective function is normal
    res = minimize_scalar(fun, bracket=(a_bound, lambda_max), bounds=(a_bound, lambda_max), args=(),
                                method='bounded', tol=None, options=None)
    lambda_op = res.x

    if judge ==1:
        break
        print('The K-T point is', x)
    else:
        number = number+1
        x = x + lambda_op * d

print('The optimal solution is',x)


a = [1, 2, 5, 6, 10]

b = [1, 3, 7, 5, 5, 7, 8, 9, 2, 4, 3, 6, 5, 3, 2, 1, 9]

c = [1, 5, 5, 9, 2, 4, 6, 5, 3, 2, 1, 9]
print("Del the position should be like this one:", c)

a.sort(reverse=True)
print("Sort the a", a)

for i in range(len(a)):
    del b[a[i]]

print("Output del use result:", b)


from turtle import Screen
from Scoreboard import Scoreboard
from paddle import Paddle
from ball import Ball
import time

canvas = Screen()
canvas.screensize(500, 500)
canvas.bgcolor("black")
canvas.title("Pong")
canvas.tracer(0)
player1 = Paddle(posx=-350, posy=0, player="Player1")
player2 = Paddle(posx=350, posy=0, player="Player2")
ball = Ball()
scoreboard = Scoreboard()
game_state = True

canvas.listen()
canvas.onkeypress(key="Up", fun=player1.moveUp)
canvas.onkeypress(key="Down", fun=player1.moveDown)
canvas.onkeypress(key="w", fun=player2.moveUp)
canvas.onkeypress(key="s", fun=player2.moveDown)

while game_state:
    canvas.update()
    ball.update()

    if ball.ycor() == 400 or ball.ycor() == -400:
        ball.reverse_y_direction()
    if ball.distance(player2) < 50 and ball.xcor() > 330:
        ball.reverse_x_direction()
    if ball.distance(player1) < 50 and ball.xcor() < -330:
        ball.reverse_x_direction()

    if ball.xcor() > 400:
        ball.restart()
        scoreboard.update_score_left()
    elif ball.xcor() < -400:
        ball.restart()
        scoreboard.update_score_right()

    time.sleep(ball.current_speed)

canvas.exitonclick()


#!/usr/bin/env python
import sys
import traceback

def puts(s):
    sys.stdout.write("%s\n" % s)

try:
    import optparse
    import SimpleHTTPServer
    import SocketServer
except ImportError:
    traceback.print_exc()
    puts('-' * 80)
    puts('Python 2.4 or greater is required.')
    puts('-' * 80)
    sys.exit(1)

class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler):
    extensions_map = SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map.copy()
    extensions_map.update({'.webapp': 'application/x-web-app-manifest+json'})

if __name__ == '__main__':
    op = optparse.OptionParser(usage='%prog [options]')
    op.add_option('-H', '--host', help='Host to bind webserver. Default: %default',
                  default='0.0.0.0')
    op.add_option('-p', '--port', help='Port to bind webserver. Default: %default',
                  default=9100)
    (options, args) = op.parse_args()
    httpd = SocketServer.TCPServer((options.host, options.port), Handler)
    puts("Manifest URL: http://%s:%s/manifest.webapp" % (options.host, options.port))
    puts("Serving app at http://%s:%s/" % (options.host, options.port))
    httpd.serve_forever()


# -*- coding: utf-8 -*-
"""
Created on Sun Sep 30 15:08:39 2018

@author: zhangyaxu
"""

from pyspark import SparkConf
from pyspark import SparkContext
from pyspark.sql import HiveContext

from pyspark.sql import functions  as F
from pyspark.sql import Window

import pandas as pds
import numpy as npy

from datetime import datetime as dtm
from params import  params
database_name=params['shared']['database_name']

def tfidf_similarty(tk2id,term_tfidf,topn=50,sim_min=0.0):
    '''
    全部在python内存中运行，效率低，且会溢出，遂摒弃了这个方案。

    获取tk2id中所以term key的相似term  ,
    tk2id ： dict-type 获取的词与词id
    term_tfidf：pandas-dataframe-type, 词的tfidf-vector ; index 是词的id, 一行的values就是该词的tfidf-vector
    topn ： 筛选topn个， None表示不筛选（不推荐，数据多时 容易内存溢出）
    sim_min ： 保留相似度>=sim_min的结果。
    return 相似term-dataframe
    '''
    def term_tfidf_similarity(term_name,tk_id,term_tfidf,topn=50,sim_min=0.0):
        '''
        term_name: make sure it is unicode-chinese if python2 . such as  u'化妆水'
        tk2id : term and id relation ,dict-type
        term_tfidf : term的tfidf向量表达，一行是一个term在各doc的tfidf权重，所以一行就是一个term的tfidf向量，且term_id是index
        '''
        def cosine(x,y):
            return npy.dot(x.reshape(1,-1),y.T)/(npy.linalg.norm(x)*npy.linalg.norm(y,axis=1))

        term_id=tk_id.loc[tk_id.term_name==term_name,'term_id'].values[0]
        x=term_tfidf.loc[term_tfidf.index==term_id,:].values  # shape = (1,n)
        y=term_tfidf.loc[term_tfidf.index!=term_id,:].values  # shape = (m,n)
        condx=x.mean()==0.0
        condy=max(y.mean(axis=1)==0)==True
        other_termid=term_tfidf.loc[term_tfidf.index!=term_id,:].index.values
        sim=cosine(x,y) # 归一化， -1==0 表示完全相反的向量  ，0==>0.5 要么是通用向量，跟谁都有点关系，也就是跟谁都没明显关系
        del x,y
        if condx and condy :
            sim[npy.isnan(sim)]=1.0
        else:
            sim[npy.isnan(sim)]=0.0
        sim=sim*0.5+0.5
        term_sim=pds.DataFrame(list(zip(other_termid.tolist(),sim.tolist()[0])),columns=['term_id','tfidf_sim'])
        del sim
        term_sim['base_term']=term_name
        #term_sim=pds.merge(term_sim,tk_id,on='term_id',how='inner')[['base_term','term_name','tfidf_sim']]
        term_sim=term_sim[['base_term','term_id','tfidf_sim']]
        #print(term_sim)
        term_sim=term_sim.loc[term_sim.tfidf_sim>=sim_min,:].reset_index(drop=True)
        if topn!=None:
            term_sim=term_sim.sort_values('tfidf_sim',ascending=False).reset_index(drop=True).loc[0:topn,:]
        return term_sim

    # 循环获取每个term的相似term
    tk_id=pds.DataFrame(list(tk2id.items()),columns=['term_name','term_id']) # dataframe 方便操作
    #term_name=u'b'
    k=1
    for term_name in  tk2id.keys():
        print(k)
        term_sim=term_tfidf_similarity(term_name=term_name,tk_id=tk_id,term_tfidf=term_tfidf,topn=topn,sim_min=sim_min)
        if k==1:
            tfidf_sim=term_sim.copy()
        else:
            tfidf_sim=pds.concat((tfidf_sim,term_sim),axis=0)
        #print(tfidf_sim.shape)
        del term_sim

    return tfidf_sim

def tfidf_similarty_sparse_vector(sqlContext,sc,tk2id,tfidf_vec,sparse=True,sparse_val=-1.0,topn=50,sim_min=0.55,storage=True):
    '''
    由于此处调用的 tfidf_vec 还是离散向量直接存储的方式，在计算过程中非常占用内存，经常会导致driver崩溃，遂 也弃用这个方案。

    tk2id ： dict-type 获取的词与词id
    tfidf_vec : pandas-dataframe-type （m,1）, 词的tfidf-vector ; index 是词的id, 唯一一列是该词的tfidf-vector （被以list形式存储在 dataframe的一列）
    sparse ： 是否稀疏，当稀疏时，会进行去稀疏值，取非稀疏并集位的方式进行相似度计算。
    sparse_val: 当稀疏时，这个作为 待去除的稀疏值，并在非稀疏取并集时，对Na位置进行填充sparse_val， 然后进行计算。
    topn ： 筛选topn个， None表示不筛选（不推荐，数据多时 容易内存溢出）
    sim_min ： 保留相似度>=sim_min的结果。
    storage=True ： 是否存储到hive表
    return 相似term spark-dataframe
    '''
    def vec_union_set(a,b,sparse_val=-1.0):
        '''
        获取两个稀疏向量 非稀疏部分的并集位置，最终二者分别保留并集位的值
        注意 a和b必须是等长的，不然位置无法对应
        a=npy.array([-1, -1,  0.2, 0.7, -1,  -1])
        b=npy.array([-1, 0.4, -1,   0,  0.7, -1])
        并集位在 [1,2,3,4] (任意一个向量的位置是非稀疏的值)
        则保留
        a_u=[-1,0.2,0.7,-1]
        b_u=[0.4,-1,0,0.7]
        return 保留向量
        '''
        pos_a=npy.array(range(len(a)))[a!=sparse_val].tolist()
        pos_b=npy.array(range(len(b)))[b!=sparse_val].tolist()
        pos_u=list(set(pos_a+pos_b)) # 去重，不在乎顺序
        a_u=a[pos_u]
        b_u=b[pos_u]
        return a_u,b_u

    def cosine_sparse_vector(a,b,sparse=True,sparse_val=-1.0):
        a=npy.array(a)
        b=npy.array(b)
        if sparse:
            a,b=vec_union_set(a,b,sparse_val=sparse_val)
        if a.mean()==0.0 and b.mean()==0.0:
            return 1.0
        elif a.mean()!=0 and b.mean()!=0:
            return npy.dot(a,b)/(npy.linalg.norm(a)*npy.linalg.norm(b))*0.5+0.5
        else:
            return 0.5

    def apply_cosine(df_vec,tfidf_vec,sparse=True,sparse_val=-1.0,sim_min=0.0,topn=30):
        #columnx=list(df_vec.columns)  # [term_id,tfidf_vec]
        vec_sim=df_vec.apply(lambda x: cosine_sparse_vector(a=tfidf_vec,b=x[0],sparse=True,sparse_val=-1.0),axis=1).loc[lambda x : x>=sim_min].sort_values(ascending=False).iloc[0:topn]  # an series
        return list(zip(vec_sim.index.values.tolist(),vec_sim.values.tolist()))

    ## 初始化 数据
    index_col='term_id'
    tfidf_vec.reset_index(inplace=True)  # [term_id,tfidf_vec]
    tfidf_vec_df=sqlContext.createDataFrame(tfidf_vec,['base_term_id','base_term_vec'])
    bc_tfidf_vec=sc.broadcast(tfidf_vec.set_index(index_col)) # 广播变量，rdd计算时调用

    ##cosine-similarity-calcularity 核心计算阶段
    term_sim1=tfidf_vec_df.rdd.map(lambda x : (x[0],apply_cosine(df_vec=bc_tfidf_vec.value,tfidf_vec=x[1],sparse=sparse,sparse_val=sparse_val,sim_min=sim_min,topn=topn))) # [(base_term_id,[(sim_term_id,sim_coef),..])]
    #y=term_sim1.top(5)  # 会 gc ，driver崩溃，跑不出来的
    ## rdd变形 并转化为 dataframe
    term_sim=term_sim1.flatMap(lambda y:[(y[0],)+(yy[0],yy[1]) for yy in y[1] if len(y[1])>0])  # 存在相似term时，则进行flatmap展开 使形式为 [(base_term_id1,sim_term_id1,sim_coef11),(base_term_id1,sim_term_id2,sim_coef12),..]
    tfidf_cosine=sqlContext.createDataFrame(term_sim,['base_term_id','sim_term_id','tfidf_similarity'])

    ## transform : get term name  #一些变形， join term的名称
    tk_id=sqlContext.createDataFrame(list(tk2id.items()),['term_name','term_id']) # dataframe 方便操作join
    tfidf_cosine=tfidf_cosine.join(tk_id,tfidf_cosine.sim_term_id==tk_id.term_id,'inner').drop('term_id').withColumnRenamed('term_name','sim_word')
    tfidf_cosine=tfidf_cosine.join(tk_id,tfidf_cosine.base_term_id==tk_id.term_id,'inner').drop('term_id').withColumnRenamed('term_name','target_word')
    tfidf_cosine=tfidf_cosine.select('target_word','sim_word','tfidf_similarity')

    # persist and storage 存储操作，action操作
    #tfidf_cosine.persist(StorageLevel(True,True,False,False,1))
    if storage:
        tfidf_cosine.write.saveAsTable('{0}.tfidf_sim_on_product_name'.format(database_name),mode='overwrite')

    return tfidf_cosine

def tfidf_similarty_unequal_length_vector(sqlContext,sc,tfidf_vec_df,tfidf_vec,sparse_val=0.0,topn=50,sim_min=0.55):
    '''
    正确的方案， 先借助broadcast 实现cross-join 的map_join ；rdd 计算相似度 并筛选等

    tk2id ： dict-type 获取的词与词id
    tfidf_vec : pandas-dataframe-type （m,1）, 词的tfidf-vector ; index 是词的id, 唯一一列是该词的tfidf-vector （被以list形式存储在 dataframe的一列）
    sparse_val: 这个作为对不等长的非稀疏向量取并集时，对Na位置进行填充sparse_val， 然后进行计算。
    topn ： 筛选topn个， None表示不筛选（不推荐，数据多时 容易内存溢出）
    sim_min ： 保留相似度>=sim_min的结果。
    return  ‘over’   # 注意 此部分相似结果 已经存储到hive表
    '''
    def vec_union_set(a,b,sparse_val=-1.0):
        '''
        获取两个向量  并集位置填充稀疏值
        a=[[0.2, 0.7],[1,3]]  ： 向量 和 位置
        b=[[0.4, 0,  0.7],[1,2,7]]
        并集位在 [1,2,3,7] (任意一个向量的位置是非稀疏的值)
        则保留
        a_u=[ 0.2, -1.0, 0.7  , -1.0 ]
        b_u=[ 0.4, 0.0 , -1.0 , 0.7]
        return 保留向量
        '''
        pos_a=a[1]
        pos_b=b[1]
        a=a[0]
        b=b[0]
        pos_u=list(set(pos_a+pos_b)) # 去重，不在乎顺序
        a_u=[sparse_val]*len(pos_u)
        b_u=[sparse_val]*len(pos_u)
        for pos in pos_u:
            if pos in pos_a:
                a_u[pos_u.index(pos)]=a[pos_a.index(pos)]
            if pos in pos_b:
                b_u[pos_u.index(pos)]=b[pos_b.index(pos)]
        return npy.array(a_u),npy.array(b_u)

    def cosine_sparse_vector(a,b,sparse_val=-1.0,min_intersect_rate=0.5):
        len_inters=len(set(a[1]).intersection(set(b[1])))
        if len_inters>0:
            r_a=len_inters*1.0/len(a[1]) # 交集占a的比例
            r_b=len_inters*1.0/len(b[1]) # 交集占b的比例
            if r_a<min_intersect_rate or r_b<min_intersect_rate:
                decay_coef=min(r_a,r_b)/min_intersect_rate
            else:
                decay_coef=1.0
            a,b=vec_union_set(a,b,sparse_val=sparse_val)
            if a.mean()==0.0 and b.mean()==0.0:
                return 1.0*decay_coef
            elif a.mean()!=0 and b.mean()!=0:
                return float(npy.dot(a,b)/(npy.linalg.norm(a)*npy.linalg.norm(b))*0.5+0.5)*decay_coef
            else:
                return 0.5*decay_coef
        else:
            return 0.0

    def apply_cosine(df_vec,tfidf_vec,sparse_val=-0.1,sim_min=0.0,topn=30):
        #columnx=list(df_vec.columns)  # [term_id,tfidf_vec]
        vec_sim=df_vec.apply(lambda x: cosine_sparse_vector(a=tfidf_vec,b=[x[0],x[1]],sparse_val=sparse_val),axis=1).loc[lambda x : x>=sim_min].sort_values(ascending=False).iloc[0:topn]  # an series
        return list(zip(vec_sim.index.values.tolist(),vec_sim.values.tolist()))

    #  sparse_val=0.0;topn=30;sim_min=0.45;storage=True

    # 1  broadcast 方法1  -- 效率：比不广播快，但是 比方法2 map-crossjoin方法的慢
    ## 初始化 数据
    #index_col='term_name'
    #tfidf_vec.set_index(index_col,inplace=True)
    #bc_tfidf_vec=sc.broadcast(tfidf_vec) # 广播变量，rdd计算时调用
    ###cosine-similarity-calcularity 核心计算阶段
    #term_sim1=tfidf_vec_df.limit(100).rdd.repartition(500).map(lambda x : (x[0],apply_cosine(df_vec=bc_tfidf_vec.value,tfidf_vec=[x[1],x[2]],sparse_val=sparse_val,sim_min=sim_min,topn=topn))) # [(base_term_id,[(sim_term_id,sim_coef),..])]
    #t1=dtm.now()
    #y=term_sim1.top(5)
    #print(dtm.now()-t1)
    ### rdd变形 并转化为 dataframe
    #term_sim=term_sim1.flatMap(lambda y:[(y[0],)+(yy[0],yy[1]) for yy in y[1] if len(y[1])>0])  # 存在相似term时，则进行flatmap展开 使形式为 [(base_term_id1,sim_term_id1,sim_coef11),(base_term_id1,sim_term_id2,sim_coef12),..]
    #tfidf_cosine=sqlContext.createDataFrame(term_sim,['target_word','sim_word','tfidf_similarity'])
    #
    # persist and storage 存储操作，action操作
    #t1=dtm.now()
    #tfidf_cosine.write.saveAsTable('{0}.tfidf_sim_on_product_name'.format(database_name),mode='overwrite')
    #print(dtm.now()-t1)

    ## 2  broadcast cross map-join 方法 ，效率快
    # 但是由于需要 window操作获得排序后筛选，这个过程，效率会随着数据规模先提高 之后就幂式降低，比如 1000*5w 需要2.3分钟，但是 2000*5w就会卡住,
    # 所以注意分批，很 window操作的数据集 不要太大
    # sparse_val=0.0;topn=30;sim_min=0.5

    #t1=dtm.now()
    #tfidf_vec_df=1
    endx=tfidf_vec_df.select(F.max('rankx')).collect()[0][0]
    #endx=10000
    rk_step=endx;rk_start=1;
    tem_type=3  # 1 limit , 2 filter, 3 broadcast map-join
    while rk_start<=endx:
        t1=dtm.now()
        #提取批次计算相似度
        if tem_type==1:
            tem1=tfidf_vec_df.limit(rk_step).selectExpr('1 as dkid','term_name','tfidf_vec','tfidf_vec_pos')
        elif tem_type==2:
            tem1=tfidf_vec_df.filter(F.col('rankx').between(rk_start,rk_start+rk_step-1)).selectExpr('1 as dkid','term_name','tfidf_vec','tfidf_vec_pos')
        elif tem_type==3:
            #tem1=tfidf_vec_df.filter(F.col('rankx').between(rk_start,rk_start+rk_step-1)).selectExpr('1 as dkid','term_name','tfidf_vec','tfidf_vec_pos').collect()
            tem1=tfidf_vec_df.filter(F.col('rankx').between(rk_start,rk_start+rk_step-1)).selectExpr('1 as dkid','term_name','tfidf_vec','tfidf_vec_pos').collect()
            bd_tem1=sc.broadcast(tem1)
        tem2=tfidf_vec_df.selectExpr('1 as dkid','term_name as term_name2','tfidf_vec as tfidf_vec2','tfidf_vec_pos as tfidf_vec_pos2')

        # join
        if tem_type<3:
            # reduce join方法
            tfidf_vec_df_crossjoin=tem1.join(tem2,'dkid','inner')
            #tfidf_vec_df_crossjoin=tfidf_vec_df_crossjoin.rdd.map(lambda x: x[0:7])
        elif tem_type==3:
            # map-join方法
            tfidf_vec_df_crossjoin=tem2.rdd.repartition(400).flatMap(lambda x : map(lambda y : (x.dkid,y.term_name,y.tfidf_vec,y.tfidf_vec_pos,x.term_name2,x.tfidf_vec2,x.tfidf_vec_pos2),bd_tem1.value))
        #tfidf_vec_df_crossjoin.count()
        #print(dtm.now()-t1) # 11  26s   11

        # 核心计算
        if tem_type==3:
            tfidf_vec_df_sim_all=tfidf_vec_df_crossjoin.map(lambda x : (x[1],x[4],cosine_sparse_vector(a=[x[2],x[3]],b=[x[5],x[6]],sparse_val=sparse_val)))
        if tem_type<3:
            tfidf_vec_df_sim_all=tfidf_vec_df_crossjoin.rdd.repartition(400).map(lambda x : (x.term_name,x.term_name2,cosine_sparse_vector(a=[x.tfidf_vec,x.tfidf_vec_pos],b=[x.tfidf_vec2,x.tfidf_vec_pos2],sparse_val=sparse_val)))
        #tfidf_vec_df_sim_all.count(); print(dtm.now()-t1)

        # sim_min筛选
        tfidf_cosine=sqlContext.createDataFrame(tfidf_vec_df_sim_all.filter(lambda x: x[2]>=sim_min),['target_word','sim_word','tfidf_similarity'])
        #tfidf_cosine.count(); print(dtm.now()-t1)
        if rk_start==1:
            modex='overwrite'
        else:
            modex='append'
        tfidf_cosine.write.saveAsTable('{0}.tfidf_sim_all_on_product_name'.format(database_name),mode=modex)
        tfidf_cosine=sqlContext.sql('select * from {0}.tfidf_sim_all_on_product_name'.format(database_name))
        # topn选取
        windowy=Window.partitionBy('target_word').orderBy(F.desc('tfidf_similarity'))
        tfidf_cosine=tfidf_cosine.withColumn('rankx',F.row_number().over(windowy)).filter(F.col('rankx')<=topn).withColumn('rk_start',F.lit(rk_start)).drop('rankx')
        #tfidf_cosine.count() ;     print(dtm.now()-t1)
        # 逐批写入表
        tfidf_cosine.write.saveAsTable('{0}.tfidf_sim_on_product_name'.format(database_name),mode=modex)
        rk_start=rk_start+rk_step
        print(dtm.now()-t1)
    return tfidf_cosine

if __name__=='__main__':
    confx=SparkConf().setAppName('4_word_semantic_similarity_on_prod_name')
    sc=SparkContext(conf=confx)
    sqlContext=HiveContext(sc)
    sc.setLogLevel("WARN")

    ## 4 tfidf 相似度
    # 4.1 生成tfidf 向量，并存储 ： 先在独立的py文件中运行了，以便释放内存

    # 4.2 计算相似度 建议这里重新开一个 py文件，这样可以释放内存
    tfidf_id_vec_df=sqlContext.sql('select * from {0}.term_id_tfidf_vec_in_cat'.format(database_name))
    tk_id=sqlContext.sql('select * from {0}.term_id_name'.format(database_name))

    tfidf_vec_df=tk_id.join(tfidf_id_vec_df,'term_id','inner').select('term_name','tfidf_vec','tfidf_vec_pos','rankx')
    tfidf_vec=tfidf_vec_df.toPandas()
    #import sys
    #sys.getsizeof(tfidf_vec)/1024.0/1024
    sparse_val=params['tfidf']['na_val']
    topn=params['tfidf']['topn']
    sim_min=params['tfidf']['sim_min']
    tfidf_cosine=tfidf_similarty_unequal_length_vector(sqlContext,sc,tfidf_vec_df,tfidf_vec,sparse_val=sparse_val,topn=topn,sim_min=sim_min)

    ## 计算 词的tfidf向量的余弦相似度，并支持返回topn个 。调用之前 失败的两个方案，弃用
    # ## term_id 和词的对应关系 {word:term_id,....}   #id2tk=dict(zip(tk2id.values(),tk2id.keys()))
    #tk2id=dict(tk_id.toPandas().values.tolist())
    #tfidf_sim=tfidf_similarty(tk2id=tk2id,term_tfidf=term_tfidf,topn=30,sim_min=0.55)
    #tfidf_sim=tfidf_similarty_sparse_vector(sqlContext,sc,tk2id,tfidf_vec,sparse=True,sparse_val=-1.0,topn=30,sim_min=0.55,storage=True)
    #sparse=True;sparse_val=-1.0;topn=30;sim_min=0.55;storage=True

    #x=[0.0687139273586093,0.26924664185961983,0.017090797817728192,0.1590905459402894,0.004967842258367511,0.4693181818181818,0.10206776801078096,0.028519914310767707,0.0270236216173122,0.014201848214739464,0.015545638590167903,0.0037373093726070067,0.1050733027445443,0.016825410566136744,0.026545443563624496,0.1417261306686095,0.014507085026813998,0.007311542916732695,0.005270590752859457,0.04538167787191872,0.07044361898916193,0.043913385128132316,0.0018616950413776838,0.01604549746493062,0.0016649624693130737,0.19158534869198032,0.019279047129423944,0.029598094052775126,0.009246162415775746,1.0,0.8539300224672597,0.3620851976056391,0.005222188222083615,0.20422210396399176]
    #
    #y=[0.009238269090663888,0.23071799674926613,0.6621621621621621,0.06018738162797896,0.023124254846568416,0.038383373553349906,0.00202016722843622,0.03183185782782627,0.030996748508415883,0.05571543220387598,0.36333059796885514,0.09410001098473945,0.005778302106633069,0.10292499285558142,0.02474830434424806,0.03418761569422351,0.027102919272619087,0.17662058415017018,0.07615526377206697,0.013009862809403206,0.010799756557706425,0.050093326001714476,0.0684995340167754,0.1064665414409902,0.006399587903302731,0.02998755378089431,1.0,0.8247416353717971,0.42155449201488127,0.11039032646702258]
    #
    #xp=[15,32,78,80,107,116,167,193,236,241,248,266,294,298,328,348,406,478,486,515,519,647,675,719,735,914,967,987,994,1026,1033,1040,1086,1192]
    #
    #yp=[78,80,116,167,193,241,266,298,314,348,395,406,419,439,453,486,491,515,519,719,735,743,821,827,987,994,1026,1033,1040,1192]
    #
    #
    #a=[x,xp]
    #b=[y,yp]
    #sparse_val=0.0
    #cosine_sparse_vector(a=a,b=b,sparse_val=sparse_val)


import torch
import torch.nn as nn
import torch.nn.functional as F
from gym import Space
from habitat import Config
from habitat_baselines.common.baseline_registry import BaselineRegistry
from habitat_baselines.rl.models.rnn_state_encoder import (
    build_rnn_state_encoder,
)
from habitat_baselines.rl.ppo.policy import Net

from vlnce_baselines.common.aux_losses import AuxLosses
from vlnce_baselines.models.encoders import resnet_encoders
from vlnce_baselines.models.encoders.instruction_encoder import (
    InstructionEncoder,
)
from vlnce_baselines.models.policy import ILPolicy

@BaselineRegistry.register_policy
class Seq2SeqPolicy(ILPolicy):
    def __init__(
        self,
        observation_space: Space,
        action_space: Space,
        model_config: Config,
    ):
        super().__init__(
            Seq2SeqNet(
                observation_space=observation_space,
                model_config=model_config,
                num_actions=action_space.n,
            ),
            action_space.n,
        )

    @classmethod
    def from_config(
        cls, config: Config, observation_space: Space, action_space: Space
    ):
        config.defrost()
        config.MODEL.TORCH_GPU_ID = config.TORCH_GPU_ID
        config.freeze()

        return cls(
            observation_space=observation_space,
            action_space=action_space,
            model_config=config.MODEL,
        )

class Seq2SeqNet(Net):
    """A baseline sequence to sequence network that performs single modality
    encoding of the instruction, RGB, and depth observations. These encodings
    are concatentated and fed to an RNN. Finally, a distribution over discrete
    actions (FWD, L, R, STOP) is produced.
    """

    def __init__(
        self, observation_space: Space, model_config: Config, num_actions: int
    ):
        super().__init__()
        self.model_config = model_config

        # Init the instruction encoder
        self.instruction_encoder = InstructionEncoder(
            model_config.INSTRUCTION_ENCODER
        )

        # Init the depth encoder
        assert model_config.DEPTH_ENCODER.cnn_type in ["VlnResnetDepthEncoder"]
        self.depth_encoder = getattr(
            resnet_encoders, model_config.DEPTH_ENCODER.cnn_type
        )(
            observation_space,
            output_size=model_config.DEPTH_ENCODER.output_size,
            checkpoint=model_config.DEPTH_ENCODER.ddppo_checkpoint,
            backbone=model_config.DEPTH_ENCODER.backbone,
            trainable=model_config.DEPTH_ENCODER.trainable,
        )

        # Init the RGB visual encoder
        assert model_config.RGB_ENCODER.cnn_type in [
            "TorchVisionResNet18",
            "TorchVisionResNet50",
        ]
        self.rgb_encoder = getattr(
            resnet_encoders, model_config.RGB_ENCODER.cnn_type
        )(
            model_config.RGB_ENCODER.output_size,
            normalize_visual_inputs=model_config.normalize_rgb,
            trainable=model_config.RGB_ENCODER.trainable,
            spatial_output=False,
        )

        if model_config.SEQ2SEQ.use_prev_action:
            self.prev_action_embedding = nn.Embedding(num_actions + 1, 32)

        # Init the RNN state decoder
        rnn_input_size = (
            self.instruction_encoder.output_size
            + model_config.DEPTH_ENCODER.output_size
            + model_config.RGB_ENCODER.output_size
        )

        if model_config.SEQ2SEQ.use_prev_action:
            rnn_input_size += self.prev_action_embedding.embedding_dim

        self.state_encoder = build_rnn_state_encoder(
            input_size=rnn_input_size,
            hidden_size=model_config.STATE_ENCODER.hidden_size,
            rnn_type=model_config.STATE_ENCODER.rnn_type,
            num_layers=1,
        )

        self.progress_monitor = nn.Linear(
            self.model_config.STATE_ENCODER.hidden_size, 1
        )

        self._init_layers()

        self.train()

    @property
    def output_size(self):
        return self.model_config.STATE_ENCODER.hidden_size

    @property
    def is_blind(self):
        return self.rgb_encoder.is_blind or self.depth_encoder.is_blind

    @property
    def num_recurrent_layers(self):
        return self.state_encoder.num_recurrent_layers

    def _init_layers(self):
        nn.init.kaiming_normal_(
            self.progress_monitor.weight, nonlinearity="tanh"
        )
        nn.init.constant_(self.progress_monitor.bias, 0)

    def forward(self, observations, rnn_states, prev_actions, masks):
        instruction_embedding = self.instruction_encoder(observations)
        depth_embedding = self.depth_encoder(observations)
        rgb_embedding = self.rgb_encoder(observations)

        if self.model_config.ablate_instruction:
            instruction_embedding = instruction_embedding * 0
        if self.model_config.ablate_depth:
            depth_embedding = depth_embedding * 0
        if self.model_config.ablate_rgb:
            rgb_embedding = rgb_embedding * 0

        x = torch.cat(
            [instruction_embedding, depth_embedding, rgb_embedding], dim=1
        )

        if self.model_config.SEQ2SEQ.use_prev_action:
            prev_actions_embedding = self.prev_action_embedding(
                ((prev_actions.float() + 1) * masks).long().view(-1)
            )
            x = torch.cat([x, prev_actions_embedding], dim=1)

        x, rnn_states_out = self.state_encoder(x, rnn_states, masks)

        if self.model_config.PROGRESS_MONITOR.use and AuxLosses.is_active():
            progress_hat = torch.tanh(self.progress_monitor(x))
            progress_loss = F.mse_loss(
                progress_hat.squeeze(1),
                observations["progress"],
                reduction="none",
            )
            AuxLosses.register_loss(
                "progress_monitor",
                progress_loss,
                self.model_config.PROGRESS_MONITOR.alpha,
            )

        return x, rnn_states_out


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from tensorflow.python.data.experimental.ops import batching
from tensorflow.python.data.ops import dataset_ops
from tensorflow.python.data.ops import multi_device_iterator_ops
from tensorflow.python.distribute import device_util
from tensorflow.python.distribute import distribution_strategy_context
from tensorflow.python.distribute import input_ops
from tensorflow.python.distribute import values
from tensorflow.python.eager import context
from tensorflow.python.framework import device as tf_device
from tensorflow.python.framework import ops
from tensorflow.python.framework import tensor_util

class InputWorkers(object):
  """A 1-to-many mapping from input worker devices to compute devices."""

  def __init__(self, device_map, worker_device_pairs=None, logical_device=0):
    """Initialize an `InputWorkers` object.

    Args:
      device_map: A `DeviceMap` with the computation devices fed by the
        input workers.
      worker_device_pairs: A sequence of pairs:
        `(input device, a tuple of compute devices fed by that input device)`.
      logical_device: The logical device of `device_map` to feed.
    """
    self._device_map = device_map
    self._logical_device = logical_device
    if worker_device_pairs is None:
      worker_device_pairs = ((
          device_util.canonicalize("/device:CPU:0"),
          device_map.logical_to_actual_devices(logical_device)),)
    self._input_worker_devices = tuple(d for d, _ in worker_device_pairs)
    self._fed_devices = tuple(tuple(device_util.canonicalize(d) for d in f)
                              for _, f in worker_device_pairs)
    flattened = tuple(d for l in self._fed_devices for d in l)
    assert (flattened ==
            device_map.logical_to_actual_devices(logical_device)), (
                "flattened: %s logical device %d: %s" %
                (flattened, logical_device,
                 device_map.logical_to_actual_devices(logical_device)))

  @property
  def device_map(self):
    return self._device_map

  @property
  def logical_device(self):
    return self._logical_device

  @property
  def num_workers(self):
    return len(self._input_worker_devices)

  @property
  def worker_devices(self):
    return self._input_worker_devices

  def compute_devices_for_worker(self, worker_index):
    return self._fed_devices[worker_index]

  def __repr__(self):
    devices = self.worker_devices
    debug_repr = ",\n".join("  %d %s: %s" %
                            (i, devices[i], self._fed_devices[i])
                            for i in range(len(devices)))
    return "%s:{\n%s\n  device_map: %s}" % (
        self.__class__.__name__, debug_repr, self._device_map)

class InputIterator(object):
  """An input iterator, intended to be passed to `DistributionStrategy.run`."""

  def get_next(self):
    """Returns the next inputs for all replicas."""
    raise NotImplementedError("must be implemented in descendants")

  def initialize(self):
    """Initialize the underlying input dataset, when applicable.

    In eager mode, this will create a new iterator and return it.
    In graph mode, this will initialize the same underlying iterator(s).

    Users are required to call this if
    - This iterator was returned from a call to `make_input_fn_iterator` with an
      input function that returns a dataset.
    - Or this iterator was returned from a call to `make_dataset_iterator`.

    Returns:
      A list of initialization ops to be executed.
    """
    raise NotImplementedError("must be implemented in descendants")

class InputIteratorImpl(InputIterator):
  """Common implementation for all input iterators."""

  def __init__(self, input_workers, iterators):
    assert isinstance(input_workers, InputWorkers)
    if not input_workers.worker_devices:
      raise ValueError("Should have at least one worker for input iterator.")

    self._iterators = iterators
    self._input_workers = input_workers

  def get_next(self, name=None):
    """Returns the next input from the iterator for all replicas."""
    replicas = []
    for i, worker in enumerate(self._input_workers.worker_devices):
      if name is not None:
        d = tf_device.DeviceSpec.from_string(worker)
        new_name = "%s_%s_%d" % (name, d.job, d.task)
      else:
        new_name = None
      with ops.device(worker):
        # Make `replicas` a flat list of values across all replicas.
        replicas.extend(self._iterators[i].get_next_as_list(new_name))

    return values.regroup(self._input_workers.device_map, replicas)

  def initialize(self):
    """Initialze underlying iterators.

    Returns:
      A list of any initializer ops that should be run.
    """
    init_ops = []
    for it in self._iterators:
      init_ops.extend(it.initialize())
    return init_ops

  # TODO(priyag): Remove when we switch to using `MultiDeviceIterator` for TPUs.
  @property
  def output_classes(self):
    return self._iterators[0].output_classes

  # TODO(priyag): Remove when we switch to using `MultiDeviceIterator` for TPUs.
  @property
  def output_shapes(self):
    return self._iterators[0].output_shapes

  # TODO(priyag): Remove when we switch to using `MultiDeviceIterator` for TPUs.
  @property
  def output_types(self):
    return self._iterators[0].output_types

  # TODO(priyag): Remove when we switch to using `MultiDeviceIterator` for TPUs.
  def get_iterator(self, worker):
    for i, w in enumerate(self._input_workers.worker_devices):
      if worker == w:
        return self._iterators[i]
    return None

class InputFunctionIterator(InputIteratorImpl):
  """Iterator created from input function."""

  def __init__(self, input_fn, input_workers, input_contexts):
    """Make an iterator for input provided via an input function.

    Currently implements PER_WORKER mode, in which the `input_fn` is called
    once on each worker.

    TODO(priyag): Add other replication modes.

    Args:
      input_fn: Input function that returns a `tf.data.Dataset` object.
      input_workers: an `InputWorkers` object.
      input_contexts: A list of `InputContext` instances to be passed to call(s)
        to `input_fn`. Length and order should match worker order in
        `worker_device_pairs`.
    """
    assert isinstance(input_workers, InputWorkers)
    if input_workers.num_workers != len(input_contexts):
      raise ValueError(
          "Number of input workers (%d) is not same as number of "
          "input_contexts (%d)" %
          (input_workers.num_workers, len(input_contexts)))

    iterators = []
    for i, ctx in enumerate(input_contexts):
      worker = input_workers.worker_devices[i]
      with ops.device(worker):
        result = input_fn(ctx)
        devices = input_workers.compute_devices_for_worker(i)
        if isinstance(result, dataset_ops.DatasetV2):
          iterator = _SingleWorkerDatasetIterator(result, worker, devices)
        elif callable(result):
          iterator = _SingleWorkerCallableIterator(result, worker, devices)
        else:
          raise ValueError(
              "input_fn must return a tf.data.Dataset or a callable.")
        iterators.append(iterator)

    super(InputFunctionIterator, self).__init__(input_workers, iterators)

class DatasetIterator(InputIteratorImpl):
  """Iterator created from input dataset."""

  def __init__(self, dataset, input_workers, split_batch_by=None):
    """Make an iterator for the dataset on given devices.

    If `split_batch_by` is not None, we "split" each batch of the
    dataset by `split_batch_by` value. To achieve this, we first unbatch the
    input dataset and then rebatch it with the per replica batch size that is
    calculated using `global_batch_size // split_batch_by`.
    The currently supported datasets are as follows:
    `dataset.batch()` is the last operation on the dataset OR
    `dataset.apply(map_and_batch)` is the last operation on the dataset OR
    `dataset.batch().prefetch()` are the last 2 operations on the dataset OR
    `dataset.apply(map_and_batch).prefetch()` are the last 2 operations.

    TODO(priyag): Support multi worker / host cases properly by cloning
    and sharding the dataset on each worker. Current setup will only work in
    some cases, such as in-graph multi worker GPU case. If the input pipeline
    has random shuffling (with a different seed on each worker), each worker
    will see random input from the same overall dataset in each step. Otherwise,
    each worker will see the same input in each step.

    Args:
      dataset: `tf.data.Dataset` that will be used as the input source.
      input_workers: an `InputWorkers` object.
      split_batch_by: Optional integer. If present, we "split" each batch of the
        dataset by `split_batch_by` value.
    """
    assert isinstance(input_workers, InputWorkers)
    if split_batch_by:
      dataset = batching._RebatchDataset(dataset, split_batch_by)  # pylint: disable=protected-access

    iterators = []
    for i, worker in enumerate(input_workers.worker_devices):
      with ops.device(worker):
        worker_devices = input_workers.compute_devices_for_worker(i)
        cloned_dataset = dataset
        if not context.executing_eagerly():
          cloned_dataset = input_ops._clone_dataset(dataset)  # pylint: disable=protected-access
          cloned_dataset = cloned_dataset.with_options(dataset.options())
        iterator = _SingleWorkerDatasetIterator(cloned_dataset, worker,
                                                worker_devices)
        iterators.append(iterator)

    self._element_structure = dataset._element_structure  # pylint: disable=protected-access

    super(DatasetIterator, self).__init__(input_workers, iterators)

class _SingleWorkerDatasetIterator(object):
  """Iterator for a single `tf.data.Dataset`."""

  def __init__(self, dataset, worker, devices):
    """Create iterator for the `dataset` to fetch data to worker's `devices` .

    `MultiDeviceIterator` is used to prefetch input to the devices on the
    given worker.

    Args:
      dataset: A `tf.data.Dataset` instance.
      worker: Worker on which ops should be created.
      devices: Distribute data from `dataset` to these devices.
    """
    self._dataset = dataset
    self._worker = worker
    self._devices = devices
    self._make_iterator()

  def _make_iterator(self):
    """Make appropriate iterator on the dataset."""
    with ops.device(self._worker):
      self._iterator = multi_device_iterator_ops.MultiDeviceIterator(
          self._dataset, self._devices)

  def get_next_as_list(self, name=None):
    """Get next element from the underlying iterator."""
    del name
    with ops.device(self._worker):
      data_list = self._iterator.get_next()
      return data_list

  def initialize(self):
    """Initialze underlying iterator.

    In eager execution, this simply recreates the underlying iterator.
    In graph execution, it returns the initializer ops for the underlying
    iterator.

    Returns:
      A list of any initializer ops that should be run.
    """
    if context.executing_eagerly():
      self._iterator._eager_reset()  # pylint: disable=protected-access
      return []
    else:
      return [self._iterator.initializer]

  @property
  def output_classes(self):
    return dataset_ops.get_legacy_output_classes(self._iterator)

  @property
  def output_shapes(self):
    return dataset_ops.get_legacy_output_shapes(self._iterator)

  @property
  def output_types(self):
    return dataset_ops.get_legacy_output_types(self._iterator)

class _SingleWorkerCallableIterator(object):
  """Iterator for a single tensor-returning callable."""

  def __init__(self, fn, worker, devices):
    self._fn = fn
    self._worker = worker
    self._devices = devices

  def get_next_as_list(self, name=None):
    """Get next element from the callable."""
    del name
    with ops.device(self._worker):
      data_list = [self._fn() for _ in self._devices]
      return data_list

  def initialize(self):
    # TODO(petebu) Should this throw an exception instead?
    return []

# TODO(sourabhbajaj): Remove this in lieu of distributed datasets
def _get_batched_dataset(d):
  """Get the batched dataset from `d`."""
  # pylint: disable=protected-access
  if isinstance(d, dataset_ops.DatasetV1Adapter):
    d = d._dataset

  if isinstance(d, (dataset_ops.BatchDataset, batching._MapAndBatchDataset)):
    return d
  elif isinstance(d, (dataset_ops.PrefetchDataset,
                      dataset_ops._OptionsDataset)):
    return _get_batched_dataset(d._input_dataset)

  raise ValueError(
      "Unable to get batched dataset from the input dataset. `batch` "
      "`map_and_batch` need to be the last operations on the dataset. "
      "The batch operations can be followed by a prefetch.")

def _get_batched_dataset_attributes(d):
  """Get `batch_size`, `drop_remainder` of dataset."""
  # pylint: disable=protected-access
  assert isinstance(d,
                    (dataset_ops.BatchDataset, batching._MapAndBatchDataset))
  if isinstance(d, dataset_ops.BatchDataset):
    batch_size = d._batch_size
    drop_remainder = d._drop_remainder
  elif isinstance(d, batching._MapAndBatchDataset):
    batch_size = d._batch_size_t
    drop_remainder = d._drop_remainder_t
  # pylint: enable=protected-access

  if tensor_util.is_tensor(batch_size):
    batch_size = tensor_util.constant_value(batch_size)

  if tensor_util.is_tensor(drop_remainder):
    drop_remainder = tensor_util.constant_value(drop_remainder)

  return batch_size, drop_remainder

# TODO(sourabhbajaj): Remove this in lieu of distributed datasets
def _get_dataset_attributes(dataset):
  """Get the underlying attributes from the dataset object."""
  # pylint: disable=protected-access

  # First, get batch_size and drop_remainder from the dataset. We need
  # to walk back the dataset creation process and find the batched version in
  # order to get the attributes.
  batched_dataset = _get_batched_dataset(dataset)
  batch_size, drop_remainder = _get_batched_dataset_attributes(batched_dataset)

  # Second, prefetch buffer should be get from the original dataset.
  prefetch_buffer = None
  if isinstance(dataset, dataset_ops.PrefetchDataset):
    prefetch_buffer = dataset._buffer_size
  elif (isinstance(dataset, dataset_ops.DatasetV1Adapter)
        and isinstance(dataset._dataset, dataset_ops.PrefetchDataset)):
    prefetch_buffer = dataset._dataset._buffer_size

  return batch_size, drop_remainder, prefetch_buffer

class MultiStepContext(object):
  """A context object that can be used to capture things when running steps.

  This context object is useful when running multiple steps at a time using the
  `experimental_run_steps_on_iterator` API. For e.g. it allows the user's step
  function to specify which outputs to emit at what frequency. Currently it
  supports capturing output from the last step, as well as capturing non tensor
  outputs.  In the future it will be augmented to support other use cases such
  as output each N steps.
  """

  def __init__(self):
    """Initialize an output context.

    Returns:
      A context object.
    """
    self._last_step_outputs = {}
    self._last_step_outputs_reduce_ops = {}
    self._non_tensor_outputs = {}

  @property
  def last_step_outputs(self):
    """A dictionary consisting of outputs to be captured on last step.

    Keys in the dictionary are names of tensors to be captured, as specified
    when `set_last_step_output` is called.
    Values in the dictionary are the tensors themselves. If
    `set_last_step_output` was called with a `reduce_op` for this output,
    then the value is the reduced value.

    Returns:
      A dictionary with last step outputs.
    """
    return self._last_step_outputs

  def _set_last_step_outputs(self, outputs):
    """Replace the entire dictionary of last step outputs."""
    if not isinstance(outputs, dict):
      raise ValueError("Need a dictionary to set last_step_outputs.")
    self._last_step_outputs = outputs

  def set_last_step_output(self, name, output, reduce_op=None):
    """Set `output` with `name` to be outputted from the last step.

    Args:
      name: String, name to identify the output. Doesn't need to match tensor
        name.
      output: The tensors that should be outputted with `name`. See below for
        actual types supported.
      reduce_op: Reduction method to use to reduce outputs from multiple
        replicas. Required if `set_last_step_output` is called in a replica
        context. Optional in cross_replica_context.
        When present, the outputs from all the replicas are reduced using the
        current distribution strategy's `reduce` method. Hence, the type of
        `output` must be what's supported by the corresponding `reduce` method.
        For e.g. if using MirroredStrategy and reduction is set, output
        must be a `PerReplica` value.
        The reduce method is also recorded in a dictionary
        `_last_step_outputs_reduce_ops` for later interpreting of the
        outputs as already reduced or not.
    """
    if distribution_strategy_context.in_cross_replica_context():
      self._last_step_outputs_reduce_ops[name] = reduce_op
      if reduce_op is None:
        self._last_step_outputs[name] = output
      else:
        distribution = distribution_strategy_context.get_strategy()
        self._last_step_outputs[name] = distribution.reduce(reduce_op, output)
    else:
      assert reduce_op is not None
      def merge_fn(distribution, value):
        self._last_step_outputs[name] = distribution.reduce(reduce_op, value)
        # Setting this inside the `merge_fn` because all replicas share the same
        # context object, so it's more robust to set it only once (even if all
        # the replicas are trying to set the same value).
        self._last_step_outputs_reduce_ops[name] = reduce_op

      distribution_strategy_context.get_replica_context().merge_call(
          merge_fn, args=(output,))

  @property
  def non_tensor_outputs(self):
    """A dictionary consisting of any non tensor outputs to be captured."""
    return self._non_tensor_outputs

  def set_non_tensor_output(self, name, output):
    """Set `output` with `name` to be captured as a non tensor output."""
    if distribution_strategy_context.in_cross_replica_context():
      self._non_tensor_outputs[name] = output
    else:
      def merge_fn(distribution, value):
        # NOTE(priyag): For non tensor outputs, we simply return all the values
        # in a list as reduction doesn't make sense on non tensors.
        self._non_tensor_outputs[name] = distribution.unwrap(value)
      distribution_strategy_context.get_replica_context().merge_call(
          merge_fn, args=(output,))