from unittest import TestCase

from aoc2021.d20 import convert_pixels_to_int, load_image, get_pixel, get_algo_index_for_pixel
from aoc2021.d20 import enhance, count_lit_pixels, recusive_enhance
from tests.aoc2021Tests.aoc2021_common import get_test_file_path

class Loader(TestCase):
    def test_algo(self):
        algo, _ = load_image(get_test_file_path("samples/d20.txt"))
        self.assertEqual(algo.pixel_map[0], ".")
        self.assertEqual(algo.pixel_map[511], "#")
        self.assertEqual(algo.pixel_map[34], "#")

    def test_image(self):
        _, image = load_image(get_test_file_path("samples/d20.txt"))
        expected_image = ["#..#.", "#....", "##..#", "..#..", "..###"]
        self.assertListEqual(expected_image, image.pixels)
        self.assertEqual(5, image.height)
        self.assertEqual(5, image.width)
        self.assertEqual(".", image.infinity_pixel)

class Indexer(TestCase):
    def test_binary_conversion(self):
        self.assertEqual(convert_pixels_to_int("........."), 0)
        self.assertEqual(convert_pixels_to_int("#########"), 511)

class Indexer(TestCase):
    def test_binary_conversion(self):
        self.assertEqual(convert_pixels_to_int("........."), 0)
        self.assertEqual(convert_pixels_to_int("#########"), 511)
        self.assertEqual(convert_pixels_to_int("...#...#."), 34)

    def test_pixel_indexer(self):
        _, image = load_image(get_test_file_path("samples/d20.txt"))
        self.assertEqual(get_pixel(image, -1, 0), ".")
        self.assertEqual(get_pixel(image, 5, 0), ".")
        self.assertEqual(get_pixel(image, 0, 5), ".")
        self.assertEqual(get_pixel(image, 0, 0), "#")
        self.assertEqual(get_pixel(image, 4, 4), "#")
        self.assertEqual(get_pixel(image, 2, 3), "#")

    def test_get_map_index(self):
        _, image = load_image(get_test_file_path("samples/d20.txt"))
        self.assertEqual(get_algo_index_for_pixel(image, 2, 2), 34)
        self.assertEqual(get_algo_index_for_pixel(image, 0, 0), convert_pixels_to_int("....#..#."))
        self.assertEqual(get_algo_index_for_pixel(image, -3, -3), 0)

    def test_get_map_infinitiy(self):
        _, image = load_image(get_test_file_path("samples/d20.txt"))
        self.assertEqual(get_algo_index_for_pixel(image, -3, -3), 0)
        image.infinity_pixel = "#"
        self.assertEqual(get_algo_index_for_pixel(image, -3, -3), 511)

class Enhancer(TestCase):
    def test_one_step(self):
        algo, image = load_image(get_test_file_path("samples/d20.txt"))
        enhanced = enhance(image, algo)
        expected = [
            ".........",
            "..##.##..",
            ".#..#.#..",
            ".##.#..#.",
            ".####..#.",
            "..#..##..",
            "...##..#.",
            "....#.#..",
            "........."
        ]
        self.assertEqual(enhanced.infinity_pixel, ".")
        self.assertListEqual(enhanced.pixels, expected)

    def test_two_steps(self):
        algo, image = load_image(get_test_file_path("samples/d20.txt"))
        enhanced = enhance(image, algo)
        enhanced = enhance(enhanced, algo)
        expected = [
            ".............",
            ".............",
            ".........#...",
            "...#..#.#....",
            "..#.#...###..",
            "..#...##.#...",
            "..#.....#.#..",
            "...#.#####...",
            "....#.#####..",
            ".....##.##...",
            "......###....",
            ".............",
            ".............",

        ]
        self.assertEqual(enhanced.infinity_pixel, ".")
        self.assertListEqual(enhanced.pixels, expected)

    def test_infinity_flip(self):
        algo, image = load_image(get_test_file_path("samples/d20.txt"))
        algo.pixel_map = "#" + algo.pixel_map[1:]
        algo.pixel_map = algo.pixel_map[0:-1] + "."
        enhanced = enhance(image, algo)
        enhanced_again = enhance(enhanced, algo)
        self.assertEqual(enhanced.infinity_pixel, "#")
        self.assertEqual(enhanced_again.infinity_pixel, ".")

    def test_count_lit_pixels(self):
        algo, image = load_image(get_test_file_path("samples/d20.txt"))
        enhanced = enhance(image, algo)
        enhanced_again = enhance(enhanced, algo)
        self.assertEqual(count_lit_pixels(enhanced_again), 35)

    def test_recursive_enhance(self):
        algo, image = load_image(get_test_file_path("samples/d20.txt"))
        enhanced = recusive_enhance(image, algo, 2)
        self.assertEqual(count_lit_pixels(enhanced), 35)

    def test_recursive_enhance_part_2(self):
        algo, image = load_image(get_test_file_path("samples/d20.txt"))
        enhanced = recusive_enhance(image, algo, 50)
        self.assertEqual(count_lit_pixels(enhanced), 3351)


'''
09 트랙바 사용하기
트랙바 : 프로그램 동작 중 사용자가 지정한 범위 안의 값을 선택할 수 있는 컨트롤
cv2.createTrackbar(trackbarName, windowName, value, count, onChange) -> None
- trackBarName: 트랙바 이름
- windowName: 트랙바를 생성할 창 이름
- value: 트랙바 위치 초기값
- count: 트랙바 최댓값. 최솟값은 항상 0
- onChange: 트랙바 위치가 변경될 때마다 호출할 콜백 함수 이름
            트랙바 이벤트 콜백 함수는 다음 형식을 따름.
            onChange(pos) -> None
'''

import numpy as np
import cv2

def on_level_changed(pos):
    global img

    level = pos * 16
    level = np.clip(level, 0, 255)  # np.clip()은 0보다 작을 땐 0으로 255보다 크면 255로 변경시켜 값을 제한해준다.

    img[:, :] = level  # 슬라이스 :만 넣었을 때는 모든 범위에 적용된다.
    cv2.imshow('image', img)

img = np.zeros((480, 640, 3), dtype=np.uint8)

cv2.namedWindow('image')
cv2.imshow('image', img)
cv2.createTrackbar('GrayLevel', 'image', 0, 16, on_level_changed)
cv2.waitKey()

cv2.destroyAllWindows()

ch02 OpenCV_Python 기초 사용법/09 Trackbar.py


import json
import time
import sys
import cv2
import numpy
import math
from enum import Enum

from cscore import CameraServer, VideoSource, UsbCamera, MjpegServer
from networktables import NetworkTablesInstance, NetworkTables
import ntcore

#   JSON format:
#   {
#       "team": <team number>,
#       "ntmode": <"client" or "server", "client" if unspecified>
#       "cameras": [
#           {
#               "name": <camera name>
#               "path": <path, e.g. "/dev/video0">
#               "pixel format": <"MJPEG", "YUYV", etc>   // optional
#               "width": <video mode width>              // optional
#               "height": <video mode height>            // optional
#               "fps": <video mode fps>                  // optional
#               "brightness": <percentage brightness>    // optional
#               "white balance": <"auto", "hold", value> // optional
#               "exposure": <"auto", "hold", value>      // optional
#               "properties": [                          // optional
#                   {
#                       "name": <property name>
#                       "value": <property value>
#                   }
#               ],
#               "stream": {                              // optional
#                   "properties": [
#                       {
#                           "name": <stream property name>
#                           "value": <stream property value>
#                       }
#                   ]
#               }
#           }
#       ]
#       "switched cameras": [
#           {
#               "name": <virtual camera name>
#               "key": <network table key used for selection>
#               // if NT value is a string, it's treated as a name
#               // if NT value is a double, it's treated as an integer index
#           }
#       ]
#   }

configFile = "/boot/frc.json"

class CameraConfig: pass

team = None
server = False
cameraConfigs = []
switchedCameraConfigs = []
cameras = []

def parseError(str):
    """Report parse error."""
    print("config error in '" + configFile + "': " + str, file=sys.stderr)

def readCameraConfig(config):
    """Read single camera configuration."""
    cam = CameraConfig()

    # name
    try:
        cam.name = config["name"]
    except KeyError:
        parseError("could not read camera name")
        return False

    # path
    try:
        cam.path = config["path"]
    except KeyError:
        parseError("camera '{}': could not read path".format(cam.name))
        return False

    # stream properties
    cam.streamConfig = config.get("stream")

    cam.config = config

    cameraConfigs.append(cam)
    return True

def readSwitchedCameraConfig(config):
    """Read single switched camera configuration."""
    cam = CameraConfig()

    # name
    try:
        cam.name = config["name"]
    except KeyError:
        parseError("could not read switched camera name")
        return False

    # path
    try:
        cam.key = config["key"]
    except KeyError:
        parseError("switched camera '{}': could not read key".format(cam.name))
        return False

    switchedCameraConfigs.append(cam)
    return True

def readConfig():
    """Read configuration file."""
    global team
    global server

    # parse file
    try:
        with open(configFile, "rt", encoding="utf-8") as f:
            j = json.load(f)
    except OSError as err:
        print("could not open '{}': {}".format(configFile, err), file=sys.stderr)
        return False

    # top level must be an object
    if not isinstance(j, dict):
        parseError("must be JSON object")
        return False

    # team number
    try:
        team = j["team"]
    except KeyError:
        parseError("could not read team number")
        return False

    # ntmode (optional)
    if "ntmode" in j:
        str = j["ntmode"]
        if str.lower() == "client":
            server = False
        elif str.lower() == "server":
            server = True
        else:
            parseError("could not understand ntmode value '{}'".format(str))

    # cameras
    try:
        cameras = j["cameras"]
    except KeyError:
        parseError("could not read cameras")
        return False
    for camera in cameras:
        if not readCameraConfig(camera):
            return False

    # switched cameras
    if "switched cameras" in j:
        for camera in j["switched cameras"]:
            if not readSwitchedCameraConfig(camera):
                return False

    return True

def startCamera(config):
    """Start running the camera."""
    print("Starting camera '{}' on {}".format(config.name, config.path))
    inst = CameraServer.getInstance()
    camera = UsbCamera(config.name, config.path)
    server = inst.startAutomaticCapture(camera=camera, return_server=True)

    camera.setConfigJson(json.dumps(config.config))
    camera.setConnectionStrategy(VideoSource.ConnectionStrategy.kKeepOpen)

    if config.streamConfig is not None:
        server.setConfigJson(json.dumps(config.streamConfig))

    return camera

def startSwitchedCamera(config):
    """Start running the switched camera."""
    print("Starting switched camera '{}' on {}".format(config.name, config.key))
    server = CameraServer.getInstance().addSwitchedCamera(config.name)

    def listener(fromobj, key, value, isNew):
        if isinstance(value, float):
            i = int(value)
            if i >= 0 and i < len(cameras):
              server.setSource(cameras[i])
        elif isinstance(value, str):
            for i in range(len(cameraConfigs)):
                if value == cameraConfigs[i].name:
                    server.setSource(cameras[i])
                    break

    NetworkTablesInstance.getDefault().getEntry(config.key).addListener(
        listener,
        ntcore.constants.NT_NOTIFY_IMMEDIATE |
        ntcore.constants.NT_NOTIFY_NEW |
        ntcore.constants.NT_NOTIFY_UPDATE)

    return server

class Pipeline:

    """
    An OpenCV pipeline generated by GRIP.
    """

    def __init__(self):
        """initializes all values to presets or None if need to be set
        """

        self.__hsv_threshold_hue = [38.84891468843968, 92.96928718228388]
        self.__hsv_threshold_saturation = [175.80937019569413, 255.0]
        self.__hsv_threshold_value = [122.30215535747061, 255.0]

        self.hsv_threshold_output = None

        self.__cv_dilate_src = self.hsv_threshold_output
        self.__cv_dilate_kernel = None
        self.__cv_dilate_anchor = (-1, -1)
        self.__cv_dilate_iterations = 6.0
        self.__cv_dilate_bordertype = cv2.BORDER_CONSTANT
        self.__cv_dilate_bordervalue = (-1)

        self.cv_dilate_output = None

        self.__cv_erode_src = self.cv_dilate_output
        self.__cv_erode_kernel = None
        self.__cv_erode_anchor = (-1, -1)
        self.__cv_erode_iterations = 4.0
        self.__cv_erode_bordertype = cv2.BORDER_CONSTANT
        self.__cv_erode_bordervalue = (-1)

        self.cv_erode_output = None

        self.__find_contours_input = self.cv_erode_output
        self.__find_contours_external_only = False

        self.find_contours_output = None

        self.__filter_contours_contours = self.find_contours_output
        self.__filter_contours_min_area = 1500.0
        self.__filter_contours_min_perimeter = 0.0
        self.__filter_contours_min_width = 0.0
        self.__filter_contours_max_width = 1000.0
        self.__filter_contours_min_height = 0.0
        self.__filter_contours_max_height = 1000.0
        self.__filter_contours_solidity = [0, 100.0]
        self.__filter_contours_max_vertices = 1000000.0
        self.__filter_contours_min_vertices = 0.0
        self.__filter_contours_min_ratio = 0.0
        self.__filter_contours_max_ratio = 1000.0

        self.filter_contours_output = None

    def process(self, source0):
        """
        Runs the pipeline and sets all outputs to new values.
        """
        # Step HSV_Threshold0:
        self.__hsv_threshold_input = source0
        (self.hsv_threshold_output) = self.__hsv_threshold(self.__hsv_threshold_input, self.__hsv_threshold_hue, self.__hsv_threshold_saturation, self.__hsv_threshold_value)

        # Step CV_dilate0:
        self.__cv_dilate_src = self.hsv_threshold_output
        (self.cv_dilate_output) = self.__cv_dilate(self.__cv_dilate_src, self.__cv_dilate_kernel, self.__cv_dilate_anchor, self.__cv_dilate_iterations, self.__cv_dilate_bordertype, self.__cv_dilate_bordervalue)

        # Step CV_erode0:
        self.__cv_erode_src = self.cv_dilate_output
        (self.cv_erode_output) = self.__cv_erode(self.__cv_erode_src, self.__cv_erode_kernel, self.__cv_erode_anchor, self.__cv_erode_iterations, self.__cv_erode_bordertype, self.__cv_erode_bordervalue)

        # Step Find_Contours0:
        self.__find_contours_input = self.cv_erode_output
        (self.find_contours_output) = self.__find_contours(self.__find_contours_input, self.__find_contours_external_only)

        # Step Filter_Contours0:
        self.__filter_contours_contours = self.find_contours_output
        (self.filter_contours_output) = self.__filter_contours(self.__filter_contours_contours, self.__filter_contours_min_area, self.__filter_contours_min_perimeter, self.__filter_contours_min_width, self.__filter_contours_max_width, self.__filter_contours_min_height, self.__filter_contours_max_height, self.__filter_contours_solidity, self.__filter_contours_max_vertices, self.__filter_contours_min_vertices, self.__filter_contours_min_ratio, self.__filter_contours_max_ratio)

    @staticmethod
    def __hsv_threshold(input, hue, sat, val):
        """Segment an image based on hue, saturation, and value ranges.
        Args:
            input: A BGR numpy.ndarray.
            hue: A list of two numbers the are the min and max hue.
            sat: A list of two numbers the are the min and max saturation.
            lum: A list of two numbers the are the min and max value.
        Returns:
            A black and white numpy.ndarray.
        """
        out = cv2.cvtColor(input, cv2.COLOR_BGR2HSV)
        return cv2.inRange(out, (hue[0], sat[0], val[0]),  (hue[1], sat[1], val[1]))

    @staticmethod
    def __cv_dilate(src, kernel, anchor, iterations, border_type, border_value):
        """Expands area of higher value in an image.
        Args:
           src: A numpy.ndarray.
           kernel: The kernel for dilation. A numpy.ndarray.
           iterations: the number of times to dilate.
           border_type: Opencv enum that represents a border type.
           border_value: value to be used for a constant border.
        Returns:
            A numpy.ndarray after dilation.
        """
        return cv2.dilate(src, kernel, anchor, iterations = (int) (iterations +0.5),
                            borderType = border_type, borderValue = border_value)

    @staticmethod
    def __cv_erode(src, kernel, anchor, iterations, border_type, border_value):
        """Expands area of lower value in an image.
        Args:
           src: A numpy.ndarray.
           kernel: The kernel for erosion. A numpy.ndarray.
           iterations: the number of times to erode.
           border_type: Opencv enum that represents a border type.
           border_value: value to be used for a constant border.
        Returns:
            A numpy.ndarray after erosion.
        """
        return cv2.erode(src, kernel, anchor, iterations = (int) (iterations +0.5),
                            borderType = border_type, borderValue = border_value)

    @staticmethod
    def __find_contours(input, external_only):
        """Sets the values of pixels in a binary image to their distance to the nearest black pixel.
        Args:
            input: A numpy.ndarray.
            external_only: A boolean. If true only external contours are found.
        Return:
            A list of numpy.ndarray where each one represents a contour.
        """
        if(external_only):
            mode = cv2.RETR_EXTERNAL
        else:
            mode = cv2.RETR_LIST
        method = cv2.CHAIN_APPROX_SIMPLE
        im2, contours, hierarchy =cv2.findContours(input, mode=mode, method=method)
        return contours

    @staticmethod
    def __filter_contours(input_contours, min_area, min_perimeter, min_width, max_width,
                        min_height, max_height, solidity, max_vertex_count, min_vertex_count,
                        min_ratio, max_ratio):
        """Filters out contours that do not meet certain criteria.
        Args:
            input_contours: Contours as a list of numpy.ndarray.
            min_area: The minimum area of a contour that will be kept.
            min_perimeter: The minimum perimeter of a contour that will be kept.
            min_width: Minimum width of a contour.
            max_width: MaxWidth maximum width.
            min_height: Minimum height.
            max_height: Maximimum height.
            solidity: The minimum and maximum solidity of a contour.
            min_vertex_count: Minimum vertex Count of the contours.
            max_vertex_count: Maximum vertex Count.
            min_ratio: Minimum ratio of width to height.
            max_ratio: Maximum ratio of width to height.
        Returns:
            Contours as a list of numpy.ndarray.
        """
        output = []
        for contour in input_contours:
            x,y,w,h = cv2.boundingRect(contour)
            if (w < min_width or w > max_width):
                continue
            if (h < min_height or h > max_height):
                continue
            area = cv2.contourArea(contour)
            if (area < min_area):
                continue
            if (cv2.arcLength(contour, True) < min_perimeter):
                continue
            hull = cv2.convexHull(contour)
            solid = 100 * area / cv2.contourArea(hull)
            if (solid < solidity[0] or solid > solidity[1]):
                continue
            if (len(contour) < min_vertex_count or len(contour) > max_vertex_count):
                continue
            ratio = (float)(w) / h
            if (ratio < min_ratio or ratio > max_ratio):
                continue
            output.append(contour)
        return output

if __name__ == "__main__":
    if len(sys.argv) >= 2:
        configFile = sys.argv[1]

    # read configuration
    if not readConfig():
        sys.exit(1)

    # start NetworkTables
    ntinst = NetworkTablesInstance.getDefault()
    if server:
        print("Setting up NetworkTables server")
        ntinst.startServer()
    else:
        print("Setting up NetworkTables client for team {}".format(team))
        ntinst.startClientTeam(team)

    # start cameras
    for config in cameraConfigs:
        cameras.append(startCamera(config))

    # start switched cameras
    for config in switchedCameraConfigs:
        startSwitchedCamera(config)

    # prefix of vision processing
    inst = CameraServer.getInstance() # 取得 Camera Server
    pipeline = Pipeline() # 定義 pipeline 為 Pipeline() 類別
    videoCap = inst.getVideo(name='cam 0') # 定義 videoCap 為 cam 0 的影像
    output = inst.putVideo('vs', 320, 240) # 定義 output 為 Dashboard 中新的影像來源 名稱為 vs 寬度 320 高度240

    # preallocate new images
    img = numpy.zeros(shape=(240, 320, 3), dtype=numpy.uint8) # 預先建立 img 圖像 內容全為0
    frame = videoCap.grabFrame(None, timeout=0.5)[1] # 預先從 videoCap 中取得一次畫面

    # NetworkTables init
    table = NetworkTables.getTable('/vision/vs') # 預先取得 Network Table 中的 /vision/vs 內容
    table.setDefaultNumber('x', -1)
    table.setDefaultNumber('y', -1)
    table.setDefaultNumber('area', -1) # 設定 x,y,area 值預設為 -1 避免誤判

    # loop forever
    while True:
        # get image
        frame = videoCap.grabFrame(frame, timeout=0.5)[1] # 從 videoCap 中取得影像
        img = frame # img 定為鏡頭原像

        # processing
        pipeline.process(frame) # 使用 GRIP 的流程進行處理

        # process with any result
        biggest = {'x': -1, 'y': -1, 'area': -1} # 定義最大的球
        for contour in pipeline.filter_contours_output: # 針對每一個找到的結果判別
            # get point
            x, y, w, h = cv2.boundingRect(contour) # 尋找端點

           # compare with biggest
            a = cv2.contourArea(contour)
            if a > biggest['area']:
                biggest['x'] = x+w/2 # 中心點 x 座標
                biggest['y'] = y # 中心點 y 座標
                biggest['area'] = a

            # draw on output img
            img = cv2.line(img, (x, y), (x+w, y), (0, 255, 0), 2) # 標出六角形中心點(十字)
            img = cv2.line(img, (int(x+w/2), y-h), (int(x+w/2), y+h), (0, 255, 0), 2)
            img = cv2.putText(img, 'vs', (x, y-30), cv2.FONT_HERSHEY_DUPLEX, 0.5, (0, 0, 0))
            text = 'x: ' + str(x+w/2) + 'y: ' + str(y) # 對六角形標示中心點座標
            img = cv2.putText(img, text, (x, y-30), cv2.FONT_HERSHEY_DUPLEX, 0.5, (0, 255, 0))

        # push value onto Table
        table.putNumber('x', biggest['x']) # 將最大的球的座標值送上 Network Table 方便從機台的程式讀取
        table.putNumber('y', biggest['y'])
        table.putNumber('area', biggest['area'])

        # output image onto dashboard
        output.putFrame(img) # 將繪圖過的圖片輸出至 Dashboard

        # sleep to wait update
        # time.sleep(10)

2020 raspberry pi vision written by Brian Chen.py


""" Toyhou.se scraper cog, adds interactive commands with Toyhou.se website """
import functions
import discord
import userdb
import asyncio
import os

from discord.ext import commands
from functions import functions
from toyhousescraper import ToyHouseScraper
from functools import partial

class ToyHouse(commands.Cog):
    """
    Discord Bot Cog, adds user interaction with images on Toyhou.se website
    """

    def __init__(self, bot):
        self.bot = bot
        self.scraper = ToyHouseScraper()
        self.db = userdb.UserDBService()
        self.img_count = 10

    @commands.Cog.listener()
    async def on_ready(self):
        """ Confirms cog load """
        print("✨ Toyhou.se is being herded! ✨")

    @commands.command()
    async def link(self, ctx):
        """
        Links a discord user to a toyhouse user account

        Toyhouse user profile must be set to visible to guests or these bot features
        will be unavailable.
        """
        await ctx.send(embed=functions.base_embed(
            title="Link Account",
            text="Tell me your Toyhou.se username and I'll link it!"
        ))

        # Message retrieval and verification
        try:
            msg = await self.bot.wait_for("message", check=partial(functions.basic_msg_check, ctx), timeout=45)
            self.scraper.set_route(msg.content)
            user_page_exists = self.scraper.verify_user_found()

        # Timeout command
        except asyncio.TimeoutError:
            await ctx.send(embed=functions.base_embed(
                title="Ok",
                text=f"Times up! Call me back if you'd like to link accounts ⏰"
            ))
            return

        # Confirm page accuracy
        if user_page_exists:
            verify_msg = await ctx.send(embed=functions.user_confirm_embed(
                user_page=self.scraper.route,
                user_name=msg.content.title()
            ))
        else:
            await ctx.send(embed=functions.base_embed(
                title="Link Account",
                text="Well this is awkward... that profile was either not found on Toyhou.se "
                     "or the user is not visible to guests 😬"
            ))
            return

        # Confirm reaction set
        await verify_msg.add_reaction("✅")
        await verify_msg.add_reaction("❌")

        # Wait for user reaction
        try:
            reaction, user = await self.bot.wait_for(
                "reaction_add",
                check=partial(functions.basic_reaction_check, ctx),
                timeout=35)

        except asyncio.TimeoutError:
            await ctx.send(embed=functions.base_embed(
                title="Link Account",
                text="Times up! Call me back if you'd like to link accounts ⏰"
            ))
            return

        if str(reaction) == "❌":
            await verify_msg.delete()
            await ctx.send(embed=functions.base_embed(
                title="Link Account",
                text="Shoot, I missed! Make sure you gave me your correct username! 😅"
            ))
            return

        await verify_msg.delete()
        # Save user ID and Toyhou.se account name
        # If user is not in the DB, insert and advise, else update and advise
        if not self.db.query_id(ctx.author.id):
            self.db.insert(ctx.author.id, ctx.author.name, msg.content.title())
            await ctx.send(embed=functions.base_embed(
                title="Account Link",
                text="🌠 Successfuly Linked! Welcome to the meadow 🌠",
                footer=f"{ctx.author.name} linked to {msg.content}."
            ))
        else:
            self.db.update_th_account(ctx.author.id, msg.content.title())
            await ctx.send(embed=functions.base_embed(
                title="Account Link",
                text="🌠 Welcome back! I updated your link! 🌠",
                footer=f"{ctx.author.name} linked to {msg.content}."
            ))

    @commands.command()
    async def random(self, ctx):
        """ Display a random file image of a character from your linked Toyhouse account """
        user = self.db.query_id(ctx.message.author.id)
        if user:
            self.scraper.set_route(user.th_account)
            path, caption = self.scraper.scrape_random_image()
            file = discord.File(path, filename="image.png")
            await ctx.send(embed=functions.random_img_embed(
                caption=caption, msg_author=user.th_account), file=file)
            os.remove(path)

        else:
            await ctx.send(embed=functions.base_embed(
                title="No Linked Account",
                text="You need to link your Toyhou.se account before using this command!"))

def setup(bot):
    """ Required setup function for cog """
    bot.add_cog(ToyHouse(bot))


from api.magic.filetype import *
from api.vfs import *
from api.env import *
from api.loader import *
from api.module.module import *
from api.module.script import *

class FILEINFO(Script):
  def __init__(self):
      Script.__init__(self, "fileinfo")
      self.ft = FILETYPE()
  def start(self, args):
    buff = ""
    node = args.get_node("file")
    buff += "File " + node.path + "/" + node.name
    if not node.next.empty():
      buff += " is linked to\n" + str(node.next.size()) + " files\n"
    elif node.is_file == 1:
      buff += " as data content\n"

      buff += "Size:" + str(node.attr.size) + " \n"
    elif not node.next.empty() and node.is_dir:
      buff += " as data content and is linked to " + (node.next.size()) + " files\n"
      buff += "Size:" + str(node.attr.size) + " \n"
    self.ft.filetype(node)
    map =  node.attr.smap
    for i in map:
      buff += i + ":" + map[i] + "\n"
    map =  node.attr.imap
    for i in map:
      buff += i + ":" + str(map[i]) + "\n"
    map =  node.attr.time
    for i in map:
      buff += i + ":" + str(map[i].get_time()) + "\n"
    if node.is_file == 1:
      n = self.ft.findcompattype(node)
      if len(n):
        buff += "Compatible drivers:\n"
        for i in n:
          buff += i + "\n"
    self.res.add_const("result", buff)

class fileinfo(Module):
  def __init__(self):
    Module.__init__(self, "fileinfo",  FILEINFO)
    self.conf.add("file", "node")
    self.tags = "information"


import urllib.request
import json
import dml
import prov.model
import datetime
import uuid
import pprint
import csv

class garden_vs_rent(dml.Algorithm):

    contributor = 'alyu_sharontj_yuxiao_yzhang11'
    reads = ['alyu_sharontj_yuxiao_yzhang11.garden_count','alyu_sharontj_yuxiao_yzhang11.average_rent_zip']
    writes = ['alyu_sharontj_yuxiao_yzhang11.garden_vs_rent']

    @staticmethod
    def execute(trial=False):
        '''Retrieve some data sets (not using the API here for the sake of simplicity).'''
        startTime = datetime.datetime.now()

        # Set up the database connection.
        client = dml.pymongo.MongoClient()
        repo = client.repo
        repo.authenticate('alyu_sharontj_yuxiao_yzhang11', 'alyu_sharontj_yuxiao_yzhang11')

        garden_count = repo['alyu_sharontj_yuxiao_yzhang11.garden_count']
        average_rent = repo['alyu_sharontj_yuxiao_yzhang11.average_rent_zip']

        # print("i am here ")
        # s = average_rent.find_one({"Zip": "11111"})
        # print(s == None)
        #pprint.pprint(average_rent.find_one({"Zip": "02169"}))
        repo.dropCollection("garden_vs_rent")
        repo.createCollection("garden_vs_rent")

        garden_cur = garden_count.find()
        rent_cur = average_rent.find()
        for i in rent_cur:
            garden_vs_rent= {}
            rent_zip = i["Zip"]
            # print("rent zip", rent_zip)
            garden_vs_rent["Zip"] = rent_zip
            garden_vs_rent["Average"] = i["Average"]

            if (garden_count.find_one({"_id": rent_zip}) != None):

                garden_vs_rent["garden_count"] = garden_count.find_one({"_id": rent_zip})['count']
            else:
                garden_vs_rent["garden_count"] = 0

            repo['alyu_sharontj_yuxiao_yzhang11.garden_vs_rent'].insert(garden_vs_rent)

        # print("INNN garden_vs_rent")
        endTime = datetime.datetime.now()

        return {"start": startTime, "end": endTime}

    @staticmethod
    def provenance(doc=prov.model.ProvDocument(), startTime=None, endTime=None):
        '''
            Create the provenance document describing everything happening
            in this script. Each run of the script will generate a new
            document describing that invocation event.
            '''

        # Set up the database connection.
        client = dml.pymongo.MongoClient()
        repo = client.repo
        repo.authenticate('alyu_sharontj_yuxiao_yzhang11', 'alyu_sharontj_yuxiao_yzhang11')
        doc.add_namespace('alg', 'http://datamechanics.io/algorithm/')  # The scripts are in <folder>#<filename> format.
        doc.add_namespace('dat', 'http://datamechanics.io/data/')  # The data sets are in <user>#<collection> format.
        doc.add_namespace('ont',
                          'http://datamechanics.io/ontology#')  # 'Extension', 'DataResource', 'DataSet', 'Retrieval', 'Query', or 'Computation'.
        doc.add_namespace('log', 'http://datamechanics.io/log/')  # The event log.
        doc.add_namespace('bdp', 'https://data.boston.gov/export/767/71c/')

        this_script = doc.agent('alg:alyu_sharontj_yuxiao_yzhang11#garden_vs_rent',
                                {prov.model.PROV_TYPE: prov.model.PROV['SoftwareAgent'], 'ont:Extension': 'py'})

        garden_input = doc.entity('dat:alyu_sharontj_yuxiao_yzhang11#garden_count',
                                  {prov.model.PROV_LABEL: 'garden_count',
                                   prov.model.PROV_TYPE: 'ont:DataSet'})

        rent_input = doc.entity('dat:alyu_sharontj_yuxiao_yzhang11#average_rent_zip',
                                  {prov.model.PROV_LABEL: 'average_rent_zip',
                                   prov.model.PROV_TYPE: 'ont:DataSet'})

        this_run = doc.activity('log:uuid' + str(uuid.uuid4()), startTime, endTime)

        output =  doc.entity('dat:alyu_sharontj_yuxiao_yzhang11#garden_vs_rent',
                             {prov.model.PROV_LABEL:'garden_vs_rent',
                              prov.model.PROV_TYPE:'ont:DataSet'})

        # get_lost = doc.activity('log:uuid' + str(uuid.uuid4()), startTime, endTime)
        #
        doc.wasAssociatedWith(this_run, this_script)
        doc.used(this_run, garden_input, startTime)
        doc.used(this_run, rent_input, startTime)

        doc.wasAttributedTo(output, this_script)
        doc.wasGeneratedBy(output, this_run, endTime)
        doc.wasDerivedFrom(output, garden_input, this_run, this_run, this_run)
        doc.wasDerivedFrom(output, rent_input, this_run, this_run, this_run)

        repo.logout()

        return doc

# garden_vs_rent.execute()
# doc = garden_vs_rent.provenance()
# print(doc.get_provn())
# print(json.dumps(json.loads(doc.serialize()), indent=4))

## eof


# @tag qsort, quicksort, 퀵정렬
import sys

count = int(input())

nums = list(map(lambda n: int(sys.stdin.readline().rstrip()), range(count)))

def merge(left, right):
    merged = []
    l_point, r_point = 0, 0

    while len(left) > l_point and len(right) > r_point:
        if left[l_point] > right[r_point]:
            merged.append(right[r_point])
            r_point += 1
        else:
            merged.append(left[l_point])
            l_point += 1
    while len(left) > l_point:
        merged.append(left[l_point])
        l_point += 1
    while len(right) > r_point:
        merged.append(right[r_point])
        r_point += 1

    return merged

def merges_split(data):
    if len(data) <= 1:
        return data
    medium = int(len(data) / 2)
    left = merges_split(data[:medium])
    right = merges_split(data[medium:])
    return merge(left, right)

for n in merges_split(nums):
    print(n)


import json

persona = {}
def abrir_archivo(ruta: str):
    cadena: list = ruta.split('.')
    if cadena[1].lower() == 'json':
        try:
            #Referencias el fichero
            with open(ruta) as archivo:
                #Cargar los datos del archivo json
                persona = json.load(archivo)
                print(persona)
        except:
            print('Error al cargar los datos')
    else:
        print('Extensión inválida')

abrir_archivo('persona.json')

#Referenciar el fichero
""" with open('personas.json','w') as archivo:
    #Escribir/crear el fichero
    json.dump(persona, archivo) """


#!/usr/bin/env python
from __future__ import print_function
import os, sys, argparse, shlex, subprocess
from args import get_parser

def convertTuple(tup):
    str =  "".join(tup)
    return str

def setup_slurm_script(args):
  input_path = args.input_path
  output_path = args.output_path

  debug_print = print if args.verbose else lambda *args: None

  # Path to this script
  self_path = os.path.realpath(__file__)
  self_dir = os.path.dirname(self_path)
  matlab_code_path = os.path.join(self_dir, '/matlabCodes/')
  sbatch_flags = ["-N 1",
                "-c 1",
                "--mem=16000",

                ]

  debug_print ("============================")
  debug_print ("Slurm sbatch flags:")
  debug_print ("\n".join(sbatch_flags))

  debug_print (matlab_code_path)
#                   "-dt" + " " + convertTuple(data_type))

  # segment_command = ["export PATH=/opt/MATLAB/R2018b/bin", "matlab", "-nodisplay",
  #                  "-nojvm",  "-r",
  #                  "cd " + matlab_code_path + "" + ";main\("+ input_path +"," +  output_path + "\)",
  #                 ]

  segment_command = ["export PATH=/opt/MATLAB/R2018b/bin", "matlab", "-nodisplay",
                   "-nojvm",
                   "cd " + matlab_code_path + "",  "-r", "main",
                  ]

  debug_print(segment_command)
  segment_command_str = " ".join(segment_command)

  debug_print ("============================")
  debug_print ("Segment command:")
  debug_print (segment_command_str)
  segment_command_wrapped = '--wrap=" ' + segment_command_str + '"'
  # Construct sbatch command
  sbatch_command = ["sbatch"] + sbatch_flags + [segment_command_wrapped]
  sbatch_command_str = " ".join(sbatch_command)
  debug_print ("============================")
  debug_print ("Slurm sbatch command:")
  debug_print (sbatch_command_str)

  print ("============================")
  final_sbatch_command = shlex.split(sbatch_command_str)
  p = subprocess.Popen(final_sbatch_command)
  p.wait()
  print ("Success!")
  print ("============================")
  sys.stdout.flush()

if __name__ == "__main__":

    args = get_parser()
    setup_slurm_script(args)


"""Write a program that reads a file and prints the letters in decreasing
order of frequency. Your program should convert all the input to lower case and
only count the letters a-z. Your program should not count spaces, digits, punctuation,
or anything other than the letters a-z. Find text samples from several different
languages and see how letter frequency varies between languages. Compare your
results with the tables at wikipedia.org/wiki/Letter_frequencies."""
import string
import matplotlib.pyplot as plt

fname = input("Enter the filname: ")

try:
    fhand = open(fname)
except:
    print("Invalid filename")
    exit()

lfq = {}         #intialize letter frequency dictionary

for line in fhand:                              #parse through each line of the file
    line = line.translate(str.maketrans('','',string.punctuation)) #get rid of punctuation marks using the translate method
    line = line.lower()                     #convert all string to lowercase
    words = line.split()                   #create a list of words using the split method
    if len(words) == 0 :
        continue
    for word in words:                   #loop through each word in the words list
        letters = str(word)             #convert each word in the list to string
        for var in letters:                 #loop through each character in the word
            if var >= "a" and var<="z":            #if the character is an alphabet, add it to the dictionary
                lfq[var] = lfq.get(var,0) + 1         #adding to the dictionary using the GET method
            else:
                continue                         #skip uninteresting characters

letterlist = sorted(lfq.items())          #create a sorted list (of tuples) by calling SORTED function on dictionary.items()
#which returns a list of tuples(key,value)
letter_list = []
freq_list = []

for letter,freq in letterlist:                  #loop through the sorted list (letter, freq is the tuple assignment, Since each element of the list is a tuple)
    print(letter,freq)
    letter_list.append(letter)
    freq_list.append(freq)
#print(len(letter_list))
#print(len(freq_list))

plt.xlabel("Letters",color="Green")
plt.ylabel("Frequency",color="Green")
plt.title("Letter Frequency distribution in '%s'"%fname,color="Green")

plt.bar(letter_list,freq_list)
plt.show()


import speech_recognition as sr
import nltk
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')
nltk.download('stopwords')
from nltk.tokenize import word_tokenize, sent_tokenize
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
import string
import streamlit as st

# Initialize the speech recognition recognizer
r = sr.Recognizer()

with open('geology.txt', 'r', encoding='utf-8') as f:
    data = f.read().replace('\n', ' ')

# Tokenize the text into sentences
sentences = sent_tokenize(data)
# Define a function to preprocess each sentence
def preprocess(sentence):
    # Tokenize the sentence into words
    words = word_tokenize(sentence)
    # Remove stopwords and punctuation
    words = [word.lower() for word in words if word.lower() not in stopwords.words('english') and word not in string.punctuation]
    # Lemmatize the words
    lemmatizer = WordNetLemmatizer()
    words = [lemmatizer.lemmatize(word) for word in words]
    return words

# Preprocess each sentence in the text
corpus = [preprocess(sentence) for sentence in sentences]

# Define a function to find the most relevant sentence given a query
def get_most_relevant_sentence(query):
    # Preprocess the query
    query = preprocess(query)
    # Compute the similarity between the query and each sentence in the text
    max_similarity = 0
    most_relevant_sentence = ""
    for sentence in corpus:
        similarity = len(set(query).intersection(sentence)) / float(len(set(query).union(sentence)))
        if similarity > max_similarity:
            max_similarity = similarity
            most_relevant_sentence = " ".join(sentence)
    return most_relevant_sentence
def chatbot(question):
    # Find the most relevant sentence
    most_relevant_sentence = get_most_relevant_sentence(question)
    # Return the answer
    return most_relevant_sentence

def transcribe_speech():
    with sr.Microphone() as source:
        st.info('Speak now...')
        print("This is only available for english speakers! Thanks for understanding!")
        audio_data = r.record(source, duration=5)
        print("Recognizing...")
        print("this is your recording: ",audio_data)
        try:
            text = r.recognize_google(audio_data)
            print(audio_data.get_wav_data(), text)
            st.write("Transcription:", text)
            return text
        except:
            print("Sorry I didn't get that or you run out of time")
            st.write("Sorry I didn't get that/You run out of time")

def main():
    st.title("Chatbot with Text/Speech Input")

    # Choose input type: Text or Speech
    input_type = st.radio("Choose input type:", ["Text", "Speech"])

    user_input = ""
    if input_type == "Text":
        user_input = st.text_input("User:")
    elif input_type == "Speech":
        user_input = transcribe_speech()

    if user_input:
        response = chatbot(user_input)
        st.write("Chatbot:", response)

if __name__ == "__main__":
    main()


from pathfinder import Pathfinder
from image_generator import ImageGenerator

class TestPathfinder:

    def integration_test(self):
        def test_square():
            plane_location = 1, 1
            boundaries = [(0, 0), (1000, 0), (1000, 1000), (0, 1000)]
            options = {
                "wind_angle_degrees": 45,
                "max_distance_between_waypoints": 150
            }
            finder = Pathfinder(plane_location, boundaries, options)
            ImageGenerator(finder).create_image("square.jpg")

        def test_square_scaled():
            plane_location = 0.1, 0.1
            boundaries = [(0, 0), (0.1, 0), (0.1, 0.1), (0, 0.1)]
            options = {
                    "wind_angle_degrees": 90,
                    "overshoot_distance": 0.0006,
                    "path_width": 0.006
            }
            finder = Pathfinder(plane_location, boundaries, options)
            ImageGenerator(finder).create_image("square_scaled.jpg")

        def test_rot_square():
            plane_location = 1, 1
            boundaries = [(500, 0), (0, 500), (-500, 0), (0, -500)]
            options = {
                "wind_angle_degrees": 90
            }
            finder = Pathfinder(plane_location, boundaries, options)
            ImageGenerator(finder).create_image("rot_square.jpg")

        def test_concave():
            plane_location = 1, 1
            boundaries = [(0, 0), (1000, 0), (500, 500), (1000, 1000), (0, 1000)]
            options = {
                "wind_angle_degrees": 90
            }
            finder = Pathfinder(plane_location, boundaries, options)
            ImageGenerator(finder).create_image("concave.jpg")

        def test_gps_coords():
            plane_location = 32.961043, -117.190664
            boundaries = [(32.961043, -117.190664),
            (32.961132, -117.188443),
            (32.962393, -117.187006),
            (32.962321, -117.189924)]
            options = {
                "wind_angle_degrees": 90,
                "overshoot_distance": 0.0001,
                "path_width": 0.0001
            }
            finder = Pathfinder(plane_location, boundaries, options)
            ImageGenerator(finder).create_image("gps.jpg")

        test_square()
        test_square_scaled()
        test_rot_square()
        test_concave()
        test_gps_coords()


#/usr/local/Cellar/python3/3.6.2
# -*- coding: utf-8 -*-

def printMsg(msg):
    print(msg)

def readTextFileAndPrint():
    path = '/Users/liuliu/input.txt'
    inputFile = open(path, 'r')
    lines = inputFile.readlines()

    for line in lines:
        printMsg(line)

    inputFile.close()

def saveMsgToFile():
    printMsg("save Msg To file中文")

    myMsg = '中文sedgwick'
    a = myMsg.encode('utf-8')
    d = a.decode('utf-8')
    fileName = '/Users/liuliu/myfile.txt'

    # with open(fileName, 'wt', encoding='utf-8') as f:
    #     f.write(myMsg)

    outPutFile = open(fileName, 'wt', encoding='utf-8')
    outPutFile.write(d)
    outPutFile.close()

if __name__ == '__main__':
    # print("this is my project")
    readTextFileAndPrint()
    s = 'Python-中文'
    print(s)
    b = s.encode('utf-8')
    print(b)
    print(b.decode('utf-8'))

    saveMsgToFile()


from .help import Help

def load(manager, params):
    """
    Create and launch a new instance of Help.
    """
    # default position
    pos = (100, 100)

    if params is not None and len(params) > 0:
        pos = params[0]

    Help(pos, manager)


import os
import numpy as np
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'  # da scegliere tra {'0', '1', '2'}
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.applications.nasnet import preprocess_input
from keras.applications.nasnet import decode_predictions
from keras.applications.nasnet import NASNetLarge

filename = input("Inserisci il nome della foto: ")

print("Preprocessing dati...")
# carica la foto
image = load_img(filename,target_size=(331,331))

# immagine -> array
image = img_to_array(image)

# reshape (batch)
image = np.array([image])
#image = image.reshape((1,image.shape[0],image.shape[1],image.shape[2]))

# preprocessing
image = preprocess_input(image)

# carico la cnn
print("Caricamento rete neurale...")
model = NASNetLarge(weights='imagenet')

#model.summary()
#input("Premi INVIO per continuare...")

# predict su tutte le classi in output
print("Running...")
prob = model.predict(image)

# probabilità -> label
label = decode_predictions(prob)

# i label più probabili
label1 = label[0][0]
label2 = label[0][1]
label3 = label[0][2]
label4 = label[0][3]
label5 = label[0][4]

# print
print('\nProbabilità:')
print('%s (%.2f%%)' % (label1[1],label1[2]*100))
print('%s (%.2f%%)' % (label2[1],label2[2]*100))
print('%s (%.2f%%)' % (label3[1],label3[2]*100))
print('%s (%.2f%%)' % (label4[1],label4[2]*100))
print('%s (%.2f%%)' % (label5[1],label5[2]*100))


import torch
import torch.nn as nn
import torch.nn.functional as F
import time

thresh = 0.5  # neuronal threshold
lens = 0.5  # hyper-parameters of approximate function

# Define approximate firing function
class ActFun(torch.autograd.Function):
    @staticmethod
    def forward(ctx, input):
        if input.requires_grad:
            ctx.save_for_backward(input)
        return input.gt(thresh).float()

    @staticmethod
    def backward(ctx, grad_output):
        input, = ctx.saved_tensors
        grad_input = grad_output.clone()
        temp = abs(input - thresh) < lens
        return grad_input * temp.float()

act_fun = ActFun.apply

class SCNN(nn.Module):
    def __init__(self, device, decay=0.8, init_gain=2.5, input_size=(304, 240, 2)): # input_size (x, y, c)
        super(SCNN, self).__init__()
        self.device = device
        self.decay = decay
        self.layers = []

        self.x = input_size[0]
        self.y = input_size[1]
        self.c = input_size[2]
        self.init_gain = init_gain  # Ensure starting spikerate
        self.s = "Input: " + str((1, self.c, self.y, self.x)) + "\n"  # string representation

        self.model = nn.ModuleList() # For pytorch functionality

        # Define network layout
        self.layers = (
            self.Conv2d(self, 16),
            self.MaxPool(self),
            self.Conv2d(self, 32),
            self.MaxPool(self),
            self.Conv2d(self, 64),
            self.MaxPool(self),
            self.Conv2d(self, 128),
            self.MaxPool(self),
            self.Conv2d(self, 256),
            self.MaxPool(self, stride=1),
            self.Conv2d(self, 512),
            self.MaxPool(self, stride=1),
            self.Conv2d(self, 1024)
        )

        self.output_spikes = torch.zeros(1, self.c, self.y, self.x, device=self.device)

    # Feed new inputs for continuous feedforward
    def feed(self, inputs):
        # Calculate firing based on input probabilities (approximates non-binary values such as gray)
        x = (inputs > torch.rand(inputs.size(), device=self.device)).float()

        for _, layer in enumerate(self.layers):
            x = layer.forward(x)

        self.output_spikes += x

    # Collect output from network
    def collect(self):
        outputs = self.output_spikes
        self.clear()
        return outputs

    # Clear output spikes
    def clear(self):
        self.output_spikes = torch.zeros(self.output_spikes.shape, device=self.device)

    # Reset membrane potentials and output spikes
    def reset_potentials(self):
        for i, layer in enumerate(self.layers):
            layer.reset()
        self.clear()

    def __str__(self):
        return self.s

    class Conv2d():
        def __init__(self, snn, f, size=3, stride=1):
            padding=1
            if snn.x % stride != 0 or snn.y % stride != 0:
                raise ValueError("Layer input", x, y, "would be rounded with stride", stride)

            self.snn = snn
            self.conv = nn.Conv2d(snn.c, f, kernel_size=size, stride=stride, padding=padding)
            nn.init.xavier_uniform_(self.conv.weight.data, gain=snn.init_gain) # Ensures an initial spike-rate

            snn.c = f
            snn.x = snn.x // stride
            snn.y = snn.y // stride
            snn.s += "Conv: " + str((1, snn.c, snn.y, snn.x)) + "\n"

            self.mem = self.spike = torch.zeros(1, snn.c, snn.y, snn.x, device=snn.device)
            snn.model.extend([self.conv]) # Used internally by pytorch

        # Iterative LIF model
        def forward(self, x):
            # Reset potential if last iteration spiked, otherwise decay it. Add new input.
            self.mem = self.mem * (1 - self.snn.decay) * (1. - self.spike) + self.conv(x)
            self.spike = act_fun(self.mem)  # Approximation firing
            return self.spike

        # Reset membrane potentials
        def reset(self):
            self.mem = self.spike = torch.zeros(self.mem.shape, device=self.snn.device)

    class AvgPool():
        def __init__(self, snn, size=2, stride=2):
            self.size = size
            self.stride = stride

            if snn.x % stride != 0 or snn.y % stride != 0:
                raise ValueError("Layer input size", snn.x, snn.y, "would get rounded with stride", stride)

            if stride == 1:  # For 0 padding
                snn.x -= size-1
                snn.y -= size-1
            else:
                snn.x = snn.x // stride
                snn.y = snn.y // stride
            snn.s += "Avg pool: " + str((1, snn.c, snn.y, snn.x)) + "\n"

        def forward(self, x):
            return F.avg_pool2d(x, self.size, stride=self.stride)

        def reset(self):
            return

    class MaxPool():
        def __init__(self, snn, size=2, stride=2):
            self.size = size
            self.stride = stride

            if snn.x % stride != 0 or snn.y % stride != 0:
                raise ValueError("Layer input size", snn.x, snn.y, "would get rounded with stride", stride)

            if stride == 1:  # For 0 padding
                snn.x -= size-1
                snn.y -= size-1
            else:
                snn.x = snn.x // stride
                snn.y = snn.y // stride
            snn.s += "Max pool: " + str((1, snn.c, snn.y, snn.x)) + "\n"

        def forward(self, x):
            return F.max_pool2d(x, self.size, stride=self.stride)

        def reset(self):
            return


import utils
import player
import planet

import random
from math import sqrt
from collections import deque
from easymunk import pyxel as phys, Vec2d
from easymunk import Constraint, Arbiter
import pyxel

class Game:
    def __init__(self):
        self.camera = phys.Camera(flip_y=False)
        self.space = phys.space(
            camera = self.camera,
            elasticity = 1.0,
        )

        # Inicializa objetos
        self.state = utils.GameState.RUNNING

        self.player = player.Player(30, 30)
        self.player.register(self.space, self.message)

        self.planet1 = planet.Planet(100, 100)
        self.planet1.register(self.space, self.message)

        self.planet2 = planet.Planet(180, 110)
        self.planet2.register(self.space, self.message)

        self.particles = utils.Particles(self.space)

        # Cria margem
        L = 48
        phys.margin(-L, -L, pyxel.width + 2 * L, pyxel.width + 2 * L, radius = 5)

    # Administra colisões
        self.space.collision_handler(
            utils.ColType.PLAYER, utils.ColType.PLANET, post_solve=self.on_collision
        )

    def on_collision(self, arb: Arbiter):
        d1 = abs(self.player.player_body.position.x - self.planet1.planet_body.position.x) + abs(self.player.player_body.position.y - self.planet1.planet_body.position.y)
        d2 = abs(self.player.player_body.position.x - self.planet2.planet_body.position.x) + abs(self.player.player_body.position.y - self.planet2.planet_body.position.y)

        if self.player.planet_joint is not None:
            self.player.planet_joint.max_force = 0

        if d1 < d2:
            self.player.planet_joint = self.player.player_body.junction(self.planet1.planet_body).pivot()
            self.player.landed_on = self.planet1
            print("hey")
        else:
            self.player.planet_joint = self.player.player_body.junction(self.planet2.planet_body).pivot()
            self.player.landed_on = self.planet2

        self.player.planet_joint.max_force = float("inf")

        for _ in range(2):
            self.particles.emmit(
                position=self.player.player_body.local_to_world((random.uniform(-2, 2), -3)),
                velocity=(0, 0) #-random.uniform(50, 90) * self.player.player_body.rotation_vector.rotated(90),
            )

    def message(self, msg, sender):
        fn = getattr(self, f'handle_{msg}', None)
        if fn is None:
            print(f'Mensagem desconhecida: "{msg} ({sender})')
        else:
            fn(sender)

    def update(self):
        self.space.step(1 / 30, 2)

        # Atualiza lógica caso o jogo esteja rodando
        if self.state is not utils.GameState.GAME_OVER:
            self.player.update(self.camera)
            self.planet1.update()
            self.planet2.update()

        # Camera segue o Player
        self.camera.follow(self.player.player_body.position)

        # atualiza particulas
        self.particles.update()

    def draw(self):
        pyxel.cls(0)

        for body in self.space.bodies:
            if isinstance(body, (player.Player, planet.Planet)):
                body.draw(self.camera)
            else:
                self.camera.draw(body)

        self.player.draw(self.camera)
        self.planet1.draw(self.camera)
        self.planet2.draw(self.camera)
        self.particles.draw(self.camera)

pyxel.init(utils.WIDTH, utils.HEIGHT)
pyxel.mouse(True)
game = Game()
pyxel.run(game.update, game.draw)


import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))

DATABASES = {
    'default': {
        # 数据库驱动  Database driver
        'ENGINE': 'django.db.backends.sqlite3',
        # 如果是mysql等数据库 这里应该是数据库名
        # Replace it with Database Name if use other DATABASES
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

INSTALLED_APPS = (
    'db',
)

# 强烈建议修改并 保护好它
# SECURITY WARNING: keep the secret key used in production secret,recommended to modify it!!
SECRET_KEY = '6few3nci_q_o@l1dlbk81%wcxe!*6r29yu629&d97!hiqat9fa'


import pydicom
# from openpyxl import load_workbook
from collections import Counter
import xlrd
from random import shuffle
import scipy.misc as sp
import matplotlib.pyplot as plt
import os
import logging
import numpy as np

def parse_xsl(path):
    """
    parse_xsl from table to list of dicts
    :param path: str - path of xslx file
    :return samples: list of dicts by rows. Each value is sorted by the column's name as the key
    """
    wb = xlrd.open_workbook(path)
    ws = wb.sheet_by_index(0)
    num_of_rows = ws.nrows
    num_of_cols = ws.ncols

    samples = []
    for i in range(1, num_of_rows):
        sample = dict()
        for j in range(num_of_cols):
            sample[str(ws.cell(0, j).value)] = str(ws.cell(i, j).value)
        samples.append(sample)

    format_accession_field(samples)
    return samples

def format_accession_field(samples):

    for sample in samples:
        try:
            float(sample['Accession'])
            sample['Accession'] = sample['Accession'].split('.')[0]
        except ValueError:
            pass

def samples_to_lables(samples):
    """
    seperate between plural efusion positive and negative and return lists of Accession field
    :param samples: list of samples generated from xl file
    :return plural_efusion_positive: list of positive samples' Accession
    :return all_the_rest: list of negative samples' Accession
    """
    plural_efusion_positive = [sample['Accession'] for sample in samples if (sample['Taflitright'] == '1.0' or
                                                                             sample['Taflitleft'] == '1.0')]
    all_the_rest = [sample['Accession'] for sample in samples if (sample['Taflitright'] == '0.0' and
                                                                  sample['Taflitleft'] == '0.0')]

    return plural_efusion_positive, all_the_rest

def unite_labels(samples_dict):

    samples = []
    for k, val in samples_dict.items():
        [samples.append({'Accession': sample, 'label': int(k)}) for sample in val]
    return samples

def load_images_to_samples(samples):
    pass

def eliminate_multiple_occurrences(dataset_descript):

    access_list = [sample['Accession'] for sample in dataset_descript]

    counter = Counter(access_list)

    multiple_occurence = [key for key, val in counter.items() if val > 1]

    for key in multiple_occurence:
        samples = [{'sample': sample, 'index': i} for i, sample in enumerate(dataset_descript)
                   if sample['Accession'] == key]

        for i, sample in enumerate(samples):
            for comp_sample in samples[i+1:]:
                if sample['sample'] == comp_sample['sample']:
                    del dataset_descript[comp_sample['index']]
                else:
                    del dataset_descript[comp_sample['index']]
                    del dataset_descript[sample['index']]

def unpack_data(src, samples, dst):
    def check_LAT_PA(fold):
        angles = {'PA' : [],
                  'LAT': []}
        if not sample['label']:  ### debug
            print('{}\n{}\n**************'.format(fold, os.listdir(fold)))
        for key in angles.keys():
            for file in os.listdir(fold):
                if file.find(key) != -1:
                    angles[key].append(file)
        return angles

    for sample in samples:
        fold = os.path.join(src, sample['Accession'])
        angle_files = check_LAT_PA(fold)
        if not all(angle_files.values()):
            if not angle_files['PA']:
                logging.warning('{} doesn\'t hold a PA file'.format(fold))
            continue

        matches = []
        matched = []
        for file_pa in angle_files['PA']:
            ending = file_pa.split('PA')[-1]

            match = [file_lat for file_lat in angle_files['LAT'] if file_lat.split('LAT')[-1] == ending]
            if match:
                logging.info('successfully matched {} to {} in {}'.format(file_pa, match[0], fold))
                matches.append({'PA': file_pa, 'LAT': match[0]})
                matched.append(match[0])
            else:
                logging.warning('{} has no match for {}'.format(fold, file_pa))

        [logging.warning('{} has no match for {}'.format(fold, file_lat))
         for file_lat in angle_files['LAT'] if file_lat not in matched]

        for i, match in enumerate(matches):
            for angle, angle_file in match.items():
                # if len(angle_file) > 1:
                #     err = '{} has {} {} files: {}'.format(fold, len(angle_file), angle, angle_file)
                #     # raise ValueError(err)
                #     logging.warning(err)

                dic_path = os.path.join(fold, angle_file)
                ds = pydicom.dcmread(dic_path)

                dst_dir = os.path.join(os.path.join(dst, str(sample['label'])), sample['Accession'] + '_{}'.format(i))
                os.makedirs(dst_dir, exist_ok=True)
                dst_path = os.path.join(dst_dir, sample['Accession'] + '_{}'.format(i) + '_' + angle + '.png')

                logging.info('saving {} to {}'.format(dic_path, dst_path))
                # sp.imsave(dst_path, ds.pixel_array)
                save_xray_scan(dst_path, ds)

def save_xray_scan(dst, ds):

    img = ds.pixel_array.astype(np.float32)
    if ds.PhotometricInterpretation == 'MONOCHROME1':
        maxl = np.amax(img)
        img = (2 ** int(np.ceil(np.log2(maxl - 1)))) - 1 - img
    sp.imsave(dst, img)

def main():

    handlers = [logging.FileHandler('/Users/Ido/Desktop/Project Data/data_log.log'), logging.StreamHandler()]
    formatter = '%(levelname)s - %(message)s'
    logging.basicConfig(handlers=handlers, level=logging.INFO, format=formatter)

    trainset_descript = parse_xsl('/Users/Ido/Desktop/Project Data/Shiba_dataset/db_description_cxr_train.xlsx')
    testset_descript = parse_xsl('/Users/Ido/Desktop/Project Data/Shiba_dataset/db_description_cxr_test.xlsx')

    eliminate_multiple_occurrences(trainset_descript)
    eliminate_multiple_occurrences(testset_descript)

    positives_trainset, negatives_trainset = samples_to_lables(trainset_descript)
    train_data = unite_labels({'0': negatives_trainset, '1': positives_trainset})
    shuffle(train_data)

    positives_testset, negatives_testset = samples_to_lables(testset_descript)
    test_data = unite_labels({'0': negatives_testset, '1': positives_testset})
    shuffle(test_data)
    # unpack_data('/Users/Ido/Desktop/Project Data/Shiba_dataset/train_dcm', train_data, '/Users/Ido/Desktop/Project Data/train_images')
    unpack_data('/Users/Ido/Desktop/Project Data/Shiba_dataset/test_dcm', test_data, '/Users/Ido/Desktop/Project Data/test_images')

if __name__ == '__main__':
    main()


import numpy as np

from numpy import pi, exp, sqrt
from math import ceil, floor
from scipy.special import gamma
from scipy.stats import t as t_distribution
from scipy.stats import norm as normal_distribution

class estimators:
    def point_normal_estimation( x):
        """
        Estimate the Parameters of the normal distribution based off the
        maximum likelihood estimator (MLE)
        Parameters:
        -----------
        x:      numpy nd-array
                If x is not a 1d-array, samples have to be arranged row wise
                (each row one sample)
        Returns:
        --------
        expectation:    float or numpy 1d-array
                        estimated expectation of the normal
                        distribution based off the samples
        variance:       float or numpy 1d-array
                        estimated variance of the normal
                        distribution based off the samples
        """
        n_samples = x.shape[0]
        return x.mean(0), x.std(0)

    def interval_expectation_estimation( x, confidence_level=0.95, theory=None):
        """
        Estimate the Parameters of the normal distribution based off the
        maximum likelihood estimator (MLE)
        Parameters:
        -----------
        x:      numpy nd-array
                If x is not a 1d-array, samples have to be arranged row wise
                (each row one sample)
        confidence_level:   float, default 0.95
                            confidence level of the estimated interval
        theory:             string, default None
                            based on which theory the interval should be estimated
                            choose between:
                            - MLE/maximum_likelihood estimator
                            - t-distribution
                            If no value is given it is chosen by the number of samples
        Returns:
        --------
        expectation_interval:   list of floats
                                Interval of the estimated expectation
        """
        n_samples = x.shape[0]
        if theory is None:
            if n_samples > 30:
                theory = 'MLE'
            else:
                theory = 't-distribution'

        q = (1+ confidence_level)/2
        expectation, variance = MLE_normal_distribution( x)
        if theory.lower() == 'mle' or 'maximum likelihood' in theory.lower():
            delta = normal_distribution.ppf( q) * variance/n_samples**0.5
        else:
            nu = n_samples -1
            delta = t_distribution( nu).ppf( q) * variance/n_samples**0.5
        return [ expectation-delta, expectation+delta ]

class sample_distribution:
    def normal_distribution( n, mu=0, variance=1):
        """
        samples n values out of the normal distribution
        with the given parameters
        Parameters:
        -----------
        n:          int
                    number of samples
        mu:         float, default 0
                    mu parameter (mean)
        variance:   float, default 1
                    variance parameter (sigma^2)
        Returns:
        --------
        x:          numpy 1d-array
                    discrete samples of the normal distribution
        """
        sigma = variance**0.5
        x = sigma* np.random.randn( n) + mu
        return x

    def uniform_distribution( n, a=0, b=1):
        """
        sample n values out of the uniform distribution
        shadows the numpy function
        Parameters:
        -----------
        a:          float, default 0
                    lower bound of the distribution
        b:          float, default 1
                    upper bound of the distribution
                    expected value of the normal distribution
        interval:   list of 2 floats, default None
                    interval on which to plot the distribution
        Returns:
        --------
        x:          numpy 1d-array
                    samples of the uniform distribution
        """
        x = np.random.uniform( a, b, n)
        return x

    def lognormal_distribution( n, mu=0, sigma=1):
        """
        samples n values out of the normal distribution
        shadows the numpy function
        Parameters:
        -----------
        n:          int
                    number of samples
        mu:         float, default 0
                    mu parameter
        sigma:      float, default 1
                    sigma parameter
        Returns:
        --------
        x:          numpy 1d-array
                    discrete samples of the normal distribution
        """
        return np.random.lognormal( mu, sigma, size=n)

class distribution_plots:
    def underlying(x, bins=200):
        """
        Redefine the samples into discrete bins to be able
        to plot the distribution given with discrete samples
        Parameters:
        -----------
        x:      numpy 1d-array
                given samples of the distribution
        bins:   int, default 100
                number of discretized bins to interpolate the plot with
        Returns:
        --------
        x:      numpy 1d-array
                interval spanned by x (input)
        y:      numpy 1d-array
                underlying distribution function of x
        """
        x = np.squeeze(x) #x is required to be of shape (n,)
        x = np.sort(x)
        n = len(x)
        bins = min(n/3, bins) #ensures that there are not too rough jumps
        f = np.zeros( (bins) )
        delta_x = (x[-1]-(x[0]) )/bins
        scalefactor = ((x[-1]-x[0])/(bins)) *n
        for i in range(bins):
            x_bin = x[0]+i*delta_x
            f[i] = (np.searchsorted(x, max(x_bin+delta_x,x[0]) ) - np.searchsorted(x, min(x_bin,x[-1]) ) )/scalefactor

        x_dist = np.arange(x[0], x[-1], (x[-1]-x[0])/(bins))[:bins]
        x_dist = x_dist + (x_dist[1]- x_dist[0])/2 #moves each value in the center of the 'bin', not the beginning

        return x_dist, f

    def normal( mu=0, variance=1, interval=None):
        """
        Plot the normal distribution based on its parameters
        on the given interval
        Parameters:
        -----------
        mu:         float, default 0
                    expected value of the normal distribution variance:   float, default 0
                    variance of the normal distribution (sigma^2)
        interval:   list three floats, default None
                    interval of sample defined as [start,stop,step]
        Returns:
        --------
        x:          numpy 1d-array
                    interval spanned by x (input)
        y:          numpy 1d-array
                    underlying distribution function of x
        """
        sigma = variance**0.5
        if interval is not None:
            x = np.arange( *interval )
        else:
            x = np.arange( min(-5*sigma, -0.5), max(5*sigma,0.5), (10*sigma)/100 ) +mu
        phi = 1/ (np.sqrt( 2*pi * variance)) * np.exp( -(x-mu)**2 / (2*variance) )
        return x, phi

    def uniform( a=0, b=1, interval=None):
        """
        sample arrays to plot the normal distribution
        based on its parameters on the given interval
        Parameters:
        -----------
        a:          float, default 0
                    lower bound of the distribution
        b:          float, default 1
                    upper bound of the distribution
                    expected value of the normal distribution
        interval:   list of 2 floats, default None
                    interval on which to plot the distribution
        Returns:
        --------
        x:          numpy 1d-array
                    interval spanned by x (input)
        y:          numpy 1d-array
                    underlying distribution function of x
        """
        if interval is not None:
            x = np.arange( *interval )
        else:
            x = np.arange( a, b+(b-a)/100, (b-a)/100)
        n = abs(b-a)

        phi = np.zeros( x.shape)
        for i in range( phi.shape[0]):
            if x[i] >= a and x[i] <= b:
                phi[i] = 1/n
        return x, phi

    def lognormal( mu=0, sigma=1, interval=None):
        """
        sample the lognormal distribution based
        on its parameters on the given interval
        Parameters:
        -----------
        mu:         float, default 0
                    mu parameter of the distribution
        sigma:      float, default 1
                    sigma paramter of the distribution
                    expected value of the normal distribution
        interval:   list of 2 floats, default None
                    interval on which to plot the distribution
        Returns:
        --------
        x:          numpy 1d-array
                    interval spanned by x (input)
        y:          numpy 1d-array
                    underlying distribution function of x
        """
        if interval is not None:
            x = np.arange( *interval )
        else:
            increment = 4*sigma/200
            #x = np.arange( 0+increment, 5*mu + 10*sigma+increment, increment )
            x = np.arange( 0.01, 5*(1+mu**3), 1/100 ) #should prolly be something with e^
        y = 1/(sqrt( 2*pi)*(sigma*x)) * exp( - (np.log( x) -  mu)**2/(2*sigma**2) )
        return x, y

    def levy( mu=0, gamma=1, interval=None):
        """
        samples n values out of the levy distribution
        with the given parameters
        Parameters:
        -----------
        mu:         float, default 0
                    mu parameter (start position)
        gamma:      float, default 1
                    variance parameter (sigma^2)
        interval:   list three floats, default None
                    interval of sample defined as [start,stop,step]
        Returns:
        --------
        x:          numpy 1d-array
                    interval spanned by x (input)
        y:          numpy 1d-array
                    underlying distribution function of x
        """
        if interval is not None:
            x = np.arange( *interval )
        else:
            x = np.arange( mu+0.01, 8*gamma+0.01 +(8*gamma-mu)/100, (8*gamma-mu)/200 )
        y = np.sqrt( gamma/(2*pi) ) * 1/( x- mu)**(3/2) * exp( - gamma/(2*(x-mu) ) )
        return x, y

    def t_distribution( nu, interval ):
        """
        Return two arrays to plot the t-distirbution based on its parameter
        Parameters:
        -----------
        nu          float
                    degrees of freedom for the distributino
        interval:   list three floats, default None
                    interval of sample defined as [start,stop,step]
        Returns:
        --------
        x:          numpy nd-array
                    sample array of the interval in 100 equidistant steps
        y:          numpy nd-array
                    f(x) of the interval above
        """
        if interval is not None:
            x = np.arange( *interval )
        else:
            x = np.arange( *interval )
        if nu > 320:
            print( "can't compute the gamma function for large nu (>320)\nReturning approximation of t-distribution")
            y = np.exp( -x**2/2)/ np.sqrt( 2*pi)
        else:
            y = (gamma( ( nu+1 )/2 ) / (np.sqrt( pi*nu)* gamma( nu/2) )
                    * (1+ x**2/nu)**(-(nu+1)/2) )
        return x, y

    def chi( k, interval=None):
        """
        Return two arrays to plot the t-distirbution based on its parameter
        Parameters:
        -----------
        k:          int
                    parameter of the chi distribution
        interval:   list three floats, default None
                    interval of sample defined as [start,stop,step]
        Returns:
        --------
        x:          numpy nd-array
                    sample array of the interval in 100 equidistant steps
        y:          numpy nd-array
                    f(x) of the interval above
        """
        if interval is not None:
            x = np.arange( *interval )
        else:
            x = np.arange( -3.5, 3.57, 7/100 ) #TODO find a fitting interval
        y = x**(k-1) * np.exp( -(x**2)/2) / (2**(k/2-1) *gamma(k/2) )
        return x, y

class data_binning:
    """
    compute the bins for data which is sampled in a 1d-array.
    This merely counts the number of samples within the bounds of the bin,
    defined by the interval sampled in the array
    """
    def bin_data( data, n_bins=None ):
        """
        Count the data and return the number of samples per bin
        If the number if n_bins is not specified it will automatically be computed
        Parameters:
        -----------
        data:       numpy 1d-array
                    given data
        n_bins:     int, default None
                    How many bins the data should be put into
                    Computes a sensitive default value if not specified

        Returns:
        --------
        count:      numpy nd-array
                    number of samples in the given bin
        center:     numpy nd-array
                    center value of the given bin
        width:      float
                    width of the bin
                    bin start/end is center -/+ width/2
        """
        n_samples = data.shape[0]

        # automatical choice for the number of bins
        if n_bins is None:
            if n_samples < 100:
                print( 'too few data samples present, returning un-binned data' )
                return [data.copy()]
            else:
                # Square-root choice
                n_bins = int(np.ceil(np.sqrt(n_sample)))

        inspected_values = data[:].flatten()
        sorting          = np.argsort( inspected_values)
        data             = data[ sorting ]
        data_bins   = []
        lower_bound = inspected_values.min()
        upper_bound = inspected_values.max() - lower_bound
        stepsize    = upper_bound/ n_bins

        center      = (0.5 + np.arange(n_bins))*stepsize+lower_bound
        width       = stepsize
        count       = np.zeros(n_bins)
        previous_sample = 0
        for i_bin in range( 0,n_bins-1):
            for j in range( previous_sample, n_samples):
                if data[ j ] > center[i_bin]+0.5*stepsize:
                    count[i_bin] = j-previous_sample
                    previous_sample = j
                    break
        count[-1] = n_samples-count[0:-1].sum()
        return count, center, width

    def rebin_data( count, center, n_bins, width=None):
        """
        Put the binned data into n_bins other bins.
        n_bins should be smaller than the number of previous bins, i.e. len(count)
        Parameters:
        -----------
        count:      numpy 1d-array
                    binned data, consisting of the number of samples per bin
        n_bins:     int
                    number of bins after re-binning. n_bins < len( count) !
        center:     numpy 1d-array
                    center of the bin, is used to accurately compute bins
                    assumes a uniform distribution of samples in each bin
        width:      float or numpy 1d-array, default None
                    width of each bin, if None is given then each is calculated
                    The median width is assumed for the first and last bin
                    NOT YET IMPLEMENTED, assumes equidistant bins
        Returns:
        --------
        count:      numpy 1d-array
                    new binned count
        center:     numpy 1d-array
                    new center of the bins
        width:      float or numpy 1d-array
                    new width of the bins
        """
        bin_length = len( count)/n_bins
        bin_overlap = bin_length % 1
        new_count = np.zeros( n_bins)
        remainder = 0.
        for i in range( n_bins -1):
            new_count[i] = count[ floor(i* bin_length)] * (1-remainder )
            new_count[i] += sum( count[ floor(i* bin_length)+1 : floor( (i+1) * bin_length) ] )
            remainder = round(remainder + bin_overlap, 15) % 1
            new_count[i] +=  count[floor( (i+1) * bin_length)] * remainder
        i +=1
        new_count[ -1] =  count[ floor(i* bin_length) ]  * (1-remainder )
        new_count[ -1] += sum( count[ floor(i* bin_length)+1 :] )

        #assume equidistant bins
        center_incr = center[1]-center[0]
        center = np.arange( center[0], center[-1]+ center_incr, center_incr * bin_length )[:n_bins] + (bin_length/2 - center_incr/2)
        if width is not None:
            if isinstance( width, np.ndarray ):
                width = (bin_length * width)[:n_bins]
            else:
                width = bin_length * width
        else:
            width = None
        return new_count, center, width

    def percentile( alpha, count, center=None, width=None ):
        """
        Compute the percentile of the binned data

        Parameters:
        -----------
        alpha:      float
                    searched percentile value
        count:      numpy 1d-array
                    number of samples in the bins
        center:     numpy 1d-array, default None
                    center value of the bins
        width:      numpy 1d-array, default None
                    width of the bins

        """
        n = count.shape[0]
        if( center is None ):
            center = np.arange(n)

        # step 1: find k such that count.cumsum()[k] >= alpha*n
        # find the k-th bin in which the percentile lies
        cum = np.cumsum(count)
        k   = 0
        N   = count.sum()*alpha
        while(cum[k] < N and k<n ):
            k += 1
        # step 2: if the data is discrete, then we are good
        if( width is None ):
            ## Debug only
            #print('k=%d, N=%d, left sum: %d, at k: %d, right sum: %d' % (k, N, n_left, count[k], n_right ))
            return center[k]

        # more computations needed: estimate the position within the bin:
        n_left  = count[0:k].sum()
        n_right = count[(k+1):].sum()
        theta = (N-n_left)/count[k]
        #print('k=%d, N=%d, left sum: %d, at k: %d, right sum: %d' % (k, N, n_left, count[k], n_right ))
        #print('theta=%f' % theta)
        return center[k] + (theta - 0.5) * width[k]

    def compute_relative_frequency( count ):
        """
        Compute the relative frequency of the data in their bins
        It is assumed that the data in each bin contains n-row samples
        The mean value of each bin will be
        Parameters:
        -----------
        count:      numpy 1d-array
                    containing the count for each bin
        Returns:
        --------
        frequency:  numpy-1d array
                    relative frequency for each bin
        """
        frequency = count/count.sum()
        return frequency

    def compute_cumulative_frequency( count ):
        """
        Compute the cumulative frequency of binned data
        It is assumed that the data in each bin contains n-row samples
        The mean value of each bin will be
        Parameters:
        -----------
        count:      numpy 1d-array
                    containing the count for each bin
        Returns:
        --------
        cumulative_frequency:   numpy-1d array
                                relative frequency for each bin
        """
        frequency = data_binning.compute_relative_frequency( count )
        cumulative_frequency = np.cumsum(frequency)
        return cumulative_frequency


import pywt
import numpy as np

from chapter3_分析实验.mel import *

def greyList(n):
    """
    生成格雷编码序列
    参考：https://www.jb51.net/article/133575.htm
    :param n: 长度
    :return: 范围 2 ** n的格雷序列
    """

    def get_grace(list_grace, n):
        if n == 1:
            return list_grace
        list_before, list_after = [], []
        for i in range(len(list_grace)):
            list_before.append('0' + list_grace[i])
            list_after.append('1' + list_grace[-(i + 1)])
        return get_grace(list_before + list_after, n - 1)

    # get_grace生成的序列是二进制字符串，转化为10进制数
    return [int(i, 2) for i in get_grace(['0', '1'], n)]

def wavePacketRec(s, wname):
    """
    小波包重构
    :param s: 小波包分解系数，(a,d)间隔
    :param wname: 小波名
    :return: 各个分量的重构,注意这里重构的长度可能稍微大于原来的长度，如果要保证一样长，去除尾段的即可
    """
    out = []
    for i, l in enumerate(s):
        # 利用该数字去判断是a,d分量类型
        magic = i
        for j in range(int(np.log2(len(s)))):
            if magic % 2 == 0:
                # 为a分量时
                l = pywt.waverec([l, None], wname)
            else:
                # 为d分量时
                l = pywt.waverec([None, l], wname)
            magic = magic // 2
        out.append(l)

    grey_order = greyList(int(np.log2(len(s))))
    return np.array(out)[grey_order]

def wavePacketDec(s, jN, wname):
    """
    小波包分解，分解得到的是最后一层的结果，并非小波系数
    :param s: 源信号
    :param jN: 分解层数
    :param wname: 小波名
    :return:
        out: 小波包系数,是len为2**jN的list,以a,d相互间隔的输出
    """
    assert jN > 0 and isinstance(jN, int), 'Please take a positive integer as jN'
    out = []
    # 第一层分解
    a, d = pywt.dwt(s, wname)
    out.append(a)
    out.append(d)

    # 执行第2-jN次分解
    for level in range(1, jN):
        tmp = []
        for i in range(2 ** level):
            a, d = pywt.dwt(out[i], wname)
            tmp.append(a)
            tmp.append(d)
        out = tmp
    return out

def WPMFCC(x, fs, p, frameSize, inc, jN, wname, nFFT=512, n_dct=12):
    """
    利用小波包-MFCC的方式提取特征，处理流程参考：
    陈静，基于小波包变换和MFCC的说话人识别特征参数，语音技术，2009，DOI:10.16311/j.audioe.2009.02.017
    :param x: 输入信号
    :param fs: 采样率
    :param p: Mel滤波器组的个数
    :param frameSize: 分帧的每帧长度
    :param inc: 帧移
    :param jN: 小波包分解尺度
    :param wname: 小波包名
    :param nFFT: FFT点数
    :param n_dct: DCT阶数
    :return:
    """
    # 预处理-预加重
    xx = lfilter([1, -0.9375], [1], x)
    # 预处理-分幀
    xx = enframe(xx, frameSize, inc)
    # 预处理-加窗
    xx = np.multiply(xx, np.hanning(frameSize))
    # 分层计算小波包能量谱线并合并
    enp = np.zeros((xx.shape[0], nFFT // 2 + 1))
    for i, l in enumerate(xx):
        # 进行小波包分解
        wpcoeff = wavePacketDec(l, jN, wname)
        wp_l = wavePacketRec(wpcoeff, wname)[:, :frameSize]
        # 计算谱线能量
        en = np.abs(np.fft.rfft(wp_l, nFFT)) ** 2 / nFFT
        # 谱线合并
        enp[i] = np.sum(en, axis=0)
    # 计算通过Mel滤波器的能量
    bank = melbankm(p, nFFT, fs, 0, 0.5 * fs, 0)
    ss = np.matmul(enp, bank.T)
    # 计算DCT倒谱
    M = bank.shape[0]
    m = np.array([i for i in range(M)])
    mfcc = np.zeros((ss.shape[0], n_dct))
    for n in range(n_dct):
        mfcc[:, n] = np.sqrt(2 / M) * np.sum(np.multiply(np.log(ss), np.cos((2 * m - 1) * n * np.pi / 2 / M)), axis=1)
    return mfcc

def wavedec(s, jN, wname):
    ca, cd = [], []
    a = s
    for i in range(jN):
        a, d = pywt.dwt(a, wname)
        ca.append(a)
        cd.append(d)
    return ca, cd

def Wavelet_Hard(s, jN, wname):
    """
    小波硬阈值滤波
    :param s:
    :param jN:
    :param wname:
    :return:
    """
    ca, cd = wavedec(s, jN, wname)
    for i in range(len(ca)):
        thr = np.median(cd[i] * np.sqrt(2 * np.log((i + 2) / (i + 1)))) / 0.6745
        di = np.array(cd[i])
        cd[i] = np.where(np.abs(di) > thr, di, 0)
    calast = np.array(ca[-1])
    thr = np.median(calast * np.sqrt(2 * np.log((jN + 1) / jN))) / 0.6745
    calast = np.where(np.abs(calast) > thr, di, 0)
    cd.append(calast)
    coef = cd[::-1]
    res = pywt.waverec(coef, wname)
    return res

def Wavelet_Soft(s, jN, wname):
    """
    小波软阈值滤波
    :param s:
    :param jN:
    :param wname:
    :return:
    """
    ca, cd = wavedec(s, jN, wname)
    for i in range(len(ca)):
        thr = np.median(cd[i] * np.sqrt(2 * np.log((i + 2) / (i + 1)))) / 0.6745
        di = np.array(cd[i])
        cd[i] = np.where(np.abs(di) > thr, np.sign(di) * (np.abs(di) - thr), 0)
    calast = np.array(ca[-1])
    thr = np.median(calast * np.sqrt(2 * np.log((jN + 1) / jN))) / 0.6745
    calast = np.where(np.abs(calast) > thr, np.sign(calast) * (np.abs(calast) - thr), 0)
    cd.append(calast)
    coef = cd[::-1]
    res = pywt.waverec(coef, wname)
    return res

def Wavelet_hardSoft(s, jN, wname, alpha=0.5):
    """
    小波折中阈值滤波
    :param s:
    :param jN:
    :param wname:
    :param alpha:
    :return:
    """
    ca, cd = wavedec(s, jN, wname)
    for i in range(len(ca)):
        thr = np.median(cd[i] * np.sqrt(2 * np.log((i + 2) / (i + 1)))) / 0.6745
        di = np.array(cd[i])
        cd[i] = np.where(np.abs(di) > thr, np.sign(di) * (np.abs(di) - alpha * thr), 0)
    calast = np.array(ca[-1])
    thr = np.median(calast * np.sqrt(2 * np.log((jN + 1) / jN))) / 0.6745
    calast = np.where(np.abs(calast) > thr, np.sign(calast) * (np.abs(calast) - alpha * thr), 0)
    cd.append(calast)
    coef = cd[::-1]
    res = pywt.waverec(coef, wname)
    return res

def Wavelet_average(s, jN, wname, mu=0.1):
    """
    小波加权平均滤波
    :param s:
    :param jN:
    :param wname:
    :param alpha:
    :return:
    """
    ca, cd = wavedec(s, jN, wname)
    for i in range(len(ca)):
        thr = np.median(cd[i] * np.sqrt(2 * np.log((i + 2) / (i + 1)))) / 0.6745
        di = np.array(cd[i])
        cd[i] = np.where(np.abs(di) > thr, (1 - mu) * di + np.sign(di) * mu * (np.abs(di) - thr), 0)
    calast = np.array(ca[-1])
    thr = np.median(calast * np.sqrt(2 * np.log((jN + 1) / jN))) / 0.6745
    calast = np.where(np.abs(calast) > thr, (1 - mu) * calast + np.sign(calast) * mu * (np.abs(calast) - thr), 0)
    cd.append(calast)
    coef = cd[::-1]
    res = pywt.waverec(coef, wname)
    return res


# 导入必要的库
import matplotlib.pyplot as plt  # 用于绘图
import numpy as np

# 提供一些示例数据
x_data = np.linspace(0, 10, 500)  # 创建一个包含5000个点的线性空间，范围从0到10
noise = 2 * np.random.rand(500) - 1
y_data = 5 * x_data + 3 + noise  # 生成带有噪声的线性数据

w = 0  # 初始化权重
b = 0  # 初始化偏差

# 定义线性回归模型的前向传播函数
def forward(x):
    return x * w + b

# 定义损失函数，衡量模型的预测与真实值之间的差距
def loss(x, y):
    y_pred = forward(x)  # 使用前向传播函数计算预测值
    return (y_pred - y) ** 2  # 返回平方损失

# 定义学习率和迭代次数
learning_rate = 0.001
num_epochs = 100
batch_size = 500  # 小批量样本的大小
losses = []  # 用于存储每个epoch的损失值

# 使用小批量随机梯度下降法更新权重和偏差
for epoch in range(num_epochs):
    # 将数据集打乱顺序
    indices = np.arange(len(x_data))
    np.random.shuffle(indices)

    for i in range(0, len(x_data), batch_size):
        # 选择小批量样本
        batch_indices = indices[i:i + batch_size]
        x_batch = x_data[batch_indices]
        y_batch = y_data[batch_indices]

        # 计算模型的预测值
        y_pred = forward(x_batch)
        # 计算平均损失值
        loss_val = np.mean(loss(x_batch, y_batch))

        # 计算梯度
        dw = np.mean(2 * x_batch * (y_pred - y_batch))  # 权重的梯度
        db = np.mean(2 * (y_pred - y_batch))  # 偏差的梯度

        # 更新权重和偏差
        w = w - learning_rate * dw  # 使用梯度下降法更新权重
        b = b - learning_rate * db  # 使用梯度下降法更新偏差
    losses.append(loss_val)  # 将最后一个小批量的损失值添加到损失列表中

# 绘制训练损失随epoch的变化图
plt.figure(figsize=(10, 6))
plt.plot(range(num_epochs), losses, label='Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss over Epochs')
plt.legend()
plt.grid(True)
plt.show()

# 打印最终的权重和偏差
print("最终的权重 w:", w)
print("最终的偏差 b:", b)


# Creating an Empty Set

b = set()
print(type(b))

# Adding the value in empty set
b.add(4)
b.add(5)
b.add(5)
# b.add([4,5,6]) # Will throw the errror does not add a repective value
b.add((4,5,6)) # Will add a tuple cause is imMutable

# Accessig Elements

# b.add({4:5}) # Cannot add a List or dicionary
# print(b)

# Length of Set
# print(len(b))

# Removal of An item
# b.remove(5) #remove 5 of an set
# print(b)

# The POP() Method will remove/pop random element
# print(b.pop())
# print(b)