#   Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import unittest
import numpy as np
from op_test import OpTest
import paddle

class TestAllcloseOp(OpTest):
    def set_args(self):
        self.input = np.array([10000., 1e-07]).astype("float32")
        self.other = np.array([10000.1, 1e-08]).astype("float32")
        self.rtol = 1e-05
        self.atol = 1e-08
        self.equal_nan = False

    def setUp(self):
        self.set_args()
        self.op_type = "allclose"
        self.inputs = {'Input': self.input, 'Other': self.other}
        self.attrs = {
            'rtol': self.rtol,
            'atol': self.atol,
            'equal_nan': self.equal_nan
        }
        self.outputs = {
            'Out': np.array([
                np.allclose(
                    self.inputs['Input'],
                    self.inputs['Other'],
                    rtol=self.rtol,
                    atol=self.atol,
                    equal_nan=self.equal_nan)
            ])
        }

    def test_check_output(self):
        self.check_output()

class TestAllcloseOpSmallNum(TestAllcloseOp):
    def set_args(self):
        self.input = np.array([10000., 1e-08]).astype("float32")
        self.other = np.array([10000.1, 1e-09]).astype("float32")
        self.rtol = 1e-05
        self.atol = 1e-08
        self.equal_nan = False

class TestAllcloseOpNanFalse(TestAllcloseOp):
    def set_args(self):
        self.input = np.array([1.0, float('nan')]).astype("float32")
        self.other = np.array([1.0, float('nan')]).astype("float32")
        self.rtol = 1e-05
        self.atol = 1e-08
        self.equal_nan = False

class TestAllcloseOpNanTrue(TestAllcloseOp):
    def set_args(self):
        self.input = np.array([1.0, float('nan')]).astype("float32")
        self.other = np.array([1.0, float('nan')]).astype("float32")
        self.rtol = 1e-05
        self.atol = 1e-08
        self.equal_nan = True

class TestAllcloseDygraph(unittest.TestCase):
    def test_api_case(self):
        paddle.disable_static()
        x_data = np.random.rand(10, 10)
        y_data = np.random.rand(10, 10)
        x = paddle.to_tensor(x_data)
        y = paddle.to_tensor(y_data)
        out = paddle.allclose(x, y, rtol=1e-05, atol=1e-08)
        expected_out = np.allclose(x_data, y_data, rtol=1e-05, atol=1e-08)
        self.assertTrue((out.numpy() == expected_out).all(), True)
        paddle.enable_static()

class TestAllcloseError(unittest.TestCase):
    def test_input_dtype(self):
        def test_x_dtype():
            with paddle.static.program_guard(paddle.static.Program(),
                                             paddle.static.Program()):
                x = paddle.fluid.data(name='x', shape=[10, 10], dtype='float16')
                y = paddle.fluid.data(name='y', shape=[10, 10], dtype='float64')
                result = paddle.allclose(x, y)

        self.assertRaises(TypeError, test_x_dtype)

        def test_y_dtype():
            with paddle.static.program_guard(paddle.static.Program(),
                                             paddle.static.Program()):
                x = paddle.fluid.data(name='x', shape=[10, 10], dtype='float64')
                y = paddle.fluid.data(name='y', shape=[10, 10], dtype='int32')
                result = paddle.allclose(x, y)

        self.assertRaises(TypeError, test_y_dtype)

    def test_attr(self):
        x = paddle.fluid.data(name='x', shape=[10, 10], dtype='float64')
        y = paddle.fluid.data(name='y', shape=[10, 10], dtype='float64')

        def test_rtol():
            result = paddle.allclose(x, y, rtol=True)

        self.assertRaises(TypeError, test_rtol)

        def test_atol():
            result = paddle.allclose(x, y, rtol=True)

        self.assertRaises(TypeError, test_atol)

        def test_equal_nan():
            result = paddle.allclose(x, y, equal_nan=1)

        self.assertRaises(TypeError, test_equal_nan)

if __name__ == "__main__":
    unittest.main()


# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from auto_scan_test import MkldnnAutoScanTest, SkipReasons
from program_config import TensorConfig, ProgramConfig, OpConfig
import numpy as np
import paddle.inference as paddle_infer
from functools import partial
from typing import Optional, List, Callable, Dict, Any, Set
import unittest

import hypothesis
from hypothesis import given, settings, seed, example, assume
import hypothesis.strategies as st

class TestMkldnnMatmulv2Op(MkldnnAutoScanTest):
    def is_program_valid(self, program_config: ProgramConfig) -> bool:
        if len(program_config.inputs["input_data2"].shape) == 4:
            if program_config.inputs["input_data1"].shape[
                    -4] != 1 and program_config.inputs["input_data2"].shape[
                        -4] != 1:
                if program_config.inputs["input_data1"].shape[
                        -4] != program_config.inputs["input_data2"].shape[-4]:
                    return False

        if program_config.inputs["input_data1"].shape[
                -3] != 1 and program_config.inputs["input_data2"].shape[
                    -3] != 1:
            if program_config.inputs["input_data1"].shape[
                    -3] != program_config.inputs["input_data2"].shape[-3]:
                return False
        return True

    def sample_program_configs(self, *args, **kwargs):
        def generate_input(type, *args, **kwargs):
            transpose_X = kwargs["transpose_X"]
            transpose_Y = kwargs["transpose_Y"]
            batch_size1 = kwargs["batch_size1"]
            batch_size2 = kwargs["batch_size2"]
            channel1 = kwargs["channel1"]
            channel2 = kwargs["channel2"]
            input_dim = kwargs["input_dim"]
            y_dim_len = kwargs["y_dim_len"]
            if transpose_X and transpose_Y:
                shape_x = [batch_size1, channel1, input_dim, 32]
                if y_dim_len == 4:
                    shape_y = [batch_size2, channel2, 64, input_dim]
                elif y_dim_len == 3:
                    shape_y = [channel2, 64, input_dim]
            elif transpose_X:
                shape_x = [batch_size1, channel1, input_dim, 32]
                if y_dim_len == 4:
                    shape_y = [batch_size2, channel2, input_dim, 64]
                elif y_dim_len == 3:
                    shape_y = [channel2, input_dim, 64]
            elif transpose_Y:
                shape_x = [batch_size1, channel1, 32, input_dim]
                if y_dim_len == 4:
                    shape_y = [batch_size2, channel2, 8, input_dim]
                elif y_dim_len == 3:
                    shape_y = [channel2, 8, input_dim]
            else:
                shape_x = [batch_size1, channel1, 32, input_dim]
                if y_dim_len == 4:
                    shape_y = [batch_size2, channel2, input_dim, 16]
                elif y_dim_len == 3:
                    shape_y = [channel2, input_dim, 16]

            if type == "x":
                return np.random.random(shape_x).astype(np.float32)
            else:
                return np.random.random(shape_y).astype(np.float32)

        matmul_op = OpConfig(
            type="matmul_v2",
            inputs={"X": ["input_data1"],
                    "Y": ["input_data2"]},
            outputs={"Out": ["matmul_output"]},
            attrs={
                "trans_x": kwargs["transpose_X"],
                "trans_y": kwargs["transpose_Y"],
                "fused_reshape_X": [],
                "fused_reshape_Y": [],
                "fused_transpose_X": [],
                "fused_transpose_Y": [],
                "fused_reshape_Out": [],
                "fused_transpose_Out": []
            })

        program_config = ProgramConfig(
            ops=[matmul_op],
            weights={},
            inputs={
                "input_data1": TensorConfig(data_gen=partial(
                    generate_input, "x", *args, **kwargs)),
                "input_data2": TensorConfig(data_gen=partial(
                    generate_input, "y", *args, **kwargs))
            },
            outputs=["matmul_output"])

        yield program_config

    def sample_predictor_configs(self, program_config):
        config = self.create_inference_config(use_mkldnn=True)
        yield config, (1e-5, 1e-5)

    @given(
        transpose_X=st.booleans(),
        transpose_Y=st.booleans(),
        y_dim_len=st.sampled_from([3, 4]),
        batch_size1=st.integers(
            min_value=1, max_value=4),
        batch_size2=st.integers(
            min_value=1, max_value=4),
        channel1=st.sampled_from([1, 16, 32, 64]),
        channel2=st.sampled_from([1, 16, 32, 64]),
        input_dim=st.sampled_from([16, 32, 64]))
    def test(self, *args, **kwargs):
        self.run_test(*args, **kwargs)

if __name__ == "__main__":
    unittest.main()


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

import pandas as pd
get_ipython().run_line_magic('matplotlib', 'notebook')
from matplotlib import pyplot as plt
from matplotlib import animation as anim, rc
import numpy as np
from scipy.linalg import block_diag

# # Load four letter words

# Kucera & Francis Word Pool downloaded from http://memory.psych.upenn.edu/files/wordpools/kfpool.txt
kf_corpus = pd.read_csv('kfpool.txt', header=None, sep=' ', names=['word', 'frequency'])

kf_corpus

# Let's see how many four letter words there are in the corpus.

(kf_corpus.word.str.len() == 4).sum()

# That is more than 1179 words reported in McClelland & Rumelhart, 1981. Probably they filtered by frequency.

for i in range(7):
    word_count = len(kf_corpus[(kf_corpus.word.str.len() == 4) & (kf_corpus.frequency > i)])
    print(f'There are {word_count} four letter words with frequency larger than {i}')

# Frequency threshold of 4 yields the number closest to 1179.

four_letter_words = kf_corpus[(kf_corpus.word.str.len() == 4) & (kf_corpus.frequency > 4)]
len(four_letter_words)

# # Encode letters as feature bundles

# In the original model, the input letters came from a simplified font in which each letter is composed of a number of simplified line strokes (*features*) as in the following image:
#
# ![Font from Rumelhar & Siple, 1974](rumelhart-siple-font.jpg)

# Here are all the features numbered from 0 to 13:
#
# ![Numbered line features](line_features.png)

# A list of letters specifying which features it is composed of.

feature_numbers = {
    'A': [0, 1, 2, 3, 4, 6, 8],
    'B': [2, 3, 4, 5, 7, 8, 9],
    'C': [0, 1, 2, 5],
    'D': [2, 3, 4, 5, 7, 9],
    'E': [0, 1, 2, 5, 6],
    'F': [0, 1, 2, 6],
    'G': [0, 1, 2, 4, 5, 8],
    'H': [0, 1, 3, 4, 6, 8],
    'I': [2, 5, 7, 9],
    'J': [0, 3, 4, 5],
    'K': [0, 1, 6, 11, 12],
    'L': [0, 1, 5],
    'M': [0, 1, 3, 4, 10, 11],
    'N': [0, 1, 3, 4, 10, 12],
    'O': [0, 1, 2, 3, 4, 5],
    'P': [0, 1, 2, 3, 6, 8],
    'Q': [0, 1, 2, 3, 4, 5, 12],
    'R': [0, 1, 2, 3, 6, 8, 12],
    'S': [1, 2, 4, 5, 6, 8],
    'T': [2, 7, 9],
    'U': [0, 1, 3, 4, 5],
    'V': [0, 1, 11, 13],
    'W': [0, 1, 3, 4, 12, 13],
    'X': [10, 11, 12, 13],
    'Y': [9, 10, 11],
    'Z': [2, 5, 11, 13]
}

# Let's draw all the letter to check that we got everything right. First, we need the coordinates of all features.

feature_coordinates = {
    0: [(-1, -1), (-1, 0)],
    1: [(-1, 0), (-1, 1)],
    2: [(-1, 1), (1, 1)],
    3: [(1, 1), (1, 0)],
    4: [(1, 0), (1, -1)],
    5: [(1, -1), (-1, -1)],
    6: [(0, 0), (-1, 0)],
    7  : [(0, 0), (0, 1)],
    8 : [(0, 0), (1, 0)],
    9 : [(0, 0), (0, -1)],
    10 : [(0, 0), (-1, 1)],
    11 : [(0, 0), (1, 1)],
    12 : [(0 ,0), (1, -1)],
    13 : [(0, 0), (-1, -1)]
}

# Function that draws one letter:

def draw_letter_features(feature_list, feature_coordinates, axes, color='k'):
    axes.grid()
    axes.set(xlim=(-1.2, 1.2), ylim=(-1.2, 1.2))

    # Remove ticks and labels from the axes
    axes.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)

    for line_nmbr in feature_list:
        line_coords = feature_coordinates[line_nmbr]
        x_values = [line_coords[0][0], line_coords[1][0]]
        y_values = [line_coords[0][1], line_coords[1][1]]
        axes.plot(x_values, y_values, color = color, linewidth = 4)

fig = plt.figure()
axes = fig.gca()
draw_letter_features(feature_list=feature_numbers['A'],
            feature_coordinates=feature_coordinates,
            axes=axes)

# Now, let's draw all of them.

def draw_letter_features_all(letter_list, feature_numbers, feature_coordinates):
    N_letters = len(letter_list)
    fig, axs = plt.subplots(3, 9)
    for axes, lttr in zip(axs.flatten()[:N_letters], letter_list):
        plt.sca(axes)
        draw_letter_features(feature_numbers[lttr], feature_coordinates, axes)

    # Clear the last empty axes
    axs.flatten()[-1].axis('off');

draw_letter_features_all(sorted(feature_numbers.keys())[:26], feature_numbers, feature_coordinates)

# ![Font from Rumelhar & Siple, 1974](rumelhart-siple-font.jpg)

# Looks correct.

# # Feature perception

M = 1.0  # max activation
m = -0.2  # min activation
theta = 0.07  # decay rate
r_feature = 0  # resting state activation

feature_count = len(list(feature_coordinates.keys()))
position_count = 4
feature_nodes = np.zeros((position_count, feature_count))

# We'll have to represent the letters as a list of binary feature flags.

features_binary = {
    letter: [1 if i in feature_list else 0 for i in range(feature_count)]
    for letter, feature_list in feature_numbers.items()}

features_binary

def present_word(word: str):
    """
    Activates features corresponding to the letters in the word
    """
    global feature_nodes
    features_present = np.array([features_binary[letter] for letter in word])
    feature_nodes = M * features_present

def f():
    global feature_nodes
    decay = (feature_nodes - r_feature) * theta
    feature_nodes = feature_nodes - decay

def draw_features(fig_axs=None, title=None):
    if fig_axs is None:
        fig, axs = plt.subplots(ncols=4, nrows=1)
    else:
        fig, axs = fig_axs

    fig.suptitle(title)

    for pos_features, axes in zip(feature_nodes, axs):
        a = max(pos_features)  # activation level
        color = (1 - a, 1 - a, 1 - a)
        draw_letter_features(feature_list=np.nonzero(pos_features)[0],
                    feature_coordinates=feature_coordinates,
                    axes=axes,
                    color=color)

np.set_printoptions(precision=2, floatmode='fixed')
present_word('WORK')
print(feature_nodes)

fig, axs = plt.subplots(ncols=4, nrows=1)
for t in range(10):
    f()
    draw_features(fig_axs=(fig, axs), title=f'\nafter {t + 1} cycles:')
    fig.canvas.draw()

# # Letter layer

letter_count = len(list(feature_numbers.keys()))
position_count = 4
r_letter = 0
letter_nodes = np.ones((position_count, letter_count)) * r_letter

def run_cycle():
    global feature_nodes, letter_nodes

    feature_decay, letter_decay = calculate_decay()
    feature_neighbours_effect, letter_neighbours_effect = calculate_neighbours_effect()

    feature_nodes += - feature_decay + feature_neighbours_effect
    letter_nodes += - letter_decay + letter_neighbours_effect

def calculate_decay():
    feature_decay = (feature_nodes - r_feature) * theta
    letter_decay = (letter_nodes - r_letter) * theta
    return feature_decay, letter_decay

def calculate_layer_to_layer_input(layer_A, layer_B, weights):
    """
    Calculates net input from layer_A to layer_B with weights connecting them.
    This function is necessary because we prefer to keep nodes in 4 x N arrays instead of long vectors
    """
    # Only the active (activation > 0) nodes get to send signals.
    # Inhibitory connections have negative weights in this implementation
    return (layer_A.ravel() * (layer_A.ravel() > 0) @ weights).reshape(layer_B.shape)

def calculate_neighbours_effect():
    # There are no connections to the feature level except for the visual input
    feature_neighbours_effect = np.zeros(feature_nodes.shape)

    # Equation 1
    # Only the active (activation > 0) nodes get to send signals.

    # This won't work! feature_nodes and letter_nodes would need to be vectors for this
    net_input = (calculate_layer_to_layer_input(feature_nodes, letter_nodes, feature_to_letter_weights)
               + calculate_layer_to_layer_input(letter_nodes, letter_nodes, letter_to_letter_weights))

    # Equation 2 and 3
    letter_neighbours_effect = np.where(
        net_input > 0,
        net_input * (M - letter_nodes),
        net_input * (letter_nodes - m)
    )

    return feature_neighbours_effect, letter_neighbours_effect

# Letter-to-letter weights were set to zero so this one is easy.

letter_to_letter_weights = np.zeros((letter_nodes.size, letter_nodes.size))

# Each feature excites all the letter that contain it and inhibits all the others.

feature_to_letter_excitatory = 0.005
feature_to_letter_inhibitory = 0.15

# Let's first build a binary array from features to letters in one position:

is_excitatory = np.array([features_binary[letter] for letter in sorted(features_binary.keys())]).T

is_excitatory

feature_to_letter_weights_1 = np.where(
    is_excitatory,
    feature_to_letter_excitatory,
    - feature_to_letter_inhibitory
)

feature_to_letter_weights_1

# Now we just have to duplicate this array for each position. Since the weights are zeros across the four positions, we need a block-diagonal matrix made of four `feature_to_letter_weights_1`s along the diagonal.

feature_to_letter_weights = block_diag(*[feature_to_letter_weights_1 for _ in range(4)])

feature_to_letter_weights.shape

# Each non-grey rectangle corresponds to weights from 14 features in a position to the 26 letters in the same position.
# All the other weights are zero.
# NB: Excitatory weights are close to 0, so they are grey as well.

fig = plt.figure()
axes = fig.gca()
axes.matshow(feature_to_letter_weights, cmap='Set1')

alphabet = sorted(features_binary.keys())

# Run for a bit and save letter activations.

def present_word_and_run(word, cycle_count):
    global letter_nodes
    present_word(word)
    # reset letter nodes
    letter_nodes = np.ones((position_count, letter_count)) * r_letter

    # "1 + " to save the initial state
    history_shape = [1 + cycle_count] + list(letter_nodes.shape)
    letters_history = np.empty(history_shape)

    letters_history[0] = letter_nodes
    for t in range(cycle_count):
        run_cycle()
        letters_history[t + 1] = letter_nodes

    return letters_history

cycle_count = 20
letters_history = present_word_and_run(word='WORK', cycle_count=cycle_count)

# Plot

def setup_letter_plot(test=False):
    fig = plt.figure(figsize=(6, 6))
    axes = fig.gca()

    axes.set_xlim((0, 4))
    axes.set_ylim((0, 26))
    axes.invert_yaxis()

    text_objects = [[axes.text(y=(i + 0.8), x=(pos + 0.2), s='A' if test else '', size=10)
                     for i  in range(len(alphabet))]
                    for pos in range(4)]

    return fig, axes, text_objects

setup_letter_plot(test=True);

def update_letter_plot(text_objects, t, axes=None, title=None):
    if not axes:
        fig = plt.figure(figsize=(4, 10))
        axes = fig.gca()

    axes.set_title(title)

    for pos, (letter_nodes_, text_objects_) in enumerate(zip(letters_history[t], text_objects)):
        for i, (letter, activation, text_object) in enumerate(zip(alphabet, letter_nodes_, text_objects_)):
            text_object.set_text(letter)
            color = tuple([min(1 - activation, 1)] * 3)
            text_object.set_color(color)

    return (text_object for row in text_objects for text_object in row)

get_ipython().run_cell_magic('capture', '', "fig, axes, text_objects = setup_letter_plot();\n\nline_ani = anim.FuncAnimation(fig, \n                              lambda t: update_letter_plot(text_objects, t, axes=axes, title=f'\\nafter {t + 1} cycles:'), \n                              frames=range(0, cycle_count + 1), blit=True, repeat=True)\nrc('animation', html='jshtml')")

line_ani

# "O" and "Q" are equally activated becase all of the "O" features are present in "Q" as well.
# "Q" is not inhibited because only features that are not present in "Q" could do that.
# Let's check that "WQRK" would not activate "O" because "Q" does have a feature absent in "O".

cycle_count = 20
letters_history = present_word_and_run(word='WQRK', cycle_count=cycle_count)

get_ipython().run_cell_magic('capture', '', "fig, axes, text_objects = setup_letter_plot();\n\nline_ani = anim.FuncAnimation(fig, \n                              lambda t: update_letter_plot(text_objects, t, axes=axes, title=f'\\nafter {t + 1} cycles:'), \n                              frames=range(0, cycle_count + 1), blit=True, repeat=True)\nrc('animation', html='jshtml')")

line_ani

# "O" was inhibited by the tail of "Q".


# 2019-11-12 13:20:54(JST)
import sys

# import collections
# import math
# from string import ascii_lowercase, ascii_uppercase, digits
# from bisect import bisect_left as bi_l, bisect_right as bi_r
# import itertools
# from functools import reduce
# import operator as op
# from scipy.misc import comb # float
# import numpy as np

def main():
    n, *l = (int(x) for x in sys.stdin.read().split())
    l.sort()
    if l[-1] < sum(l[:-1]):
        ans = 'Yes'
    else:
        ans = 'No'
    print(ans)

if __name__ == "__main__":
    main()


# Copyright 2019 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
r"""
This module contains a base class for constructing Qiskit devices for PennyLane.
"""
# pylint: disable=too-many-instance-attributes

import abc
import functools
import inspect
import itertools
import warnings
from collections import OrderedDict

import numpy as np
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
from qiskit import extensions as ex
from qiskit.circuit.measure import measure
from qiskit.compiler import assemble, transpile
from qiskit.converters import circuit_to_dag, dag_to_circuit

from pennylane import Device, QuantumFunctionError
from pennylane.operation import Sample

from ._version import __version__

@functools.lru_cache()
def pauli_eigs(n):
    r"""Returns the eigenvalues for :math:`A^{\otimes n}`,
    where :math:`A` is any operator that shares eigenvalues
    with the Pauli matrices.

    Args:
        n (int): number of wires

    Returns:
        array[int]: eigenvalues of :math:`Z^{\otimes n}`
    """
    if n == 1:
        return np.array([1, -1])
    return np.concatenate([pauli_eigs(n - 1), -pauli_eigs(n - 1)])

QISKIT_OPERATION_MAP = {
    # native PennyLane operations also native to qiskit
    "PauliX": ex.XGate,
    "PauliY": ex.YGate,
    "PauliZ": ex.ZGate,
    "Hadamard": ex.HGate,
    "CNOT": ex.CXGate,
    "CZ": ex.CZGate,
    "SWAP": ex.SwapGate,
    "RX": ex.RXGate,
    "RY": ex.RYGate,
    "RZ": ex.RZGate,
    "S": ex.SGate,
    "T": ex.TGate,
    # Adding the following for conversion compatibility
    "CSWAP": ex.CSwapGate,
    "CRX": ex.CRXGate,
    "CRY": ex.CRYGate,
    "CRZ": ex.CRZGate,
    "PhaseShift": ex.U1Gate,
    "QubitStateVector": ex.Initialize,
    "U2": ex.U2Gate,
    "U3": ex.U3Gate,
    "Toffoli": ex.CCXGate,
    "QubitUnitary": ex.UnitaryGate,
}

# Separate dictionary for the inverses as the operations dictionary needs
# to be invertable for the conversion functionality to work
QISKIT_OPERATION_INVERSES_MAP = {k + ".inv": v for k, v in QISKIT_OPERATION_MAP.items()}

class QiskitDevice(Device, abc.ABC):
    r"""Abstract Qiskit device for PennyLane.

    Args:
        wires (int): The number of qubits of the device
        provider (Provider): The Qiskit simulation provider
        backend (str): the desired backend
        shots (int): Number of circuit evaluations/random samples used
            to estimate expectation values of observables.

    Keyword Args:
        name (str): The name of the circuit. Default ``'circuit'``.
        compile_backend (BaseBackend): The backend used for compilation. If you wish
            to simulate a device compliant circuit, you can specify a backend here.
        analytic (bool): For statevector backends, determines if the
            expectation values and variances are to be computed analytically.
            Default value is ``False``.
    """
    name = "Qiskit PennyLane plugin"
    pennylane_requires = ">=0.8.1"
    version = "0.9.0-dev"
    plugin_version = __version__
    author = "Xanadu"

    _capabilities = {"model": "qubit", "tensor_observables": True, "inverse_operations": True}
    _operation_map = {**QISKIT_OPERATION_MAP, **QISKIT_OPERATION_INVERSES_MAP}
    _state_backends = {"statevector_simulator", "unitary_simulator"}
    """set[str]: Set of backend names that define the backends
    that support returning the underlying quantum statevector"""

    operations = set(_operation_map.keys())
    observables = {"PauliX", "PauliY", "PauliZ", "Identity", "Hadamard", "Hermitian"}

    hw_analytic_warning_message = (
        "The analytic calculation of expectations and variances "
        "is only supported on statevector backends, not on the {}. "
        "The obtained result is based on sampling."
    )

    _eigs = {}

    def __init__(self, wires, provider, backend, shots=1024, **kwargs):
        super().__init__(wires=wires, shots=shots)

        self.analytic = kwargs.pop("analytic", False)

        if "verbose" not in kwargs:
            kwargs["verbose"] = False

        self.provider = provider
        self.backend_name = backend
        self._capabilities["backend"] = [b.name() for b in self.provider.backends()]

        # check that backend exists
        if backend not in self._capabilities["backend"]:
            raise ValueError(
                "Backend '{}' does not exist. Available backends "
                "are:\n {}".format(backend, self._capabilities["backend"])
            )

        # perform validation against backend
        b = self.backend
        if wires > b.configuration().n_qubits:
            raise ValueError(
                "Backend '{}' supports maximum {} wires".format(backend, b.configuration().n_qubits)
            )

        # Inner state
        self._reg = QuantumRegister(wires, "q")
        self._creg = ClassicalRegister(wires, "c")
        self._circuit = None
        self._current_job = None
        self._state = None  # statevector of a simulator backend

        # job execution options
        self.memory = False  # do not return samples, just counts

        # determine if backend supports backend options and noise models,
        # and properly put together backend run arguments
        s = inspect.signature(b.run)
        self.run_args = {}
        self.compile_backend = None

        if "compile_backend" in kwargs:
            self.compile_backend = kwargs.pop("compile_backend")

        if "noise_model" in kwargs:
            if "noise_model" in s.parameters:
                self.run_args["noise_model"] = kwargs.pop("noise_model")
            else:
                raise ValueError("Backend {} does not support noisy simulations".format(backend))

        if "backend_options" in s.parameters:
            self.run_args["backend_options"] = kwargs

        self.reset()

    @property
    def backend(self):
        """The Qiskit simulation backend object"""
        return self.provider.get_backend(self.backend_name)

    def apply(self, operation, wires, par):
        mapped_operation = self._operation_map[operation]

        qregs = [self._reg[i] for i in wires]

        if operation == "QubitStateVector":

            if self.backend_name == "unitary_simulator":
                raise QuantumFunctionError(
                    "The QubitStateVector operation is not supported on the unitary simulator backend."
                )

            if len(par[0]) != 2 ** len(wires):
                raise ValueError("State vector must be of length 2**wires.")

            qregs = list(reversed(qregs))

            # TODO: Once a fix is available in Qiskit-Aer, remove the following:
            par = (x.tolist() for x in par if isinstance(x, np.ndarray))

        if operation == "QubitUnitary":

            if len(par[0]) != 2 ** len(wires):
                raise ValueError("Unitary matrix must be of shape (2**wires, 2**wires).")

            qregs = list(reversed(qregs))

        dag = circuit_to_dag(QuantumCircuit(self._reg, self._creg, name=""))
        gate = mapped_operation(*par)

        if operation.endswith(".inv"):
            gate = gate.inverse()

        dag.apply_operation_back(gate, qargs=qregs)
        qc = dag_to_circuit(dag)
        self._circuit = self._circuit + qc

    def compile(self):
        """Compile the quantum circuit to target
        the provided compile_backend. If compile_backend is None,
        then the target is simply the backend."""
        compile_backend = self.compile_backend or self.backend
        compiled_circuits = transpile(self._circuit, backend=compile_backend)
        return assemble(
            experiments=compiled_circuits,
            backend=compile_backend,
            shots=self.shots,
            memory=self.memory,
        )

    def run(self, qobj):
        """Run the compiled circuit, and query the result."""
        self._current_job = self.backend.run(qobj, **self.run_args)
        result = self._current_job.result()

        if self.backend_name in self._state_backends:
            self._state = self._get_state(result)

    def _get_state(self, result):
        """Returns the statevector for state simulator backends.

        Args:
            result (qiskit.Result): result object

        Returns:
            array[float]: size ``(2**num_wires,)`` statevector
        """
        if self.backend_name == "statevector_simulator":
            state = np.asarray(result.get_statevector())

        elif self.backend_name == "unitary_simulator":
            unitary = np.asarray(result.get_unitary())
            initial_state = np.zeros([2 ** self.num_wires])
            initial_state[0] = 1

            state = unitary @ initial_state

        # reverse qubit order to match PennyLane convention
        return state.reshape([2] * self.num_wires).T.flatten()

    def rotate_basis(self, obs, wires, par):
        """Rotates the specified wires such that they
        are in the eigenbasis of the provided observable.

        Args:
            observable (str): the name of an observable
            wires (List[int]): wires the observable is measured on
            par (List[Any]): parameters of the observable
        """
        if obs == "PauliX":
            # X = H.Z.H
            self.apply("Hadamard", wires=wires, par=[])

        elif obs == "PauliY":
            # Y = (HS^)^.Z.(HS^) and S^=SZ
            self.apply("PauliZ", wires=wires, par=[])
            self.apply("S", wires=wires, par=[])
            self.apply("Hadamard", wires=wires, par=[])

        elif obs == "Hadamard":
            # H = Ry(-pi/4)^.Z.Ry(-pi/4)
            self.apply("RY", wires, [-np.pi / 4])

        elif obs == "Hermitian":
            # For arbitrary Hermitian matrix H, let U be the unitary matrix
            # that diagonalises it, and w_i be the eigenvalues.
            Hmat = par[0]
            Hkey = tuple(Hmat.flatten().tolist())

            if Hkey in self._eigs:
                # retrieve eigenvectors
                U = self._eigs[Hkey]["eigvec"]
            else:
                # store the eigenvalues corresponding to H
                # in a dictionary, so that they do not need to
                # be calculated later
                w, U = np.linalg.eigh(Hmat)
                self._eigs[Hkey] = {"eigval": w, "eigvec": U}

            # Perform a change of basis before measuring by applying U^ to the circuit
            self.apply("QubitUnitary", wires, [U.conj().T])

    def pre_measure(self):
        for e in self.obs_queue:
            # Add unitaries if a different expectation value is given
            # Exclude unitary_simulator as it does not support memory=True
            if (
                hasattr(e, "return_type")
                and e.return_type == Sample
                and self.backend_name != "unitary_simulator"
            ):
                self.memory = True  # make sure to return samples

            if isinstance(e.name, list):
                # tensor product
                for n, w, p in zip(e.name, e.wires, e.parameters):
                    self.rotate_basis(n, w, p)
            else:
                # single wire observable
                self.rotate_basis(e.name, e.wires, e.parameters)

        if self.backend_name not in self._state_backends:
            # Add measurements if they are needed
            for qr, cr in zip(self._reg, self._creg):
                measure(self._circuit, qr, cr)

        qobj = self.compile()
        self.run(qobj)

    def expval(self, observable, wires, par):
        if self.backend_name in self._state_backends and self.analytic:
            # exact expectation value
            eigvals = self.eigvals(observable, wires, par)
            prob = np.fromiter(self.probability(wires=wires).values(), dtype=np.float64)
            return (eigvals @ prob).real

        if self.analytic:
            # Raise a warning if backend is a hardware simulator
            warnings.warn(self.hw_analytic_warning_message.format(self.backend), UserWarning)

        # estimate the ev
        return np.mean(self.sample(observable, wires, par))

    def var(self, observable, wires, par):
        if self.backend_name in self._state_backends and self.analytic:
            # exact variance value
            eigvals = self.eigvals(observable, wires, par)
            prob = np.fromiter(self.probability(wires=wires).values(), dtype=np.float64)
            return (eigvals ** 2) @ prob - (eigvals @ prob).real ** 2

        if self.analytic:
            # Raise a warning if backend is a hardware simulator
            warnings.warn(self.hw_analytic_warning_message.format(self.backend), UserWarning)

        return np.var(self.sample(observable, wires, par))

    def sample(self, observable, wires, par):
        if observable == "Identity":
            return np.ones([self.shots])

        # branch out depending on the type of backend
        if self.backend_name in self._state_backends:
            # software simulator. Need to sample from probabilities.
            eigvals = self.eigvals(observable, wires, par)
            prob = np.fromiter(self.probability(wires=wires).values(), dtype=np.float64)
            return np.random.choice(eigvals, self.shots, p=prob)

        # a hardware simulator
        if self.memory:
            # get the samples
            samples = self._current_job.result().get_memory()

            # reverse qubit order to match PennyLane convention
            samples = np.vstack([np.array([int(i) for i in s[::-1]]) for s in samples])

        else:
            # Need to convert counts into samples
            samples = np.vstack(
                [np.vstack([s] * int(self.shots * p)) for s, p in self.probability().items()]
            )

        if isinstance(observable, str) and observable in {"PauliX", "PauliY", "PauliZ", "Hadamard"}:
            return 1 - 2 * samples[:, wires[0]]

        eigvals = self.eigvals(observable, wires, par)
        wires = np.hstack(wires)
        res = samples[:, np.array(wires)]
        samples = np.zeros([self.shots])

        for w, b in zip(eigvals, itertools.product([0, 1], repeat=len(wires))):
            samples = np.where(np.all(res == b, axis=1), w, samples)

        return samples

    @property
    def state(self):
        return self._state

    def probability(self, wires=None):
        """Return the (marginal) probability of each computational basis
        state from the last run of the device.

        Args:
            wires (Sequence[int]): Sequence of wires to return
                marginal probabilities for. Wires not provided
                are traced out of the system.

        Returns:
            OrderedDict[tuple, float]: Dictionary mapping a tuple representing the state
            to the resulting probability. The dictionary should be sorted such that the
            state tuples are in lexicographical order.
        """
        # Note: Qiskit uses the convention that the first qubit is the
        # least significant qubit.
        if self._current_job is None:
            return None

        if self.backend_name in self._state_backends:
            # statevector simulator
            prob = np.abs(self.state.reshape([2] * self.num_wires)) ** 2
        else:
            # hardware simulator
            result = self._current_job.result()

            # sort the counts and reverse qubit order to match PennyLane convention
            nonzero_prob = {
                tuple(int(i) for i in s[::-1]): c / self.shots
                for s, c in result.get_counts().items()
            }

            if wires is None:
                # marginal probabilities not required
                return OrderedDict(tuple(sorted(nonzero_prob.items())))

            prob = np.zeros([2] * self.num_wires)

            for s, p in tuple(sorted(nonzero_prob.items())):
                prob[s] = p

        wires = wires or range(self.num_wires)
        wires = np.hstack(wires)

        basis_states = itertools.product(range(2), repeat=len(wires))
        inactive_wires = list(set(range(self.num_wires)) - set(wires))
        prob = np.apply_over_axes(np.sum, prob, inactive_wires).flatten()
        return OrderedDict(zip(basis_states, prob))

    def eigvals(self, observable, wires, par):
        """Determine the eigenvalues of observable(s).

        Args:
            observable (str, List[str]): the name of an observable,
                or a list of observables representing a tensor product
            wires (List[int]): wires the observable(s) is measured on
            par (List[Any]): parameters of the observable(s)

        Returns:
            array[float]: an array of size ``(len(wires),)`` containing the
            eigenvalues of the observable
        """
        # the standard observables all share a common eigenbasis {1, -1}
        # with the Pauli-Z gate/computational basis measurement
        standard_observables = {"PauliX", "PauliY", "PauliZ", "Hadamard"}

        # observable should be Z^{\otimes n}
        eigvals = pauli_eigs(len(wires))

        if isinstance(observable, list):
            # tensor product of observables

            # check if there are any non-standard observables (such as Identity, Hadamard)
            if set(observable) - standard_observables:
                # Tensor product of observables contains a mixture
                # of standard and non-standard observables
                eigvals = np.array([1])

                # group the observables into subgroups, depending on whether
                # they are in the standard observables or not.
                for k, g in itertools.groupby(
                    zip(observable, wires, par), lambda x: x[0] in standard_observables
                ):
                    if k:
                        # Subgroup g contains only standard observables.
                        # Determine the size of the subgroup, by transposing
                        # the list, flattening it, and determining the length.
                        n = len([w for sublist in list(zip(*g))[1] for w in sublist])
                        eigvals = np.kron(eigvals, pauli_eigs(n))
                    else:
                        # Subgroup g contains only non-standard observables.
                        for ns_obs in g:
                            # loop through all non-standard observables
                            if ns_obs[0] == "Hermitian":
                                # Hermitian observable has pre-computed eigenvalues
                                p = ns_obs[2]
                                Hkey = tuple(p[0].flatten().tolist())
                                eigvals = np.kron(eigvals, self._eigs[Hkey]["eigval"])

                            elif ns_obs[0] == "Identity":
                                # Identity observable has eigenvalues (1, 1)
                                eigvals = np.kron(eigvals, np.array([1, 1]))

        elif observable == "Hermitian":
            # single wire Hermitian observable
            Hkey = tuple(par[0].flatten().tolist())
            eigvals = self._eigs[Hkey]["eigval"]

        elif observable == "Identity":
            # single wire identity observable
            eigvals = np.ones(2 ** len(wires))

        return eigvals

    def reset(self):
        self._circuit = QuantumCircuit(self._reg, self._creg, name="temp")
        self._state = None


# Copyright 2019 Cloudera, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# # Creating new columns in a pandas DataFrame

# Import modules and read games data
import numpy as np
import pandas as pd
games = pd.read_table('data/games/games.csv', sep=',')
games

# Use the DataFrame method `assign` to return the
# dataframe with a new column added to it.

# The new column can contain a scalar value (repeated in
# every row):
games.assign(tax_percent = 0.08875)

# Or, the new column can be calculated using an
# expression that uses the values in other columns. To
# do this, you need to reference the original DataFrame
# or use a lambda:
games \
  .assign(
    price_with_tax = np.round(
      games.list_price * 1.08875, 2
    )
  )

games \
  .assign(
    price_with_tax = lambda x:
      np.round(x.list_price * 1.08875, 2)
  )

# The latter option is better for chaining

# You can also use the quoted column name in square
# brackets. This is less concise but safer, because
# Python can interpret the dot notation to refer to
# an attribute or method of the DataFrame class
# instead of a column of the DataFrame
games.assign(under_ten_dollars = games.list_price < 10)
games.assign(under_ten_dollars = games['list_price'] < 10)

# You can create multiple columns with one call to the
# `assign` method
games \
  .assign(
    tax_percent = 0.08875,
    price_with_tax = lambda x:
      np.round(x.list_price * 1.08875, 2)
  )

# But you can't reference columns that you created in an
# `assign` in other expressions later in the same
# `assign`; for that, use multiple `assign`s
games \
  .assign(
    tax_percent = 0.08875
  ) \
  .assign(
    price_with_tax = lambda x:
      np.round(x.list_price * (1 + x.tax_percent), 2)
  )

# Alternatively, use the DataFrame method `eval`, which
# evaluates a string describing operations on DataFrame
# columns. Specify `inplace=False` to ensure that pandas
# does not mutate the existing DataFrame in place
games.eval(
  'price_with_tax = list_price * 1.08875',
  inplace=False
)

# However, many operations are not supported by `eval`.
# This code fails with the error `"round" is not a
# supported function`
#```python
#games.eval(
#  'price_with_tax = round(list_price * 1.08875, 2)',
#  inplace=False
#)
#```

# ## Replacing columns

# You can replace existing columns the same way you make
# new columns
games. \
  assign(
    name = lambda x: x.name.str.upper(),
    inventor = lambda x: x.inventor.str.lower()
  )

# ## Renaming columns

# To return a DataFrame with one or more columns renamed,
# use the `rename` method. For the `columns` argument,
# pass a dictionary in the form  `{'old_name':'new_name'}`
games.rename(columns = {'id':'game_id'})
games.rename(
  columns = {'id':'game_id', 'list_price':'price'}
)

# ## Removing columns

# To return a DataFrame with one or more columns removed,
# use the `drop` method, with `axis=1`
games.drop(['inventor', 'min_age'], axis=1)

# ## Replacing missing values

# Load the inventory data (since the games data has no
# missing values)
inventory = pd.read_table('data/inventory/data.txt')
inventory

# Use the `fillna` method
inventory.assign(price = lambda x : x.price.fillna(9.00))

# ## Iterating over rows

# You can call the `apply` method of a column (which is
# a pandas Series object) to iterate over the rows of a
# DataFrame in `assign`
games.assign(
  name = lambda x: x.name.apply(
    lambda y: 'Cluedo' if y == 'Clue' else y
  )
)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt

from matplotlib.ticker import LogLocator
from matplotlib import rc
from matplotlib import rcParams
font = {'family' : 'Dejavu Sans',
        'weight' : 'normal',
        'size'   : 22}
rc('font', **font)
rcParams['lines.markersize'] = 12
rcParams['markers.fillstyle'] = 'none'

def print_config(cfg):
    for key in cfg:
        print ("\t", key,":",cfg[key])

def write_outputFG(filename, cfg, inv_hx, inv_ht, ndof, errorBuf):

    file = open(filename,"w")

    if cfg['save xt sol']:
        errorType = 'xtErr_'+cfg['error type']
    else:
        errorType = 'xErr_'+cfg['error type']

    data = errorType+', '+str(cfg['deg_x_v'])+', '+str(cfg['deg_t'])+'\n'
    file.write(data)

    N = inv_hx.shape[0]
    for k in range(0,N):
        data = str(inv_hx[k])+', '+str(inv_ht[k])+', '+str(ndof[k])\
               +', '+str(errorBuf[k,0])+', '+str(errorBuf[k,1])+'\n'
        file.write(data)
    file.close()

def read_outputFG(filename):

    file = open(filename,"r")

    data = file.readlines()
    N = len(data)-1

    ## read deg_x, deg_t from first line
    line = data[0]
    line_ = line.split(', ')
    deg_x = int(line_[1])
    deg_t = int(line_[2])

    inv_hx = np.zeros(N, dtype=np.int32)
    inv_ht = np.zeros(N, dtype=np.int32)
    ndof = np.zeros(N, dtype=np.int32)
    errorBuf = np.zeros((N,2), dtype=np.float64)
    ## read data
    for k in range(1,len(data)):
        line = data[k]
        line_ = line.split(', ')

        inv_hx[k-1] = int(line_[0])
        inv_ht[k-1] = int(line_[1])
        ndof[k-1] = int(line_[2])
        errorBuf[k-1,0] = float(line_[3])
        errorBuf[k-1,1] = float(line_[4])

    file.close()

    return deg_x, deg_t, inv_hx, inv_ht, ndof, errorBuf

def write_outputSG(filename, cfg, inv_h, ndof, errorBuf):

    file = open(filename,"w")

    if cfg['save xt sol']:
        errorType = 'xtErr_'+cfg['error type']
    else:
        errorType = 'xErr_'+cfg['error type']

    data = errorType+', '+str(cfg['deg_x_v'])+', '+str(cfg['deg_t'])+'\n'
    file.write(data)

    N = inv_h.shape[0]
    for k in range(0,N):
        data = str(inv_h[k])+', '+str(ndof[k])\
               +', '+str(errorBuf[k,0])+', '+str(errorBuf[k,1])+'\n'
        file.write(data)
    file.close()

def read_outputSG(filename):

    file = open(filename,"r")

    data = file.readlines()
    N = len(data)-1

    ## read deg_x, deg_t from first line
    line = data[0]
    line_ = line.split(', ')
    deg_x = int(line_[1])
    deg_t = int(line_[2])

    inv_h = np.zeros(N, dtype=np.int64)
    ndof = np.zeros(N, dtype=np.int64)
    errorBuf = np.zeros((N,2), dtype=np.float64)
    ## read data
    for k in range(1,len(data)):
        line = data[k]
        line_ = line.split(', ')

        inv_h[k-1] = int(line_[0])
        ndof[k-1] = int(line_[1])
        errorBuf[k-1,0] = float(line_[2])
        errorBuf[k-1,1] = float(line_[3])

    file.close()

    return deg_x, deg_t, inv_h, ndof, errorBuf

def plotL2ErrorVsNdof(d, p, ndof_FG, err_FG, ndof_SG, err_SG):

    m_FG = (p+1)/(d+1)
    m_SG = (p+1)/d
    ref_FG = 3e+1/ndof_FG**m_FG
    ref_SG = 5e+2/ndof_SG**m_SG

    fig, ax = plt.subplots()
    ax.loglog(ndof_FG, err_FG, 'k-x', label='FG')
    ax.loglog(ndof_SG, err_SG, 'r-o', label='SG')
    ax.loglog(ndof_FG, ref_FG, 'k--x', label='$O(M_h^{%.2f})$'%m_FG)
    ax.loglog(ndof_SG, ref_SG, 'r--o', label='$O(M_h^{%.2f})$'%m_SG)

    legend = ax.legend(loc='lower left', shadow=False)

    plt.xlabel(r'$M_h$ [log]')
    plt.ylabel(r'Rel. error in ${L^2(Q)}$ norm [log]')
    plt.show()

def plotL2ErrorVsMeshSize(d, p, mesh_type, inv_hx, err_L2, showPlot, savePlot, filename):

    ## choose reference parameters
    if (mesh_type == ""):
        m = p+1
        factor = 2e+0

    elif (mesh_type == "quasi-uniform"):
        m = 2./3.
        if d == 1:
            factor = 1e+0
        else:
            factor = 4e-2

    elif mesh_type == "graded":
        m = p+0.5
        if d == 1:
            factor = 1e+0
        else:
            factor = 2e-2

    elif mesh_type == "bisection-refined":
        m = p+1
        if d == 1:
            factor = 1e+0
        else:
            factor = 8e-2

    ref_L2 = factor/inv_hx**m

    fig, ax = plt.subplots()
    ax.loglog(inv_hx, err_L2, 'r-x', label='$L^2$-norm')
    ax.loglog(inv_hx, ref_L2, 'k--x', label='$r_{L^2}$ = %.2f'%m)

    legend = ax.legend(loc='lower left', shadow=False)

    plt.xlabel(r'$h_x^{-1}$ [log]')
    plt.ylabel(r'Rel. error in ${L^2(\Omega)}$ norm [log]')

    fig = plt.gcf()
    fig.set_size_inches(16, 10)

    if showPlot:
        plt.show()
    if savePlot:
        fig.savefig(filename, format='eps', dpi=1000)

# END OF FILE


import time
import numpy as np

def time_it(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        ret = func(*args, **kwargs)
        end = time.time()
        print(f'Function took {end-start}s')

        return ret

    return wrapper

rng = np.random.RandomState(0)

# Create a lot of numbers
nums = rng.random(10000000)
# Decorate np.sort with our time_it transformer
timed_sort = time_it(np.sort)
# Perform the sort with our time_it functionality
timed_sort(nums)


#!/usr/bin/python
import numpy as np
import pandas as pd
from pandas import *  # Sereis, DataFrame
data = DataFrame(np.arange(16).reshape(4,4),index=list('abcd'),columns=list('wxyz'))
data['w']  #选择表格中的'w'列，使用类字典属性,返回的是Series类型
data.w    #选择表格中的'w'列，使用点属性,返回的是Series类型
data[['w']]  #选择表格中的'w'列，返回的是DataFrame类型
data[['w','z']]  #选择表格中的'w'、'z'列
data.to_csv=('a.csv')


#!/usr/bin/env python3

#from collections import defaultdict
#from heapq import heappush, heappop
#import numpy as np
import sys

sys.setrecursionlimit(10**6)
input = sys.stdin.buffer.readline
INF = 10 ** 9 + 1  # sys.maxsize # float("inf")
MOD = 10 ** 9 + 7

debug_indent = 0

def debug(*x):
    global debug_indent
    x = list(x)
    indent = 0
    if x[0].startswith("enter") or x[0][0] == ">":
        indent = 1
    if x[0].startswith("leave") or x[0][0] == "<":
        debug_indent -= 1
    x[0] = "  " * debug_indent + x[0]
    print(*x, file=sys.stderr)
    debug_indent += indent

def solve(N, XS):
    return sum([1 for x in range(0, N, 2) if XS[x] % 2])

def main():
    # parse input
    N = int(input())
    XS = list(map(int, input().split()))
    print(solve(N, XS))

# tests
T1 = """
15
13 76 46 15 50 98 93 77 31 43 84 90 6 24 14
"""

def test_T1():
    """
    >>> as_input(T1)
    >>> main()
    result
    """
# add tests above

def _test():
    import doctest
    doctest.testmod()

def as_input(s):
    "use in test, use given string as input file"
    import io
    global read, input
    f = io.StringIO(s.strip())

    def input():
        return bytes(f.readline(), "ascii")

    def read():
        return bytes(f.read(), "ascii")

USE_NUMBA = False
if (USE_NUMBA and sys.argv[-1] == 'ONLINE_JUDGE') or sys.argv[-1] == '-c':
    print("compiling")
    from numba.pycc import CC
    cc = CC('my_module')
    cc.export('solve', solve.__doc__.strip().split()[0])(solve)
    cc.compile()
    exit()
else:
    input = sys.stdin.buffer.readline
    read = sys.stdin.buffer.read

    if (USE_NUMBA and sys.argv[-1] != '-p') or sys.argv[-1] == "--numba":
        # -p: pure python mode
        # if not -p, import compiled module
        from my_module import solve  # pylint: disable=all
    elif sys.argv[-1] == "-t":
        print("testing")
        _test()
        sys.exit()
    elif sys.argv[-1] != '-p' and len(sys.argv) == 2:
        # input given as file
        input_as_file = open(sys.argv[1])
        input = input_as_file.buffer.readline
        read = input_as_file.buffer.read

    main()


import numpy as np
import matplotlib.pyplot as plt

class ImageProcessor:
    def __init__(self):
        pass

    def load(self, path):
        img_array = plt.imread(path)
        print('Loading image of dimensions {} x {}'.format(
              img_array.shape[0],
              img_array.shape[1]))
        return img_array

    def display(self, array):
        _, ax = plt.subplots()
        ax.imshow(array)
        ax.set_axis_off()
        plt.show()

if __name__ == "__main__":
    imp = ImageProcessor()

    arr = imp.load("../resources/42AI.png")
    print(arr)
    print(type(arr))
    imp.display(arr)


"""
@file
@brief Helpers to test a model which follows :epkg:`scikit-learn` API.
"""
import copy
import pickle
import pprint
from unittest import TestCase
from io import BytesIO
from numpy import ndarray
from numpy.testing import assert_almost_equal
from pandas.testing import assert_frame_equal
from sklearn.base import BaseEstimator
from sklearn.model_selection import train_test_split
from sklearn.base import clone
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import GridSearchCV

def train_test_split_with_none(X, y=None, sample_weight=None, random_state=0):
    """
    Splits into train and test data even if they are None.

    @param      X               X
    @param      y               y
    @param      sample_weight   sample weight
    @param      random_state    random state
    @return                     similar to :epkg:`scikit-learn:model_selection:train_test_split`.
    """
    not_none = [_ for _ in [X, y, sample_weight] if _ is not None]
    res = train_test_split(*not_none)
    inc = len(not_none)
    trains = []
    tests = []
    for i in range(inc):
        trains.append(res[i * 2])
        tests.append(res[i * 2 + 1])
    while len(trains) < 3:
        trains.append(None)
        tests.append(None)
    X_train, y_train, w_train = trains
    X_test, y_test, w_test = tests
    return X_train, y_train, w_train, X_test, y_test, w_test

def test_sklearn_pickle(fct_model, X, y=None, sample_weight=None, **kwargs):
    """
    Creates a model, fit, predict and check the prediction
    are similar after the model was pickled, unpickled.

    @param      fct_model       function which creates the model
    @param      X               X
    @param      y               y
    @param      sample_weight   sample weight
    @param      kwargs          additional parameters for :epkg:`numpy:testing:assert_almost_equal`
    @return                     model, unpickled model

    :raises:
        AssertionError
    """
    X_train, y_train, w_train, X_test, _, __ = train_test_split_with_none(
        X, y, sample_weight)
    model = fct_model()
    if y_train is None and w_train is None:
        model.fit(X_train)
    else:
        try:
            model.fit(X_train, y_train, w_train)
        except TypeError:
            # Do not accept weights?
            model.fit(X_train, y_train)
    if hasattr(model, 'predict'):
        pred1 = model.predict(X_test)
    else:
        pred1 = model.transform(X_test)

    st = BytesIO()
    pickle.dump(model, st)
    data = BytesIO(st.getvalue())
    model2 = pickle.load(data)
    if hasattr(model2, 'predict'):
        pred2 = model2.predict(X_test)
    else:
        pred2 = model2.transform(X_test)
    if isinstance(pred1, ndarray):
        assert_almost_equal(pred1, pred2, **kwargs)
    else:
        assert_frame_equal(pred1, pred2, **kwargs)
    return model, model2

def _get_test_instance():
    try:
        from pyquickhelper.pycode import ExtTestCase  # pylint: disable=C0415
        cls = ExtTestCase
    except ImportError:  # pragma: no cover

        class _ExtTestCase(TestCase):
            "simple test classe with a more methods"

            def assertIsInstance(self, inst, cltype):
                "checks that one instance is from one type"
                if not isinstance(inst, cltype):
                    raise AssertionError(
                        "Unexpected type {} != {}.".format(
                            type(inst), cltype))

        cls = _ExtTestCase
    return cls()

def test_sklearn_clone(fct_model, ext=None, copy_fitted=False):
    """
    Tests that a cloned model is similar to the original one.

    @param      fct_model       function which creates the model
    @param      ext             unit test class instance
    @param      copy_fitted     copy fitted parameters as well
    @return                     model, cloned model

    :raises:
        AssertionError
    """
    conv = fct_model()
    p1 = conv.get_params(deep=True)
    if copy_fitted:
        cloned = clone_with_fitted_parameters(conv)
    else:
        cloned = clone(conv)
    p2 = cloned.get_params(deep=True)
    if ext is None:
        ext = _get_test_instance()
    try:
        ext.assertEqual(set(p1), set(p2))
    except AssertionError as e:  # pragma no cover
        p1 = pprint.pformat(p1)
        p2 = pprint.pformat(p2)
        raise AssertionError(
            "Differences between\n----\n{0}\n----\n{1}".format(p1, p2)) from e

    for k in sorted(p1):
        if isinstance(p1[k], BaseEstimator) and isinstance(p2[k], BaseEstimator):
            if copy_fitted:
                assert_estimator_equal(p1[k], p2[k])
        elif isinstance(p1[k], list) and isinstance(p2[k], list):
            _assert_list_equal(p1[k], p2[k], ext)
        else:
            try:
                ext.assertEqual(p1[k], p2[k])
            except AssertionError:  # pragma no cover
                raise AssertionError(  # pylint: disable=W0707
                    "Difference for key '{0}'\n==1 {1}\n==2 {2}".format(
                        k, p1[k], p2[k]))
    return conv, cloned

def _assert_list_equal(l1, l2, ext):
    if len(l1) != len(l2):
        raise AssertionError(  # pragma no cover
            "Lists have different length {0} != {1}".format(len(l1), len(l2)))
    for a, b in zip(l1, l2):
        if isinstance(a, tuple) and isinstance(b, tuple):
            _assert_tuple_equal(a, b, ext)
        else:
            ext.assertEqual(a, b)

def _assert_dict_equal(a, b, ext):
    if not isinstance(a, dict):  # pragma no cover
        raise TypeError('a is not dict but {0}'.format(type(a)))
    if not isinstance(b, dict):  # pragma no cover
        raise TypeError('b is not dict but {0}'.format(type(b)))
    rows = []
    for key in sorted(b):
        if key not in a:
            rows.append("** Added key '{0}' in b".format(key))
        elif isinstance(a[key], BaseEstimator) and isinstance(b[key], BaseEstimator):
            assert_estimator_equal(a[key], b[key], ext)
        else:
            if a[key] != b[key]:
                rows.append(
                    "** Value != for key '{0}': != id({1}) != id({2})\n==1 {3}\n==2 {4}".format(
                        key, id(a[key]), id(b[key]), a[key], b[key]))
    for key in sorted(a):
        if key not in b:
            rows.append("** Removed key '{0}' in a".format(key))
    if len(rows) > 0:
        raise AssertionError(  # pragma: no cover
            "Dictionaries are different\n{0}".format('\n'.join(rows)))

def _assert_tuple_equal(t1, t2, ext):
    if len(t1) != len(t2):  # pragma no cover
        raise AssertionError(
            "Lists have different length {0} != {1}".format(len(t1), len(t2)))
    for a, b in zip(t1, t2):
        if isinstance(a, BaseEstimator) and isinstance(b, BaseEstimator):
            assert_estimator_equal(a, b, ext)
        else:
            ext.assertEqual(a, b)

def assert_estimator_equal(esta, estb, ext=None):
    """
    Checks that two models are equal.

    @param      esta        first estimator
    @param      estb        second estimator
    @param      ext         unit test class

    The function raises an exception if the comparison fails.
    """
    if ext is None:
        ext = _get_test_instance()
    ext.assertIsInstance(esta, estb.__class__)
    ext.assertIsInstance(estb, esta.__class__)
    _assert_dict_equal(esta.get_params(), estb.get_params(), ext)
    for att in esta.__dict__:
        if (att.endswith('_') and not att.endswith('__')) or \
                (att.startswith('_') and not att.startswith('__')):
            if not hasattr(estb, att):  # pragma no cover
                raise AssertionError("Missing fitted attribute '{}' class {}\n==1 {}\n==2 {}".format(
                    att, esta.__class__, list(sorted(esta.__dict__)), list(sorted(estb.__dict__))))
            if isinstance(getattr(esta, att), BaseEstimator):
                assert_estimator_equal(
                    getattr(esta, att), getattr(estb, att), ext)
            else:
                ext.assertEqual(getattr(esta, att), getattr(estb, att))
    for att in estb.__dict__:
        if att.endswith('_') and not att.endswith('__'):
            if not hasattr(esta, att):  # pragma no cover
                raise AssertionError("Missing fitted attribute\n==1 {}\n==2 {}".format(
                    list(sorted(esta.__dict__)), list(sorted(estb.__dict__))))

def test_sklearn_grid_search_cv(fct_model, X, y=None, sample_weight=None, **grid_params):
    """
    Creates a model, checks that a grid search works with it.

    @param      fct_model       function which creates the model
    @param      X               X
    @param      y               y
    @param      sample_weight   sample weight
    @param      grid_params     parameter to use to run the grid search.
    @return                     dictionary with results

    :raises:
        AssertionError
    """
    X_train, y_train, w_train, X_test, y_test, w_test = (
        train_test_split_with_none(X, y, sample_weight))
    model = fct_model()
    pipe = make_pipeline(model)
    name = model.__class__.__name__.lower()
    parameters = {name + "__" + k: v for k, v in grid_params.items()}
    if len(parameters) == 0:
        raise ValueError(
            "Some parameters must be tested when running grid search.")
    clf = GridSearchCV(pipe, parameters)
    if y_train is None and w_train is None:
        clf.fit(X_train)
    elif w_train is None:
        clf.fit(X_train, y_train)  # pylint: disable=E1121
    else:
        clf.fit(X_train, y_train, w_train)  # pylint: disable=E1121
    score = clf.score(X_test, y_test)
    ext = _get_test_instance()
    ext.assertIsInstance(score, float)
    return dict(model=clf, X_train=X_train, y_train=y_train, w_train=w_train,
                X_test=X_test, y_test=y_test, w_test=w_test, score=score)

def clone_with_fitted_parameters(est):
    """
    Clones an estimator with the fitted results.

    @param      est     estimator
    @return             cloned object
    """
    def adjust(obj1, obj2):
        if isinstance(obj1, list) and isinstance(obj2, list):
            for a, b in zip(obj1, obj2):
                adjust(a, b)
        elif isinstance(obj1, tuple) and isinstance(obj2, tuple):
            for a, b in zip(obj1, obj2):
                adjust(a, b)
        elif isinstance(obj1, dict) and isinstance(obj2, dict):
            for a, b in zip(obj1, obj2):
                adjust(obj1[a], obj2[b])
        elif isinstance(obj1, BaseEstimator) and isinstance(obj2, BaseEstimator):
            for k in obj1.__dict__:
                if hasattr(obj2, k):
                    v1 = getattr(obj1, k)
                    if callable(v1):
                        raise RuntimeError(  # pragma: no cover
                            "Cannot migrate trained parameters for {}.".format(obj1))
                    elif isinstance(v1, BaseEstimator):
                        v1 = getattr(obj1, k)
                        setattr(obj2, k, clone_with_fitted_parameters(v1))
                    else:
                        adjust(getattr(obj1, k), getattr(obj2, k))
                elif (k.endswith('_') and not k.endswith('__')) or \
                     (k.startswith('_') and not k.startswith('__')):
                    v1 = getattr(obj1, k)
                    setattr(obj2, k, clone_with_fitted_parameters(v1))
                else:
                    raise RuntimeError(  # pragma: no cover
                        "Cloned object is missing '{0}' in {1}.".format(k, obj2))

    if isinstance(est, BaseEstimator):
        cloned = clone(est)
        adjust(est, cloned)
        res = cloned
    elif isinstance(est, list):
        res = list(clone_with_fitted_parameters(o) for o in est)
    elif isinstance(est, tuple):
        res = tuple(clone_with_fitted_parameters(o) for o in est)
    elif isinstance(est, dict):
        res = {k: clone_with_fitted_parameters(v) for k, v in est.items()}
    else:
        res = copy.deepcopy(est)
    return res


'''
@author: Daniel Hjertholm
'''

import time
import numpy as np
import matplotlib.pyplot as plt
from algorithms import primes1, primes2, primes3, primes4, primes5, primes6, primes7, primes8

ubounds = range(0, 10000, 100)
num = len(ubounds)

results = []

for algorithm in (primes1, primes2, primes3, primes4, primes5, primes6, primes7, primes8):
    print(f'Testing algorithm {algorithm.__name__}')
    results_for_current_algorithm = []
    for ubound in ubounds:
        starttime = time.time()
        result = algorithm(ubound)
        endtime = time.time()
        duration = endtime - starttime
        results_for_current_algorithm.append(duration)
    results.append(results_for_current_algorithm)

plt.plot(np.transpose(np.array(results)), linewidth=2)
plt.xticks(range(len(ubounds))[0::10], ubounds[0::10])
plt.xlabel('Upper bound for primes')
plt.ylabel('Time in seconds to generate primes')
plt.legend(['algorithm 1', 'algorithm 2', 'algorithm 3', 'algorithm 4',
            'algorithm 5', 'algorithm 6', 'algorithm 7', 'algorithm 8'], loc=2)
plt.show()


"""some helper functions."""
import numpy as np

def batch_iter(y, tx, batch_size, num_batches=None, shuffle=True):
    """
    Generate a minibatch iterator for a dataset.
    Takes as input two iterables (here the output desired values 'y' and the input data 'tx')
    Outputs an iterator which gives mini-batches of `batch_size` matching elements from `y` and `tx`.
    Data can be randomly shuffled to avoid ordering in the original data messing with the randomness of the minibatches.
    Example of use :
    for minibatch_y, minibatch_tx in batch_iter(y, tx, 32):
        <DO-SOMETHING>
    """
    data_size = len(y)
    num_batches_max = int(np.ceil(data_size/batch_size))
    if num_batches is None:
        num_batches = num_batches_max
    else:
        num_batches = min(num_batches, num_batches_max)

    if shuffle:
        shuffle_indices = np.random.permutation(np.arange(data_size))
        shuffled_y = y[shuffle_indices]
        shuffled_tx = tx[shuffle_indices]
    else:
        shuffled_y = y
        shuffled_tx = tx
    for batch_num in range(num_batches):
        start_index = batch_num * batch_size
        end_index = min((batch_num + 1) * batch_size, data_size)
        if start_index != end_index:
            yield shuffled_y[start_index:end_index], shuffled_tx[start_index:end_index]


from __future__ import with_statement

import os
import time
import tempfile

from latex import latex

def preview(expr, output='png', viewer=None, euler=True, packages=(), **latex_settings):
    r"""
    View expression or LaTeX markup in PNG, DVI, PostScript or PDF form.

    If the expr argument is an expression, it will be exported to LaTeX and
    then compiled using available the TeX distribution.  The first argument,
    'expr', may also be a LaTeX string.  The function will then run the
    appropriate viewer for the given output format or use the user defined
    one. By default png output is generated.

    By default pretty Euler fonts are used for typesetting (they were used to
    typeset the well known "Concrete Mathematics" book). For that to work, you
    need the 'eulervm.sty' LaTeX style (in Debian/Ubuntu, install the
    texlive-fonts-extra package). If you prefer default AMS fonts or your
    system lacks 'eulervm' LaTeX package then unset the 'euler' keyword
    argument.

    To use viewer auto-detection, lets say for 'png' output, issue

    >>> from sympy import symbols, preview, Symbol
    >>> x, y = symbols("x,y")

    >>> preview(x + y, output='png') # doctest: +SKIP

    This will choose 'pyglet' by default. To select a different one, do

    >>> preview(x + y, output='png', viewer='gimp') # doctest: +SKIP

    The 'png' format is considered special. For all other formats the rules
    are slightly different. As an example we will take 'dvi' output format. If
    you would run

    >>> preview(x + y, output='dvi') # doctest: +SKIP

    then 'view' will look for available 'dvi' viewers on your system
    (predefined in the function, so it will try evince, first, then kdvi and
    xdvi). If nothing is found you will need to set the viewer explicitly.

    >>> preview(x + y, output='dvi', viewer='superior-dvi-viewer') # doctest: +SKIP

    This will skip auto-detection and will run user specified
    'superior-dvi-viewer'. If 'view' fails to find it on your system it will
    gracefully raise an exception. You may also enter 'file' for the viewer
    argument. Doing so will cause this function to return a file object in
    read-only mode.

    Currently this depends on pexpect, which is not available for windows.

    Additional keyword args will be passed to the latex call, e.g., the
    symbol_names flag.

    >>> phidd = Symbol('phidd')
    >>> preview(phidd, symbol_names={phidd:r'\ddot{\varphi}'}) # doctest: +SKIP

    """

    # we don't want to depend on anything not in the
    # standard library with SymPy by default
    import pexpect

    special = [ 'pyglet' ]

    if viewer is None:
        if output == "png":
            viewer = "pyglet"
        else:
            # sorted in order from most pretty to most ugly
            # very discussable, but indeed 'gv' looks awful :)
            candidates = {
                "dvi" : [ "evince", "okular", "kdvi", "xdvi" ],
                "ps"  : [ "evince", "okular", "gsview", "gv" ],
                "pdf" : [ "evince", "okular", "kpdf", "acroread", "xpdf", "gv" ],
            }

            try:
                for candidate in candidates[output]:
                    if pexpect.which(candidate):
                        viewer = candidate
                        break
                else:
                    raise SystemError("No viewers found for '%s' output format." % output)
            except KeyError:
                raise SystemError("Invalid output format: %s" % output)
    else:
        if viewer not in special and not pexpect.which(viewer):
            raise SystemError("Unrecognized viewer: %s" % viewer)

    actual_packages = packages + ("amsmath", "amsfonts")
    if euler:
        actual_packages += ("euler",)
    package_includes = "\n".join(["\\usepackage{%s}" % p
                                  for p in actual_packages])

    format = r"""\documentclass[12pt]{article}
                 %s
                 \begin{document}
                 \pagestyle{empty}
                 %s
                 \vfill
                 \end{document}
              """ % (package_includes, "%s")

    if isinstance(expr, str):
        latex_string = expr
    else:
        latex_string = latex(expr, mode='inline', **latex_settings)

    tmp = tempfile.mktemp()

    with open(tmp + ".tex", "w") as tex:
        tex.write(format % latex_string)

    cwd = os.getcwd()
    os.chdir(tempfile.gettempdir())

    if os.system("latex -halt-on-error %s.tex" % tmp) != 0:
        raise SystemError("Failed to generate DVI output.")

    os.remove(tmp + ".tex")
    os.remove(tmp + ".aux")
    os.remove(tmp + ".log")

    if output != "dvi":
        command = {
            "ps"  : "dvips -o %s.ps %s.dvi",
            "pdf" : "dvipdf %s.dvi %s.pdf",
            "png" : "dvipng -T tight -z 9 " + \
                    "--truecolor -o %s.png %s.dvi",
        }

        try:
            if os.system(command[output] % (tmp, tmp)) != 0:
                raise SystemError("Failed to generate '%s' output." % output)
            else:
                os.remove(tmp + ".dvi")
        except KeyError:
            raise SystemError("Invalid output format: %s" % output)

    src = "%s.%s" % (tmp, output)
    src_file = None

    if viewer == "file":
        src_file = open(src, 'rb')
    elif viewer == "pyglet":
        try:
            from pyglet import window, image, gl
            from pyglet.window import key
        except ImportError:
            raise ImportError("pyglet is required for plotting.\n visit http://www.pyglet.org/")

        if output == "png":
            from pyglet.image.codecs.png import PNGImageDecoder
            img = image.load(src, decoder=PNGImageDecoder())
        else:
            raise SystemError("pyglet preview works only for 'png' files.")

        offset = 25

        win = window.Window(
            width = img.width + 2*offset,
            height = img.height + 2*offset,
            caption = "sympy",
            resizable = False
        )

        win.set_vsync(False)

        try:
            def on_close():
                win.has_exit = True

            win.on_close = on_close

            def on_key_press(symbol, modifiers):
                if symbol in [key.Q, key.ESCAPE]:
                    on_close()

            win.on_key_press = on_key_press

            def on_expose():
                gl.glClearColor(1.0, 1.0, 1.0, 1.0)
                gl.glClear(gl.GL_COLOR_BUFFER_BIT)

                img.blit(
                    (win.width - img.width) / 2,
                    (win.height - img.height) / 2
                )

            win.on_expose = on_expose

            while not win.has_exit:
                win.dispatch_events()
                win.flip()
        except KeyboardInterrupt:
            pass

        win.close()
    else:
        os.system("%s %s &> /dev/null &" % (viewer, src))
        time.sleep(2) # wait for the viewer to read data

    os.remove(src)
    os.chdir(cwd)

    if src_file is not None:
        return src_file


import numpy as np
import matplotlib.pyplot as plt
import timeit

class NumpyVSList:
    @staticmethod
    def compute(operation):
        """Compute the time of an operation on a numpy array and a core_list.

        :param str operation: The operation to compute.
        :return: Tuple containing the time of the operation on an numpy array and a core list.
        :rtype: tuple of float
        """

        if operation == "init":
            return NumpyVSList.compute_time_init()
        elif operation == "reading":
            return NumpyVSList.compute_time_reading()
        elif operation == "writing":
            return NumpyVSList.compute_time_writing()

    @staticmethod
    def compute_time_init(nb_values=100, repeat=10000):
        """Compare the time of initialization of a numpy array and a core list.

        :param int nb_values: The number of values in the iterables.
        :param int repeat: The number of times we repeat the experiment.
        :return: The time of initialization of the numpy array and the core list.
        :rtype: tuple of float
        """

        time_numpy_array = timeit.timeit("numpy_array = np.array(range({}))".format(nb_values), number=repeat, setup="import numpy as np") / repeat
        time_core_list = timeit.timeit("[i for i in range({})]".format(nb_values), number=repeat) / repeat
        return time_numpy_array, time_core_list

    @staticmethod
    def compute_time_reading(nb_values=100, repeat=10000):
        """Compare the time of reading of a numpy array and a core list.

        :param int nb_values: The number of values in the iterables.
        :param int repeat: The number of times we repeat the experiment.
        :return: The time of reading of the numpy array and the core list.
        :rtype: tuple of float
        """

        numpy_setup = "import numpy as np\nnumpy_array = np.array(range({}))".format(nb_values)
        numpy_test = "for i in numpy_array: pass"
        core_setup = "core_list = [i for i in range({})]".format(nb_values)
        core_test = "for i in core_list: pass"
        time_numpy_array = timeit.timeit(numpy_test, setup=numpy_setup, number=repeat) / repeat
        time_core_list = timeit.timeit(core_test, setup=core_setup, number=repeat) / repeat
        return time_numpy_array, time_core_list

    @staticmethod
    def compute_time_writing(nb_values=100, repeat=10000):
        """Compare the time of writing of a numpy array and a core list.

        :param int nb_values: The number of values in the iterables.
        :param int repeat: The number of times we repeat the experiment.
        :return: The time of writing of the numpy array and the core list.
        :rtype: tuple of float
        """

        numpy_setup = "import numpy as np\nnumpy_array = np.array(range({}))".format(nb_values)
        numpy_test = "for i in range(len(numpy_array)): numpy_array[i] = 1"
        core_setup = "core_list = [i for i in range({})]".format(nb_values)
        core_test = "for i in range(len(core_list)): core_list[i] = 1"
        time_numpy_array = timeit.timeit(numpy_test, setup=numpy_setup, number=repeat) / repeat
        time_core_list = timeit.timeit(core_test, setup=core_setup, number=repeat) / repeat
        return time_numpy_array, time_core_list

    @staticmethod
    def display_compare_init(nb_values=100, repeat=10000):
        """Display the time of initialization of a numpy array and a core list.

        :param int nb_values: The number of values in the iterables.
        :param int repeat: The number of times we repeat the experiment.
        """

        time_numpy_array, time_core_list = NumpyVSList.compute_time_init(nb_values, repeat)
        print("=====RESULT INITIATION=====")
        print("Number of values: {}".format(nb_values))
        print("Number of repeat: {}".format(repeat))
        print("Mean numpy array: {}".format(time_numpy_array))
        print("Mean core list: {}".format(time_core_list))
        print("T_numpy - T_core = {}".format(time_numpy_array - time_core_list))
        print("===========================")

    @staticmethod
    def display_compare_reading(nb_values=100, repeat=10000):
        """Display the time of reading of a core list and a numpy array.

        :param int nb_values: The number of values in the iterables.
        :param int repeat: The number of times we repeat the experiment.
        """

        numpy_setup = "import numpy as np\nnumpy_array = np.array(range({}))".format(nb_values)
        numpy_test = "for i in numpy_array: pass"
        core_setup = "core_list = [i for i in range({})]".format(nb_values)
        core_test = "for i in core_list: pass"
        time_numpy_array, time_core_list = NumpyVSList.compute_time_reading(nb_values, repeat)
        print("=====RESULT READING=====")
        print("Number of values: {}".format(nb_values))
        print("Number of repeat: {}".format(repeat))
        print("Mean numpy array: {}".format(time_numpy_array))
        print("Mean core list: {}".format(time_core_list))
        print("T_numpy - T_core = {}".format(time_numpy_array - time_core_list))
        print("===========================")
        return time_numpy_array, time_core_list

    @staticmethod
    def display_compare_writing(nb_values=100, repeat=10000):
        """Display the time of writing of a core list and a numpy array.

        :param int nb_values: The number of values in the iterables.
        :param int repeat: The number of times we repeat the experiment.
        """

        numpy_setup = "import numpy as np\nnumpy_array = np.array(range({}))".format(nb_values)
        numpy_test = "for i in range(len(numpy_array)): numpy_array[i] = 1"
        core_setup = "core_list = [i for i in range({})]".format(nb_values)
        core_test = "for i in range(len(core_list)): core_list[i] = 1"
        time_numpy_array, time_core_list = NumpyVSList.compute_time_writing(nb_values, repeat)
        print("=====RESULT WRITING=====")
        print("Number of values: {}".format(nb_values))
        print("Number of repeat: {}".format(repeat))
        print("Mean numpy array: {}".format(time_numpy_array))
        print("Mean core list: {}".format(time_core_list))
        print("T_numpy - T_core = {}".format(time_numpy_array - time_core_list))
        print("===========================")
        return time_numpy_array, time_core_list

    @staticmethod
    def compare_all_plot(nb_values=100, repeat=10000):
        """Plot in a bar plot the different mean computation times of different operations on a numpy array and a core list.

        :param int nb_values: The number of values in the iterables NOT IMPLEMENTED.
        :param int repeat: The number of times we repeat the experiment NOT IMPLEMENTED.
        """
        time_numpy_array = {}
        time_core_list = {}
        for operation in ["init", "reading", "writing"]:
            times = NumpyVSList.compute(operation)
            time_numpy_array[operation] = times[0]
            time_core_list[operation] = times[1]
        print(time_numpy_array)
        print(time_core_list)
        plt.bar(time_numpy_array.keys(), time_numpy_array.values())
        plt.bar(time_core_list.keys(), time_core_list.values())
        plt.show()

NumpyVSList.compare_all_plot()


import os.path
import re

import numpy
import pytest

from grunnur import (
    cuda_api_id, opencl_api_id, cuda_api_id,
    Program, Queue, MultiQueue, Array, MultiArray, CompilationError, StaticKernel, API, Context,
    )
from grunnur.template import Template, DefTemplate

from .mock_base import MockKernel, MockDefTemplate
from .mock_pycuda import PyCUDADeviceInfo

SRC_OPENCL = """
__kernel void multiply(__global int *dest, __global int *a, __global int *b, int c)
{
    const int i = get_global_id(0);
    dest[i] = a[i] * b[i] + c;
}
"""

SRC_CUDA = """
extern "C" __global__ void multiply(int *dest, int *a, int *b, int c)
{
    const int i = threadIdx.x + blockIdx.x * blockDim.x;
    dest[i] = a[i] * b[i] + c;
}
"""

SRC_GENERIC = """
KERNEL void multiply(GLOBAL_MEM int *dest, GLOBAL_MEM int *a, GLOBAL_MEM int *b, int c)
{
    const int i = get_global_id(0);
    dest[i] = a[i] * b[i] + c;
}
"""

@pytest.mark.parametrize('no_prelude', [False, True], ids=["with_prelude", "no_prelude"])
def test_compile(mock_or_real_context, no_prelude):

    context, mocked = mock_or_real_context

    if mocked:
        src = MockDefTemplate(kernels=[MockKernel('multiply', [None, None, None, numpy.int32])])
    else:
        if no_prelude:
            src = SRC_CUDA if context.api.id == cuda_api_id() else SRC_OPENCL
        else:
            src = SRC_GENERIC

    program = Program(context.device, src, no_prelude=no_prelude)

    if mocked and no_prelude:
        assert program.sources[context.device].prelude.strip() == ""

    length = 64

    a = numpy.arange(length).astype(numpy.int32)
    b = numpy.arange(length).astype(numpy.int32) + 1
    c = numpy.int32(3)
    ref = a * b + c

    queue = Queue(context.device)

    a_dev = Array.from_host(queue, a)
    b_dev = Array.from_host(queue, b)

    res_dev = Array.empty(context.device, length, numpy.int32)
    # Check that passing both Arrays and Buffers is supported
    # Pass one of the buffers as a subregion, too.
    a_dev_view = a_dev.data.get_sub_region(0, a_dev.data.size)
    program.kernel.multiply(queue, length, None, res_dev, a_dev_view, b_dev.data, c)
    res = res_dev.get(queue)
    if not mocked:
        assert (res == ref).all()

    # Explicit local_size
    res2_dev = Array.from_host(queue, a) # Array.empty(queue, length, numpy.int32)
    program.kernel.multiply(queue, length, length // 2, res2_dev, a_dev, b_dev, c)
    res2 = res2_dev.get(queue)
    if not mocked:
        assert (res2 == ref).all()

def test_compile_multi_device(mock_or_real_multi_device_context):

    context, mocked = mock_or_real_multi_device_context
    devices = context.devices[[1, 0]]

    if mocked:
        src = MockDefTemplate(kernels=[MockKernel('multiply', [None, None, None, numpy.int32])])
    else:
        src = SRC_GENERIC

    length = 64

    program = Program(devices, src)
    a = numpy.arange(length).astype(numpy.int32)
    b = numpy.arange(length).astype(numpy.int32) + 1
    c = numpy.int32(3)
    ref = a * b + c

    mqueue = MultiQueue.on_devices(devices)

    a_dev = MultiArray.from_host(mqueue, a)
    b_dev = MultiArray.from_host(mqueue, b)

    res_dev = MultiArray.empty(devices, length, numpy.int32)
    program.kernel.multiply(mqueue, a_dev.shapes, None, res_dev, a_dev, b_dev, c)
    res = res_dev.get(mqueue)
    if not mocked:
        assert (res == ref).all()

    # Test argument unpacking from dictionaries
    res_dev = MultiArray.empty(devices, length, numpy.int32)
    program.kernel.multiply(
        mqueue, a_dev.shapes, {device: None for device in devices},
        res_dev, a_dev.subarrays, b_dev, c)
    res = res_dev.get(mqueue)
    if not mocked:
        assert (res == ref).all()

def test_mismatched_devices(mock_4_device_context):
    context = mock_4_device_context
    src = MockDefTemplate(kernels=[MockKernel('multiply', [None, None, None, numpy.int32])])
    program = Program(context.devices, src)
    with pytest.raises(ValueError, match="Mismatched device sets for global and local sizes"):
        program.kernel.multiply.prepare(
            {context.devices[0]: 10, context.devices[2]: 20},
            {context.devices[0]: None, context.devices[1]: None})

SRC_CONSTANT_MEM = """
KERNEL void copy_from_cm(
    GLOBAL_MEM int *dest
#ifdef GRUNNUR_OPENCL_API
    , CONSTANT_MEM int *cm1
    , CONSTANT_MEM int *cm2
    , CONSTANT_MEM int *cm3
#endif
    )
{
    const int i = get_global_id(0);
    dest[i] = cm1[i] + cm2[i] + cm3[i];
}
"""

SRC_CONSTANT_MEM_STATIC = """
KERNEL void copy_from_cm(
    GLOBAL_MEM int *dest
#ifdef GRUNNUR_OPENCL_API
    , CONSTANT_MEM int *cm1
    , CONSTANT_MEM int *cm2
    , CONSTANT_MEM int *cm3
#endif
    )
{
    ${static.begin};
    const int i = ${static.global_id}(0);
    dest[i] = cm1[i] + cm2[i] + cm3[i];
}
"""

def _test_constant_memory(context, mocked, is_static):

    cm1 = numpy.arange(16).astype(numpy.int32)
    cm2 = numpy.arange(16).astype(numpy.int32) * 2 + 1
    cm3 = numpy.arange(16).astype(numpy.int32) * 3 + 2

    if mocked:
        kernel = MockKernel(
            'copy_from_cm',
            [None] if context.api.id == cuda_api_id() else [None, None, None, None],
            max_total_local_sizes={0: 1024})
        src = MockDefTemplate(
            constant_mem={
                'cm1': cm1.size * cm1.dtype.itemsize,
                'cm2': cm2.size * cm2.dtype.itemsize,
                'cm3': cm3.size * cm3.dtype.itemsize},
            kernels=[kernel])
    else:
        src = SRC_CONSTANT_MEM_STATIC if is_static else SRC_CONSTANT_MEM

    queue = Queue(context.device)

    cm1_dev = Array.from_host(queue, cm1)
    cm2_dev = Array.from_host(queue, cm2)
    cm3_dev = Array.from_host(queue, cm3)
    res_dev = Array.empty(context.device, 16, numpy.int32)

    if context.api.id == cuda_api_id():

        # Use different forms of constant array representation
        constant_arrays=dict(
            cm1=cm1, # as an array(-like) object
            cm2=(cm2.shape, cm2.dtype), # as a tuple of shape and dtype
            cm3=cm3_dev) # as a device array

        if is_static:
            copy_from_cm = StaticKernel(
                context.device, src, 'copy_from_cm',
                global_size=16, constant_arrays=constant_arrays)
            copy_from_cm.set_constant_array(queue, 'cm1', cm1_dev) # setting from a device array
            copy_from_cm.set_constant_array(queue, 'cm2', cm2) # setting from a host array
            copy_from_cm.set_constant_array(queue, 'cm3', cm3_dev.data) # setting from a host buffer
        else:
            program = Program(context.device, src, constant_arrays=constant_arrays)
            program.set_constant_array(queue, 'cm1', cm1_dev) # setting from a device array
            program.set_constant_array(queue, 'cm2', cm2) # setting from a host array
            program.set_constant_array(queue, 'cm3', cm3_dev.data) # setting from a host buffer
            copy_from_cm = lambda queue, *args: program.kernel.copy_from_cm(queue, 16, None, *args)

        copy_from_cm(queue, res_dev)
    else:

        if is_static:
            copy_from_cm = StaticKernel(context.device, src, 'copy_from_cm', global_size=16)
        else:
            program = Program(context.device, src)
            copy_from_cm = lambda queue, *args: program.kernel.copy_from_cm(queue, 16, None, *args)

        copy_from_cm(queue, res_dev, cm1_dev, cm2_dev, cm3_dev)

    res = res_dev.get(queue)

    if not mocked:
        assert (res == cm1 + cm2 + cm3).all()

def test_constant_memory(mock_or_real_context):
    context, mocked = mock_or_real_context
    _test_constant_memory(context=context, mocked=mocked, is_static=False)

SRC_COMPILE_ERROR = """
KERNEL void compile_error(GLOBAL_MEM int *dest)
{
    const int i = get_global_id(0);
    dest[i] = 1;
    zzz
}
"""

def test_compilation_error(mock_or_real_context, capsys):

    context, mocked = mock_or_real_context

    if mocked:
        src = MockDefTemplate(should_fail=True)
    else:
        src = SRC_COMPILE_ERROR

    with pytest.raises(CompilationError):
        Program(context.device, src)

    captured = capsys.readouterr()
    assert "Failed to compile on device" in captured.out

    # check that the full source is shown (including the prelude)
    assert "#define GRUNNUR_" in captured.out

    if mocked:
        assert "<<< mock source >>>" in captured.out
    else:
        assert "KERNEL void compile_error(GLOBAL_MEM int *dest)" in captured.out

def test_keep(mock_or_real_context, capsys):

    context, mocked = mock_or_real_context

    if mocked:
        src = MockDefTemplate(kernels=[MockKernel('multiply', [None, None, None, numpy.int32])])
    else:
        src = SRC_GENERIC

    program = Program(context.device, src, keep=True)
    captured = capsys.readouterr()
    path = re.match(r'\*\*\* compiler output in (.*)', captured.out).group(1)
    assert os.path.isdir(path)

    if context.api.id == opencl_api_id():
        srcfile = os.path.join(path, 'kernel.cl')
    elif context.api.id == cuda_api_id():
        srcfile = os.path.join(path, 'kernel.cu')

    with open(srcfile) as f:
        source = f.read()

    assert str(src) in source

def test_wrong_device_idxs(mock_4_device_context):
    src = MockDefTemplate(kernels=[MockKernel('multiply', [None])])

    context = mock_4_device_context
    program = Program(context.devices[[0, 1]], src)
    mqueue = MultiQueue.on_devices(context.devices[[2, 1]])
    res_dev = MultiArray.empty(context.devices[[2, 1]], 16, numpy.int32)

    # Using all the queue's devices (1, 2)
    with pytest.raises(ValueError, match="Requested execution on devices"):
        program.kernel.multiply(mqueue, 8, None, res_dev)

def test_wrong_context(mock_backend):

    mock_backend.add_devices(['Device0'])

    src = MockDefTemplate(kernels=[MockKernel('multiply', [None])])

    api = API.from_api_id(mock_backend.api_id)
    context = Context.from_devices(api.platforms[0].devices[0])
    context2 = Context.from_devices(api.platforms[0].devices[0])

    res_dev = Array.empty(context.device, 16, numpy.int32)

    program = Program(context.device, src)
    queue = Queue(context2.device)

    with pytest.raises(ValueError, match="The provided queue must belong to the same context this program uses"):
        program.kernel.multiply(queue, 8, None, res_dev)

def test_set_constant_array_errors(mock_4_device_context):

    context = mock_4_device_context

    api = API.from_api_id(mock_4_device_context.api.id)
    other_context = Context.from_criteria(api)
    other_queue = Queue(other_context.devices[0])
    # Contexts don't know about each other and can't interact with stack in a consistent manner.
    # So we deactivate the other context if we're on CUDA API.
    if api.id == cuda_api_id():
        other_context.deactivate()

    cm1 = numpy.arange(16).astype(numpy.int32)
    src = MockDefTemplate(kernels=[
        MockKernel(
            'kernel', [],
            max_total_local_sizes={0: 1024, 1: 1024, 2: 1024, 3: 1024})],
            constant_mem={'cm1': cm1.size * cm1.dtype.itemsize})
    queue = Queue(context.devices[0])

    if context.api.id == cuda_api_id():
        program = Program(context.devices, src, constant_arrays=dict(cm1=cm1))

        with pytest.raises(
                ValueError,
                match="The provided queue must belong to the same context as this program uses"):
            program.set_constant_array(other_queue, 'cm1', cm1)

        with pytest.raises(TypeError, match="Unsupported array type"):
            program.set_constant_array(queue, 'cm1', [1])

        with pytest.raises(ValueError, match="Incorrect size of the constant buffer;"):
            program.set_constant_array(queue, 'cm1', cm1[:8])

        with pytest.raises(TypeError, match="Unknown constant array metadata type"):
            program = Program(context.devices[[0, 1, 2]], src, constant_arrays=dict(cm1=1))

        program = Program(context.devices[[0, 1, 2]], src, constant_arrays=dict(cm1=cm1))
        queue3 = Queue(context.devices[3])

        with pytest.raises(
                ValueError,
                match="The program was not compiled for the device this queue uses"):
            program.set_constant_array(queue3, 'cm1', cm1)

    else:
        with pytest.raises(ValueError, match="Compile-time constant arrays are only supported by CUDA API"):
            program = Program(context.devices, src, constant_arrays=dict(cm1=cm1))

        program = Program(context.devices, src)
        with pytest.raises(ValueError, match="Constant arrays are only supported for CUDA API"):
            program.set_constant_array(queue, 'cm1', cm1)

        with pytest.raises(ValueError, match="Compile-time constant arrays are only supported by CUDA API"):
            sk = StaticKernel(context.devices, src, 'kernel', 1024, constant_arrays=dict(cm1=cm1))

        sk = StaticKernel(context.devices, src, 'kernel', 1024)
        with pytest.raises(ValueError, match="Constant arrays are only supported for CUDA API"):
            sk.set_constant_array(queue, 'cm1', cm1)

def test_max_total_local_sizes(mock_backend):
    mock_backend.add_devices(["Device1", "Device2 - tag", "Device3 - tag", "Device4"])
    api = API.from_api_id(mock_backend.api_id)
    context = Context.from_criteria(api, devices_num=2, device_include_masks=["tag"])

    # Providing max_total_local_sizes for all possible devices to make sure
    # only the ones corresponding to the context will get picked up
    kernel = MockKernel('test', max_total_local_sizes={0: 64, 1: 1024, 2: 512, 3: 128})

    src = MockDefTemplate(kernels=[kernel])
    program = Program(context.devices, src)

    # The indices here correspond to the devices in the context, not in the platform
    assert program.kernel.test.max_total_local_sizes == {context.devices[0]: 1024, context.devices[1]: 512}

def test_cannot_override_builtin_globals(mock_context):
    with pytest.raises(ValueError, match="'device_params' is a reserved global name and cannot be used"):
        Program(
            mock_context.device,
            MockDefTemplate(kernels=[MockKernel('test', [None])]),
            render_globals=dict(device_params=None))

def test_builtin_globals(mock_backend_pycuda):
    mock_backend_pycuda.add_devices([
        PyCUDADeviceInfo(max_threads_per_block=1024),
        PyCUDADeviceInfo(max_threads_per_block=512)])

    source_template = DefTemplate.from_string(
        'mock_source', [],
        """
        KERNEL void test()
        {
            int max_total_local_size = ${device_params.max_total_local_size};
        }
        """)

    api = API.from_api_id(mock_backend_pycuda.api_id)
    context = Context.from_devices([api.platforms[0].devices[0], api.platforms[0].devices[1]])

    src = MockDefTemplate(kernels=[MockKernel('test', [None])], source_template=source_template)

    program = Program(context.devices, src)

    assert 'max_total_local_size = 1024' in program.sources[context.devices[0]].source
    assert 'max_total_local_size = 512' in program.sources[context.devices[1]].source


import numpy as np

def digest_group_indices(group_indices):

    if type(group_indices)==str:
        if group_indices in ['all', 'All', 'ALL']:
            group_indices = 'all'
        else:
            raise ValueError()
    elif type(group_indices) in [int, np.int64, np.int32]:
        group_indices = np.array([group_indices], dtype='int64')
    elif hasattr(group_indices, '__iter__'):
        group_indices = np.array(group_indices, dtype='int64')

    return group_indices