import itertools
from dataclasses import fields
from typing import Any

from ...common.constraints import SizeConstraint, SizeConstraintList, ValueConstraint
from ...common.error import (
    ConstraintViolatedError,
    InputStreamBytesDepletedError,
    InputStreamSuperfluousBytesError,
    SizeConstraintExceededError,
    ValueConstraintViolatedError,
)
from ...common.event import MarshalEvent, Path, WarningEvent
from ...common.path import PATH_NODE_ROOT_NAME, PathNode
from ...common.util import is_list
from ...spec.commands import Command, CommandResponseStream, Response
from ...spec.commands.params_common import TPMS_PARAMS
from ...spec.common.values import ValidValues
from ...spec.structures.constants import TPM_CC, TPM_RC, TPM_ST
from ...spec.structures.structures import TPMS_AUTH_COMMAND

def consume_bytes(count):
    for _ in range(count):
        _ = yield

def is_parameter_encryption(
    command: Command = None,
    authorizationArea: TPMS_AUTH_COMMAND = None,
    for_response=False,
) -> bool:
    """Return if we have to do parameter encryption for command (or response if for_response=True)."""
    assert command is None or authorizationArea is None
    if command is not None:
        if command.authorizationArea is None:
            return False
        authorizationArea = command.authorizationArea
    if for_response:
        return any(
            authorizationArea.sessionAttributes.encrypt
            for authorizationArea in authorizationArea
        )
    else:
        return any(
            authorizationArea.sessionAttributes.decrypt
            for authorizationArea in authorizationArea
        )

def marshal(
    tpm_type,
    buffer,
    root_path=None,
    command_code=None,
    parameter_encryption=None,
    abort_on_error=True,
):
    """
    Generator.
    Takes iterable "buffer" as a parameter which yields single bytes.
    Yields Events.
    Return (command_code, remaining_bytes)
    command_code is an int (for Responses) or None.
    parameter_encryption is True for Responses for which we expect param encryption (sessionAttributes.encrypt) or None
    remaining_bytes is a generator or None if depleted.

    Internally:
    A) Send a byte into the processor.
    B) As long as Events are yielded back, send None into the processor.
    C.1) When it is done (for this byte), the processor will yield None ("ask for next byte"). Go back to A).
    C.2) Alternatively, it might raise a StopIteration.

    When the processor is done, it will raise a StopIteration (without yielding None first). In
    that case we need to check if the buffer was indeed fully depleted (by taking an extra byte and expecting a
    StopIteration).

    If the byte iterator raises a StopIteration, we ran out of bytes.
    """
    if root_path is None:
        root_path = Path(PathNode(PATH_NODE_ROOT_NAME))
    command_code_path = Path(root_path / PathNode("commandCode"))
    processor = process(
        tpm_type,
        path=root_path,
        command_code=command_code,
        parameter_encryption=parameter_encryption,
        abort_on_error=abort_on_error,
    )
    buffer_iter = iter(buffer)

    command_code = None
    byte = None
    buffer_depleted = False
    event = None

    while not buffer_depleted:
        assert event is None

        # the processor yielded None last time, asking for another byte (so it won't raise a StopIteration here)
        try:
            # send next byte into processor
            event = processor.send(byte)
        except ConstraintViolatedError as error:
            # TODO code is redundant
            error.set_bytes_remaining(buffer_iter)
            raise error

        # get next byte ahead of time, but we still have to get the events from previous byte
        # this is to know ahead of time, if the buffer is depleted
        try:
            byte = next(buffer_iter)
            # print(f"{byte:02x} ", end="")
        except StopIteration:
            buffer_depleted = True

        # get events from processor until None is yielded
        while event is not None:
            # TODO is this still needed?
            if isinstance(event, MarshalEvent):
                if event.path == command_code_path:
                    command_code = event.value
                if (
                    buffer_depleted
                    and event.path == Path.from_string(".")
                    and event.value is ...
                ):
                    # root path of new command/response although bytes are depleted
                    # (occurs for CommandResponseStream), do not yield event and end parsing
                    # TODO what to return here? (formerly: command_code, None)
                    return

            # yield event from when we sent the byte or last iteration...
            yield event

            # ... and get next event
            try:
                event = processor.send(None)
            except StopIteration as error:
                size, obj = error.value
                if not buffer_depleted:
                    # we already got next byte, so processor should not be done

                    # TODO properly make bytes_remaining a property for InputStreamBytesDepletedError, InputStreamSuperfluousBytesError
                    bytes_remaining = bytes(itertools.chain((byte,), buffer_iter))
                    error = InputStreamSuperfluousBytesError(
                        bytes_remaining=bytes_remaining, command_code=command_code
                    )
                    if abort_on_error:
                        raise error
                    else:
                        yield WarningEvent(error=error)
                        return obj

                else:
                    # all bytes were depleted
                    return obj
            except ConstraintViolatedError as error:
                bytes_remaining = bytes(itertools.chain((byte,), buffer_iter))
                error.set_bytes_remaining(bytes_remaining)
                raise error

    error = InputStreamBytesDepletedError(command_code=command_code)
    if abort_on_error:
        raise error
    else:
        yield WarningEvent(error=error)
        return

def process_primitive(tpm_type, path, size_constraints=None, abort_on_error=True):
    """Coroutine. Send in one byte if it yields None. Send in None if it yields an MarshalEvents."""
    size = tpm_type._int_size
    data = []

    # before we consume byte, we need to check if we would violate any of the size constraints
    if size_constraints is not None:
        yield from size_constraints.bytes_parsed(path, size)

    for _ in range(size):
        byte = yield None
        data.append(byte)
    value = int.from_bytes(data, byteorder="big", signed=tpm_type._signed)

    value_typed = tpm_type(value)
    event = MarshalEvent(path, tpm_type, value_typed)
    value_constraint = ValueConstraint(
        constraint_path=path, tpm_type=tpm_type, valid_values=value_typed._valid_values
    )

    error = None
    if not value_typed.is_valid():
        error = ValueConstraintViolatedError(constraint=value_constraint, value=value)
        if abort_on_error:
            raise error

    none = yield event
    assert none is None

    if error:
        none = yield WarningEvent(error=error)
        assert none is None

    return size, value_typed

def process_array(tpm_type, path, count, size_constraints=None, abort_on_error=True):
    """Coroutine. Send in one byte if it yields None. Send in None if it yields an MarshalEvents."""
    assert len(tpm_type.__args__) == 1
    element_type = tpm_type.__args__[0]

    none = yield MarshalEvent(path, tpm_type, ...)
    assert none is None

    parent_path = path[:-1]
    element_size = 0
    elements = tpm_type()
    for index in range(count):
        child_node = path[-1].with_index(index)
        element_size, element = yield from process(
            element_type,
            parent_path / child_node,
            size_constraints=size_constraints,
            abort_on_error=abort_on_error,
        )
        elements.append(element)

    return element_size * count, elements

def process_byte_sized_array(
    tpm_type, path, array_size_constraint, size_constraints=None, abort_on_error=True
):
    """
    Coroutine. Send in one byte if it yields None. Send in None if it yields an MarshalEvents.
    Assumes that whatever amount of bytes is left in array_size_constraint is meant for the array.
    Ensures that array_size_constraint is not violated.
    """
    assert len(tpm_type.__args__) == 1
    element_type = tpm_type.__args__[0]

    none = yield MarshalEvent(path, tpm_type, ...)
    assert none is None

    elements = tpm_type()
    parent_path = path[:-1]
    index = 0
    while array_size_constraint.size_already < array_size_constraint.size_max:
        child_node = path[-1].with_index(index)
        try:
            _element_size, element_value = yield from process(
                element_type,
                parent_path / child_node,
                size_constraints=size_constraints,
                abort_on_error=abort_on_error,
            )
        except SizeConstraintExceededError as error:
            if abort_on_error or error.constraint != array_size_constraint:
                raise error
            yield WarningEvent(error=error)
            return array_size_constraint.size_already, None

        elements.append(element_value)
        index += 1

    yield from array_size_constraint.assert_done(
        all_size_constraints=size_constraints, abort_on_error=abort_on_error
    )
    return array_size_constraint.size_already, elements

def process_tpms(
    tpm_type,
    path,
    size_constraints=None,
    parameter_encryption=None,
    abort_on_error=True,
):
    """Coroutine. Send in one byte if it yields None. Send in None if it yields an MarshalEvents."""
    if parameter_encryption and issubclass(tpm_type, TPMS_PARAMS):
        tpm_type = tpm_type.encrypted()

    none = yield MarshalEvent(path, tpm_type, ...)
    assert none is None

    size = 0
    values = {}
    element_size, element_value = None, None
    for field in fields(tpm_type):
        if is_list(field.type):
            # list member
            # count is (non-list) field immediately preceding this list
            count = [v for v in values.values() if not is_list(type(v))][-1]
            elements_size, element_value = yield from process(
                field.type,
                path / PathNode(field.name),
                count=count,
                size_constraints=size_constraints,
                abort_on_error=abort_on_error,
            )
        elif hasattr(tpm_type, "_selectors") and field.name in tpm_type._selectors:
            # union member
            selector_name = tpm_type._selectors[field.name]
            selector_value = values[selector_name]
            element_size, element_value = yield from process(
                field.type,
                path / PathNode(field.name),
                selector=selector_value,
                size_constraints=size_constraints,
                abort_on_error=abort_on_error,
            )
        else:
            element_size, element_value = yield from process(
                field.type,
                path / PathNode(field.name),
                size_constraints=size_constraints,
                abort_on_error=abort_on_error,
            )
        values[field.name] = element_value
        size += element_size
    return size, tpm_type(**values)

def process_tpm2b(tpm_type, path, size_constraints=None, abort_on_error=True):
    """Coroutine. Send in one byte if it yields None. Send in None if it yields an MarshalEvents."""
    # A dedicated funtion is needed because the size in TPM2B is always in bytes (not in elements)
    none = yield MarshalEvent(path, tpm_type, ...)
    assert none is None

    values = {}
    size_field, buffer_field = fields(tpm_type)
    size_path = path / PathNode(size_field.name)
    size_size, buffer_size_exp = yield from process(
        size_field.type,
        size_path,
        size_constraints=size_constraints,
        abort_on_error=abort_on_error,
    )
    values[size_field.name] = buffer_size_exp

    # Size can be for a byte buffer or a complex type.
    # Technically, a byte buffer does not need a size constraint, however, when calling set_constraint(), the violation
    # of all other size constraints is anticipated. Therefore, always create a constraint, even for byte buffer sizes.
    tpm2b_size_constraint = SizeConstraint()
    yield from tpm2b_size_constraint.set_constraint(
        constraint_path=size_path,
        size_max=buffer_size_exp,
        other_size_constraints=size_constraints,
        abort_on_error=abort_on_error,
    )
    size_constraints.append(tpm2b_size_constraint)

    if is_list(buffer_field.type):
        # common tpm2b with byte buffer
        buffer_size, buffer_value = yield from process(
            buffer_field.type,
            path / PathNode(buffer_field.name),
            count=buffer_size_exp,
            size_constraints=size_constraints,
            abort_on_error=abort_on_error,
        )
        values[buffer_field.name] = buffer_value
        yield from tpm2b_size_constraint.assert_done(
            all_size_constraints=size_constraints, abort_on_error=abort_on_error
        )
        return size_size + buffer_size, tpm_type(**values)

    # buffer represents single complex type, count is number of bytes
    if buffer_size_exp == 0:
        values[buffer_field.name] = None
        none = yield MarshalEvent(
            path / PathNode(buffer_field.name), buffer_field.type, ...
        )
        assert none is None
        yield from tpm2b_size_constraint.assert_done(
            all_size_constraints=size_constraints, abort_on_error=abort_on_error
        )
        return size_size, tpm_type(**values)

    try:
        buffer_size, buffer_value = yield from process(
            buffer_field.type,
            path / PathNode(buffer_field.name),
            size_constraints=size_constraints,
            abort_on_error=abort_on_error,
        )
    except SizeConstraintExceededError as error:
        if abort_on_error or error.constraint != tpm2b_size_constraint:
            raise error
        yield WarningEvent(error=error)
        return size_size + tpm2b_size_constraint.size_already, None

    yield from tpm2b_size_constraint.assert_done(
        all_size_constraints=size_constraints, abort_on_error=abort_on_error
    )
    buffer_size = tpm2b_size_constraint.size_already
    values[buffer_field.name] = buffer_value
    return size_size + buffer_size, tpm_type(**values)

def process_tpmu(tpm_type, path, selector, size_constraints=None, abort_on_error=True):
    """Coroutine. Send in one byte if it yields None. Send in None if it yields an MarshalEvents."""
    none = yield MarshalEvent(path, tpm_type, ...)
    assert none is None

    # TODO _selected_by
    assert hasattr(
        tpm_type, "_selected_by"
    ), f"Union type {tpm_type} must have attribute ._selected_by"
    # reverse dict
    selection = {v: k for k, v in tpm_type._selected_by.items()}
    if selector in selection:
        selectee_name = selection[selector]
    elif None in selection:
        # use fallback option
        selectee_name = selection[None]
    else:
        # selector value fails to select union member
        # only possible if value checking is turnt off
        # TODO only possible if value checking is turnt off
        raise AssertionError(
            f"Selection error in {path} ({tpm_type.__name__}): {selector} not in {selection}. Value checking should have taken when parsing the selector, right?"
        )
        # raise ValueConstraintViolatedError(
        #     tpm_type=None,  # TODO type of selector
        #     path=None,  # TODO path of selector
        #     value=selector,
        #     selection=selection.keys(),
        # )

    field = next(f for f in fields(tpm_type) if f.name == selectee_name)
    if field.type is None:
        return 0, None
    if is_list(field.type):
        # union member of list type (must be statically sized as indicated in _list_size)
        assert hasattr(tpm_type, "_list_size")
        size, value = yield from process(
            field.type,
            path / PathNode(field.name),
            count=tpm_type._list_size[field.name],
            size_constraints=size_constraints,
            abort_on_error=abort_on_error,
        )
    else:
        size, value = yield from process(
            field.type,
            path / PathNode(field.name),
            size_constraints=size_constraints,
            abort_on_error=abort_on_error,
        )

    return size, tpm_type(**{selectee_name: value})

def process_command(path, abort_on_error=True):
    """Coroutine. Send in one byte if it yields None. Send in None if it yields an MarshalEvents."""
    tpm_type = Command
    command_size_constraint = SizeConstraint()
    authorization_area_constraint = SizeConstraint()
    size_constraints = SizeConstraintList((command_size_constraint,))
    parameter_encryption = None

    none = yield MarshalEvent(path, tpm_type, ...)
    assert none is None

    size = 0
    values = {}
    for field in fields(tpm_type):
        field_type = field.type
        if (
            field.name in ("authSize", "authorizationArea")
            and values["tag"] != TPM_ST.SESSIONS
        ):
            continue

        # resolve Any type with _type_maps/_selectors
        # TODO change Any to any
        if field_type is Any:
            selector_name = tpm_type._selectors[field.name]
            selector_type = next(
                f.type for f in fields(tpm_type) if f.name == selector_name
            )
            types_map = tpm_type._type_maps[field.name]
            assert selector_name in values, f"Did not parse {selector_name} yet."
            selector_value = values[selector_name]
            try:
                field_type = types_map[selector_value]
            except KeyError as error:
                # it is ensured that every TPM_CC maps to a type in types_map
                # i.e. list(TPM_CC) is a subgroup of list(types_map.keys())
                value_constraint = ValueConstraint(
                    constraint_path=path + PathNode(selector_name),
                    tpm_type=selector_type,
                    valid_values=ValidValues(TPM_CC),
                )
                raise ValueConstraintViolatedError(
                    constraint=value_constraint,
                    value=selector_value,
                ) from error

        element_path = path / PathNode(field.name)
        array_size_constraint = None
        if field.name == "authorizationArea":
            array_size_constraint = authorization_area_constraint
        try:
            element_size, element_value = yield from process(
                field_type,
                element_path,
                parameter_encryption=parameter_encryption,
                array_size_constraint=array_size_constraint,
                size_constraints=size_constraints,
                abort_on_error=abort_on_error,
            )
            size += element_size
        except SizeConstraintExceededError as error:
            if abort_on_error or error.constraint not in (
                command_size_constraint,
                authorization_area_constraint,
            ):
                raise error
            yield WarningEvent(error=error)
            return values["commandSize"], tpm_type(**values)

        parameter_encryption = None

        if field.name == "commandSize":
            yield from command_size_constraint.set_constraint(
                constraint_path=element_path,
                size_max=element_value,
                other_size_constraints=size_constraints,
                abort_on_error=abort_on_error,
            )
        if field.name == "authSize":
            yield from authorization_area_constraint.set_constraint(
                constraint_path=element_path,
                size_max=element_value,
                other_size_constraints=size_constraints,
                abort_on_error=abort_on_error,
            )
            size_constraints.append(authorization_area_constraint)
        if field.name == "authorizationArea":
            parameter_encryption = (
                is_parameter_encryption(authorizationArea=element_value) or None
            )

        values[field.name] = element_value

    yield from command_size_constraint.assert_done(
        all_size_constraints=size_constraints, abort_on_error=abort_on_error
    )
    return values["commandSize"], tpm_type(**values)

    # as a sanity check - all size_constraints should be handled explicitly by now
    size_constraints.assert_done()
    return size, tpm_type(**values)

def process_response(
    path, command_code, parameter_encryption=None, abort_on_error=True
):
    """Coroutine. Send in one byte if it yields None. Send in None if it yields an MarshalEvents."""
    tpm_type = Response
    response_size_constraint = SizeConstraint()
    parameter_size_constraint = SizeConstraint()
    size_constraints = SizeConstraintList((response_size_constraint,))

    none = yield MarshalEvent(path, tpm_type, ...)
    assert none is None

    size = 0
    values = {}
    for field in fields(tpm_type):
        field_type = field.type

        if (
            field.name in ("parameterSize", "authorizationArea")
            and values["tag"] != TPM_ST.SESSIONS
        ):
            continue

        if (
            field.name
            in ("handles", "parameterSize", "parameters", "authorizationArea")
            and "responseCode" in values
            and values["responseCode"] != TPM_RC.SUCCESS
        ):
            continue

        if field_type is Any:
            types_map = tpm_type._type_maps[field.name]
            try:
                field_type = types_map[command_code]
            except KeyError as error:
                # it is ensured that every TPM_CC maps to a type in types_map
                # i.e. list(TPM_CC) is a subgroup of list(types_map.keys())
                # TODO
                value_constraint = ValueConstraint(
                    constraint_path=path + PathNode(selector_name),
                    tpm_type=selector_type,
                    valid_values=ValidValues(TPM_CC),
                )
                raise ValueConstraintViolatedError(
                    constraint=value_constraint,
                    value=command_code,
                ) from error

        element_path = path / PathNode(field.name)
        array_size_constraint = None
        if field.name == "authorizationArea":
            array_size_constraint = response_size_constraint
        try:
            element_size, element_value = yield from process(
                field_type,
                element_path,
                parameter_encryption=parameter_encryption,
                array_size_constraint=array_size_constraint,
                size_constraints=size_constraints,
                abort_on_error=abort_on_error,
            )
            size += element_size
        except SizeConstraintExceededError as error:
            if abort_on_error or error.constraint not in (
                response_size_constraint,
                parameter_size_constraint,
            ):
                raise error
            yield WarningEvent(error=error)
            return values["responseSize"], tpm_type(**values)

        if field.name == "parameters" and "parameterSize" in values:
            yield from parameter_size_constraint.assert_done(
                all_size_constraints=size_constraints, abort_on_error=abort_on_error
            )

        if field.name == "responseSize":
            yield from response_size_constraint.set_constraint(
                constraint_path=element_path,
                size_max=element_value,
                other_size_constraints=size_constraints,
                abort_on_error=abort_on_error,
            )
        if field.name == "parameterSize":
            yield from parameter_size_constraint.set_constraint(
                constraint_path=element_path,
                size_max=element_value,
                other_size_constraints=size_constraints,
                abort_on_error=abort_on_error,
            )
            size_constraints.append(parameter_size_constraint)
        if field.name == "authorizationArea":
            parameter_encryption_expected = (
                is_parameter_encryption(
                    authorizationArea=element_value, for_response=True
                )
                or None
            )
            # TODO yield Warning
            assert (
                parameter_encryption == parameter_encryption_expected
            ), f"Started parsing Response with parameter_encryption = {parameter_encryption}, but authorizationArea.sessionAttributes.encrypt = {parameter_encryption_expected}."

        values[field.name] = element_value

    yield from response_size_constraint.assert_done(
        all_size_constraints=size_constraints, abort_on_error=abort_on_error
    )
    # as a sanity check - all size_constraints should be handled explicitly by now
    size_constraints.assert_done()
    return values["responseSize"], tpm_type(**values)

def process_command_response_stream(path, abort_on_error=True):
    """Generator. Take iterable which yields single bytes. Yield MarshalEvents."""
    while True:
        # The calling function must detect when this generator is done. Basically, when there are no bytes left and this
        # generator yields the command/response root event for the new command/response, we are done here. This cannot
        # be handles at this level. Well, technically it can, but trust me, it is not something anyone would want...
        _, command = yield from process(Command, path, abort_on_error=abort_on_error)
        _, _ = yield from process(
            Response,
            path,
            command_code=command.commandCode,
            parameter_encryption=is_parameter_encryption(command, for_response=True)
            or None,
            abort_on_error=abort_on_error,
        )

def process(
    tpm_type,
    path,
    selector=None,
    count=None,
    command_code=None,
    parameter_encryption=None,
    array_size_constraint=None,
    size_constraints=None,
    abort_on_error=True,
):
    """Coroutine. Send in one byte if it yields None. Send in None if it yields an MarshalEvents."""
    if size_constraints is None:
        size_constraints = SizeConstraintList()

    if tpm_type is CommandResponseStream:
        result = yield from process_command_response_stream(
            path, abort_on_error=abort_on_error
        )
    elif tpm_type is Command:
        result = yield from process_command(path, abort_on_error=abort_on_error)
    elif tpm_type is Response:
        result = yield from process_response(
            path,
            command_code=command_code,
            parameter_encryption=parameter_encryption,
            abort_on_error=abort_on_error,
        )
    elif hasattr(tpm_type, "_int_size"):
        # Primitives, TPMA
        result = yield from process_primitive(
            tpm_type,
            path,
            size_constraints=size_constraints,
            abort_on_error=abort_on_error,
        )
    elif tpm_type.__name__.startswith("TPM2B"):
        result = yield from process_tpm2b(
            tpm_type,
            path,
            size_constraints=size_constraints,
            abort_on_error=abort_on_error,
        )
    elif hasattr(tpm_type, "_selected_by"):
        # TPMU
        result = yield from process_tpmu(
            tpm_type,
            path,
            selector=selector,
            size_constraints=size_constraints,
            abort_on_error=abort_on_error,
        )
    elif is_list(tpm_type) and array_size_constraint is not None:
        # list[...] with size in bytes
        result = yield from process_byte_sized_array(
            tpm_type,
            path,
            array_size_constraint=array_size_constraint,
            size_constraints=size_constraints,
            abort_on_error=abort_on_error,
        )
    elif is_list(tpm_type):
        # list[...] with count of elements
        result = yield from process_array(
            tpm_type,
            path,
            count=count,
            size_constraints=size_constraints,
            abort_on_error=abort_on_error,
        )
    else:
        # TPMS, TPMT, TPML
        result = yield from process_tpms(
            tpm_type,
            path,
            parameter_encryption=parameter_encryption,
            size_constraints=size_constraints,
            abort_on_error=abort_on_error,
        )
    return result


from typing import TypedDict, List, Dict

SltxUrl = str
SltxDriver = str
SltxStrPattern = str
SltxStrKey = str

# we use a value constructor to allow for '-' in TypedDict
SltxDependency = TypedDict('SltxDependency', {
   'url': SltxUrl,
   'driver': SltxDriver,
   'grab-files': List[SltxStrPattern]
}, total=False)  # keys are optional

SltxDependencies = Dict[SltxStrKey, SltxDependency]


import math
import os
import cv2
import numpy as np
import skimage.morphology
from PIL import Image
from torchvision import transforms
import time

from envs.utils.fmm_planner import FMMPlanner
from envs.habitat.objectgoal_env import ObjectGoal_Env
from envs.habitat.objectgoal_env21 import ObjectGoal_Env21
from agents.utils.semantic_prediction import SemanticPredMaskRCNN
from constants import color_palette
import envs.utils.pose as pu
import agents.utils.visualization as vu

from RedNet.RedNet_model import load_rednet
from constants import mp_categories_mapping
import torch

class Sem_Exp_Env_Agent(ObjectGoal_Env21):
    """The Sem_Exp environment agent class. A seperate Sem_Exp_Env_Agent class
    object is used for each environment thread.

    """

    def __init__(self, args, rank, config_env, dataset):

        self.args = args
        super().__init__(args, rank, config_env, dataset)

        # initialize transform for RGB observations
        self.res = transforms.Compose(
            [transforms.ToPILImage(),
             transforms.Resize((args.frame_height, args.frame_width),
                               interpolation=Image.NEAREST)])

        # initialize semantic segmentation prediction model
        if args.sem_gpu_id == -1:
            args.sem_gpu_id = config_env.SIMULATOR.HABITAT_SIM_V0.GPU_DEVICE_ID

        self.device = args.device
        self.sem_pred = SemanticPredMaskRCNN(args)
        self.red_sem_pred = load_rednet(
            self.device, ckpt='RedNet/model/rednet_semmap_mp3d_40.pth', resize=True, # since we train on half-vision
        )
        self.red_sem_pred.eval()
        # self.red_sem_pred.to(self.device)

        # initializations for planning:
        self.selem = skimage.morphology.disk(3)

        self.obs = None
        self.obs_shape = None
        self.collision_map = None
        self.visited = None
        self.visited_vis = None
        self.col_width = None
        self.curr_loc = None
        self.last_loc = None
        self.last_action = None
        self.count_forward_actions = None

        self.replan_count = 0
        self.collision_n = 0
        self.kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))

        if args.visualize or args.print_images:
            self.legend = cv2.imread('docs/legend.png')
            self.vis_image = None
            self.rgb_vis = None

        self.fail_case = {}
        self.fail_case['collision'] = 0
        self.fail_case['success'] = 0
        self.fail_case['detection'] = 0
        self.fail_case['exploration'] = 0

        self.eve_angle = 0

    def reset(self):
        args = self.args

        self.replan_count = 0
        self.collision_n = 0

        obs, info = super().reset()
        obs = self._preprocess_obs(obs)

        self.obs_shape = obs.shape

        # Episode initializations
        map_shape = (args.map_size_cm // args.map_resolution,
                     args.map_size_cm // args.map_resolution)
        self.collision_map = np.zeros(map_shape)
        self.visited = np.zeros(map_shape)
        self.visited_vis = np.zeros(map_shape)
        self.col_width = 1
        self.count_forward_actions = 0
        self.curr_loc = [args.map_size_cm / 100.0 / 2.0,
                         args.map_size_cm / 100.0 / 2.0, 0.]
        self.last_action = None

        self.eve_angle = 0
        self.eve_angle_old = 0

        info['eve_angle'] = self.eve_angle

        if args.visualize or args.print_images:
            self.vis_image = vu.init_vis_image(self.goal_name, self.legend)

        return obs, info

    def plan_act_and_preprocess(self, planner_inputs):
        """Function responsible for planning, taking the action and
        preprocessing observations

        Args:
            planner_inputs (dict):
                dict with following keys:
                    'map_pred'  (ndarray): (M, M) map prediction
                    'goal'      (ndarray): (M, M) mat denoting goal locations
                    'pose_pred' (ndarray): (7,) array denoting pose (x,y,o)
                                 and planning window (gx1, gx2, gy1, gy2)
                     'found_goal' (bool): whether the goal object is found

        Returns:
            obs (ndarray): preprocessed observations ((4+C) x H x W)
            reward (float): amount of reward returned after previous action
            done (bool): whether the episode has ended
            info (dict): contains timestep, pose, goal category and
                         evaluation metric info
        """
        # s_time = time.time()

        # plan
        if planner_inputs["wait"]:
            self.last_action = None
            self.info["sensor_pose"] = [0., 0., 0.]
            return np.zeros(self.obs.shape), self.fail_case, False, self.info

        # Reset reward if new long-term goal
        if planner_inputs["new_goal"]:
            goal = planner_inputs['goal']
            if np.sum(goal == 1) == 1 and self.args.task_config == "tasks/objectnav_gibson.yaml":
                frontier_loc = np.where(goal == 1)
                self.info["g_reward"] = self.get_llm_distance(planner_inputs["map_target"], frontier_loc)

            # self.collision_map = np.zeros(self.visited.shape)
            self.info['clear_flag'] = 0

        action = self._plan(planner_inputs)

        # c_time = time.time()
        # ss_time = c_time - s_time
        # print('plan map: %.3f秒'%ss_time) 0.19

        if self.collision_n > 20 or self.replan_count > 26:
            self.info['clear_flag'] = 1
            self.collision_n = 0

        if self.args.visualize or self.args.print_images:
            self._visualize(planner_inputs)

        if action >= 0:

            # act
            action = {'action': action}
            obs, rew, done, info = super().step(action)

            if done and self.info['success'] == 0:
                if self.info['time'] >= self.args.max_episode_length - 1:
                    self.fail_case['exploration'] += 1
                elif self.replan_count > 26:
                    self.fail_case['collision'] += 1
                else:
                    self.fail_case['detection'] += 1

            if done and self.info['success'] == 1:
                self.fail_case['success'] += 1

            # preprocess obs
            obs = self._preprocess_obs(obs)
            self.last_action = action['action']
            self.obs = obs
            self.info = info
            info['eve_angle'] = self.eve_angle

            # e_time = time.time()
            # ss_time = e_time - c_time
            # print('act map: %.3f秒'%ss_time) 0.23

            # info['g_reward'] += rew

            return obs, self.fail_case, done, info

        else:
            self.last_action = None
            self.info["sensor_pose"] = [0., 0., 0.]
            return np.zeros(self.obs_shape), self.fail_case, False, self.info

    def _plan(self, planner_inputs):
        """Function responsible for planning

        Args:
            planner_inputs (dict):
                dict with following keys:
                    'map_pred'  (ndarray): (M, M) map prediction
                    'goal'      (ndarray): (M, M) goal locations
                    'pose_pred' (ndarray): (7,) array  denoting pose (x,y,o)
                                 and planning window (gx1, gx2, gy1, gy2)
                    'found_goal' (bool): whether the goal object is found

        Returns:
            action (int): action id
        """
        args = self.args

        self.last_loc = self.curr_loc

        # Get Map prediction
        map_pred = np.rint(planner_inputs['map_pred'])
        exp_pred = np.rint(planner_inputs['exp_pred'])
        goal = planner_inputs['goal']

        # Get pose prediction and global policy planning window
        start_x, start_y, start_o, gx1, gx2, gy1, gy2 = \
            planner_inputs['pose_pred']
        gx1, gx2, gy1, gy2 = int(gx1), int(gx2), int(gy1), int(gy2)
        planning_window = [gx1, gx2, gy1, gy2]

        # Get curr loc
        self.curr_loc = [start_x, start_y, start_o]
        r, c = start_y, start_x
        start = [int(r * 100.0 / args.map_resolution - gx1),
                 int(c * 100.0 / args.map_resolution - gy1)]
        start = pu.threshold_poses(start, map_pred.shape)

        self.visited[gx1:gx2, gy1:gy2][start[0] - 0:start[0] + 1,
                                       start[1] - 0:start[1] + 1] = 1

        # if args.visualize or args.print_images:
            # Get last loc
        last_start_x, last_start_y = self.last_loc[0], self.last_loc[1]
        r, c = last_start_y, last_start_x
        last_start = [int(r * 100.0 / args.map_resolution - gx1),
                        int(c * 100.0 / args.map_resolution - gy1)]
        last_start = pu.threshold_poses(last_start, map_pred.shape)
        self.visited_vis[gx1:gx2, gy1:gy2] = \
            vu.draw_line(last_start, start,
                            self.visited_vis[gx1:gx2, gy1:gy2])

        # Collision check
        if self.last_action == 1 and not planner_inputs["new_goal"]:
            x1, y1, t1 = self.last_loc
            x2, y2, _ = self.curr_loc
            buf = 4
            length = 2

            if abs(x1 - x2) < 0.05 and abs(y1 - y2) < 0.05:
                self.col_width += 2
                if self.col_width == 7:
                    length = 4
                    buf = 3
                self.col_width = min(self.col_width, 5)
            else:
                self.col_width = 1

            dist = pu.get_l2_distance(x1, x2, y1, y2)
            if dist < args.collision_threshold:  # Collision
                self.collision_n += 1
                width = self.col_width
                for i in range(length):
                    for j in range(width):
                        wx = x1 + 0.05 * \
                            ((i + buf) * np.cos(np.deg2rad(t1))
                             + (j - width // 2) * np.sin(np.deg2rad(t1)))
                        wy = y1 + 0.05 * \
                            ((i + buf) * np.sin(np.deg2rad(t1))
                             - (j - width // 2) * np.cos(np.deg2rad(t1)))
                        r, c = wy, wx
                        r, c = int(r * 100 / args.map_resolution), \
                            int(c * 100 / args.map_resolution)
                        [r, c] = pu.threshold_poses([r, c],
                                                    self.collision_map.shape)
                        self.collision_map[r, c] = 1

        stg, replan, stop = self._get_stg(map_pred, start, np.copy(goal),
                                  planning_window)

        if replan:
            self.replan_count += 1
            print("false: ", self.replan_count)
        else:
            self.replan_count = 0

        # Deterministic Local Policy
        if (stop and planner_inputs['found_goal'] == 1) or self.replan_count > 26:
            action = 0  # Stop
        else:
            (stg_x, stg_y) = stg
            angle_st_goal = math.degrees(math.atan2(stg_x - start[0],
                                                    stg_y - start[1]))
            angle_agent = (start_o) % 360.0
            if angle_agent > 180:
                angle_agent -= 360

            relative_angle = (angle_agent - angle_st_goal) % 360.0
            if relative_angle > 180:
                relative_angle -= 360

            ## add the evelution angle
            eve_start_x = int(5 * math.sin(angle_st_goal) + start[0])
            eve_start_y = int(5 * math.cos(angle_st_goal) + start[1])
            if eve_start_x > map_pred.shape[0]: eve_start_x = map_pred.shape[0]
            if eve_start_y > map_pred.shape[0]: eve_start_y = map_pred.shape[0]
            if eve_start_x < 0: eve_start_x = 0
            if eve_start_y < 0: eve_start_y = 0
            if exp_pred[eve_start_x, eve_start_y] == 0 and self.eve_angle > -60:
                action = 5
                self.eve_angle -= 30
            elif exp_pred[eve_start_x, eve_start_y] == 1 and self.eve_angle < 0:
                action = 4
                self.eve_angle += 30
            elif relative_angle > self.args.turn_angle / 2.:
                action = 3  # Right
            elif relative_angle < -self.args.turn_angle / 2.:
                action = 2  # Left
            else:
                action = 1  # Forward

        return action

    def _get_stg(self, grid, start, goal, planning_window):
        """Get short-term goal"""

        [gx1, gx2, gy1, gy2] = planning_window

        x1, y1, = 0, 0
        x2, y2 = grid.shape

        def add_boundary(mat, value=1):
            h, w = mat.shape
            new_mat = np.zeros((h + 2, w + 2)) + value
            new_mat[1:h + 1, 1:w + 1] = mat
            return new_mat

        traversible = skimage.morphology.binary_dilation(
            grid[x1:x2, y1:y2],
            self.selem) != True
        traversible[self.collision_map[gx1:gx2, gy1:gy2]
                    [x1:x2, y1:y2] == 1] = 0
        traversible[cv2.dilate(self.visited_vis[gx1:gx2, gy1:gy2][x1:x2, y1:y2], self.kernel) == 1] = 1

        traversible[int(start[0] - x1) - 1:int(start[0] - x1) + 2,
                    int(start[1] - y1) - 1:int(start[1] - y1) + 2] = 1

        traversible = add_boundary(traversible)
        goal = add_boundary(goal, value=0)

        planner = FMMPlanner(traversible)
        selem = skimage.morphology.disk(10)
        goal = skimage.morphology.binary_dilation(
            goal, selem) != True
        goal = 1 - goal * 1.
        planner.set_multi_goal(goal)

        state = [start[0] - x1 + 1, start[1] - y1 + 1]
        stg_x, stg_y, replan, stop = planner.get_short_term_goal(state)

        stg_x, stg_y = stg_x + x1 - 1, stg_y + y1 - 1

        return (stg_x, stg_y), replan, stop

    def _preprocess_obs(self, obs, use_seg=True):
        args = self.args
        # print("obs: ", obs)
        obs = obs.transpose(1, 2, 0)
        rgb = obs[:, :, :3]
        depth = obs[:, :, 3:4]
        semantic = obs[:,:,4:5].squeeze()
        # print("obs: ", semantic.shape)
        if args.use_gtsem:
            self.rgb_vis = rgb
            sem_seg_pred = np.zeros((rgb.shape[0], rgb.shape[1], 15 + 1))
            for i in range(16):
                sem_seg_pred[:,:,i][semantic == i+1] = 1
        else:
            red_semantic_pred, semantic_pred = self._get_sem_pred(
                rgb.astype(np.uint8), depth, use_seg=use_seg)

            sem_seg_pred = np.zeros((rgb.shape[0], rgb.shape[1], 15 + 1))
            for i in range(0, 15):
                # print(mp_categories_mapping[i])
                sem_seg_pred[:,:,i][red_semantic_pred == mp_categories_mapping[i]] = 1

            sem_seg_pred[:,:,0][semantic_pred[:,:,0] == 0] = 0
            sem_seg_pred[:,:,1][semantic_pred[:,:,1] == 0] = 0
            sem_seg_pred[:,:,3][semantic_pred[:,:,3] == 0] = 0
            sem_seg_pred[:,:,4][semantic_pred[:,:,4] == 1] = 1
            sem_seg_pred[:,:,5][semantic_pred[:,:,5] == 1] = 1

        # sem_seg_pred = self._get_sem_pred(
        #     rgb.astype(np.uint8), depth, use_seg=use_seg)

        depth = self._preprocess_depth(depth, args.min_depth, args.max_depth)

        ds = args.env_frame_width // args.frame_width  # Downscaling factor
        if ds != 1:
            rgb = np.asarray(self.res(rgb.astype(np.uint8)))
            depth = depth[ds // 2::ds, ds // 2::ds]
            sem_seg_pred = sem_seg_pred[ds // 2::ds, ds // 2::ds]

        depth = np.expand_dims(depth, axis=2)
        state = np.concatenate((rgb, depth, sem_seg_pred),
                               axis=2).transpose(2, 0, 1)

        return state

    def _preprocess_depth(self, depth, min_d, max_d):
        depth = depth[:, :, 0] * 1

        for i in range(depth.shape[1]):
            depth[:, i][depth[:, i] == 0.] = depth[:, i].max()

        mask2 = depth > 0.99
        depth[mask2] = 0.

        mask1 = depth == 0
        depth[mask1] = 100.0
        # depth = min_d * 100.0 + depth * max_d * 100.0
        depth = min_d * 100.0 + depth * (max_d-min_d) * 100.0
        # depth = depth*1000.

        return depth

    def _get_sem_pred(self, rgb, depth, use_seg=True):
        if use_seg:
            image = torch.from_numpy(rgb).to(self.device).unsqueeze_(0).float()
            depth = torch.from_numpy(depth).to(self.device).unsqueeze_(0).float()
            with torch.no_grad():
                red_semantic_pred = self.red_sem_pred(image, depth)
                red_semantic_pred = red_semantic_pred.squeeze().cpu().detach().numpy()
            semantic_pred, self.rgb_vis = self.sem_pred.get_prediction(rgb)
            semantic_pred = semantic_pred.astype(np.float32)
        else:
            semantic_pred = np.zeros((rgb.shape[0], rgb.shape[1], 16))
            self.rgb_vis = rgb[:, :, ::-1]
        return red_semantic_pred, semantic_pred

    def _visualize(self, inputs):
        args = self.args
        dump_dir = "{}/dump/{}/".format(args.dump_location,
                                        args.exp_name)
        ep_dir = '{}/episodes/thread_{}/eps_{}/'.format(
            dump_dir, self.rank, self.episode_no)
        if not os.path.exists(ep_dir):
            os.makedirs(ep_dir)

        local_w = inputs['map_pred'].shape[0]

        map_pred = inputs['map_pred']
        exp_pred = inputs['exp_pred']
        map_edge = inputs['map_edge']
        start_x, start_y, start_o, gx1, gx2, gy1, gy2 = inputs['pose_pred']

        goal = inputs['goal']
        sem_map = inputs['sem_map_pred']

        gx1, gx2, gy1, gy2 = int(gx1), int(gx2), int(gy1), int(gy2)

        sem_map += 5

        no_cat_mask = sem_map == 20
        map_mask = np.rint(map_pred) == 1
        exp_mask = np.rint(exp_pred) == 1
        vis_mask = self.visited_vis[gx1:gx2, gy1:gy2] == 1
        edge_mask = map_edge == 1

        sem_map[no_cat_mask] = 0
        m1 = np.logical_and(no_cat_mask, exp_mask)
        sem_map[m1] = 2

        m2 = np.logical_and(no_cat_mask, map_mask)
        sem_map[m2] = 1

        sem_map[vis_mask] = 3
        sem_map[edge_mask] = 3

        selem = skimage.morphology.disk(4)
        goal_mat = 1 - skimage.morphology.binary_dilation(
            goal, selem) != True

        goal_mask = goal_mat == 1
        sem_map[goal_mask] = 4
        if np.sum(goal) == 1:
            f_pos = np.argwhere(goal == 1)
            # fmb = get_frontier_boundaries((f_pos[0][0], f_pos[0][1]))
            # goal_fmb = skimage.draw.circle_perimeter(int((fmb[0]+fmb[1])/2), int((fmb[2]+fmb[3])/2), 23)
            goal_fmb = skimage.draw.circle_perimeter(f_pos[0][0], f_pos[0][1], local_w/4-2)
            goal_fmb[0][goal_fmb[0] > local_w-1] = local_w-1
            goal_fmb[1][goal_fmb[1] > local_w-1] = local_w-1
            goal_fmb[0][goal_fmb[0] < 0] = 0
            goal_fmb[1][goal_fmb[1] < 0] = 0
            # goal_fmb[goal_fmb < 0] =0
            goal_mask[goal_fmb[0], goal_fmb[1]] = 1
            sem_map[goal_mask] = 4

        color_pal = [int(x * 255.) for x in color_palette]
        sem_map_vis = Image.new("P", (sem_map.shape[1],
                                      sem_map.shape[0]))
        sem_map_vis.putpalette(color_pal)
        sem_map_vis.putdata(sem_map.flatten().astype(np.uint8))
        sem_map_vis = sem_map_vis.convert("RGB")
        sem_map_vis = np.flipud(sem_map_vis)

        sem_map_vis = sem_map_vis[:, :, [2, 1, 0]]
        sem_map_vis = cv2.resize(sem_map_vis, (480, 480),
                                 interpolation=cv2.INTER_NEAREST)
        self.vis_image[50:530, 15:655] = self.rgb_vis
        self.vis_image[50:530, 670:1150] = sem_map_vis

        pos = (
            (start_x * 100. / args.map_resolution - gy1)
            * 480 / map_pred.shape[0],
            (map_pred.shape[1] - start_y * 100. / args.map_resolution + gx1)
            * 480 / map_pred.shape[1],
            np.deg2rad(-start_o)
        )

        agent_arrow = vu.get_contour_points(pos, origin=(670, 50), size=10)
        color = (int(color_palette[11] * 255),
                 int(color_palette[10] * 255),
                 int(color_palette[9] * 255))
        cv2.drawContours(self.vis_image, [agent_arrow], 0, color, -1)

        if args.visualize:
            # Displaying the image
            cv2.imshow("Thread {}".format(self.rank), self.vis_image)
            cv2.waitKey(1)

        if args.print_images:
            fn = '{}/episodes/thread_{}/eps_{}/{}-{}-Vis-{}.png'.format(
                dump_dir, self.rank, self.episode_no,
                self.rank, self.episode_no, self.timestep)
            cv2.imwrite(fn, self.vis_image)


import os
from time import sleep
from selenium.webdriver.support.select import Select
from webdriver_setup import get_webdriver_for

driver = get_webdriver_for("firefox")

html_page = "file://" + os.getcwd() + "/deselect_option.html"
driver.get(html_page)

select_element = driver.find_element_by_id("langs")

select_object = Select(select_element)

print(f"Multiple selections enabled: {select_object.is_multiple}")

# print all options
print("All options")
for option in select_object.options:
    print(option.text)

sleep(1)

# select three options
select_object.select_by_index(0)
select_object.select_by_value("js")
select_object.select_by_visible_text("Python")

# print all selected options
print("\nSelected options")
for option in select_object.all_selected_options:
    print(option.text)

sleep(1)

# deselect first option
select_object.deselect_by_index(0)

# print all selected options
print("\nSelected options after first deselect")
for option in select_object.all_selected_options:
    print(option.text)

sleep(1)

# deselect all selected options
print("\nDeselect all selected options")
select_object.deselect_all()

print(f"Number of selected options: {len(select_object.all_selected_options)}")

sleep(2)

driver.quit()


""" Name- Kishan Sharma
    Roll No - B20294
    Mob no - 8000543233 """
# Python code for Part-A (Lab-5)

# import module from python library
import pandas as pd
from sklearn.mixture import GaussianMixture
from sklearn.metrics import confusion_matrix , accuracy_score

# read the csv file of spilting data of train and test set using pandas library
train_data=pd.read_csv('SteelPlateFaults-train.csv')
test_data=pd.read_csv('SteelPlateFaults-test.csv')

# remove the some data column using drop function
train_data=train_data.drop(columns=[train_data.columns[0],'X_Minimum','Y_Minimum','TypeOfSteel_A300','TypeOfSteel_A400'])
test_data=test_data.drop(columns=[test_data.columns[0],'X_Minimum','Y_Minimum','TypeOfSteel_A300','TypeOfSteel_A400'])

# Classifing the train data basis on classes (class 1 or 0)
train_0=train_data[train_data['Class']==0].drop(columns=['Class'])
train_1=train_data[train_data['Class']==1].drop(columns=['Class'])

# Classifing the TEST data basis on classes (class 1 or 0)
test_0=test_data[test_data['Class']==0].drop(columns=['Class'])
test_1=test_data[test_data['Class']==1].drop(columns=['Class'])

# assume the value of maximum accurancy and corrosponding Q-value
Max_acc=0
Max_acc_Q=2
# Put the all Q-value in a list for GaussianMixture model predection
Q_list=[2,4,8,16]
for Q in Q_list:
    # make the GaussianMixture model for class 0 and class 1 using sklearn library function
    gmm_0 = GaussianMixture(n_components=Q,covariance_type='full',reg_covar=1e-4)
    gmm_1 = GaussianMixture(n_components=Q,covariance_type='full',reg_covar=1e-4)
    gmm_0.fit(train_0)
    gmm_1.fit(train_1)
    # find the probability of sample class of all the test data using score_samples function
    y_0=gmm_0.score_samples(test_data.iloc[:,:23])
    y_1=gmm_1.score_samples(test_data.iloc[:,:23])
    # Predect the class of test data using for loop
    pred=[]
    for i in range(len(y_1)):
        if y_0[i]>y_1[i]:
            pred.append(0)
        else:
            pred.append(1)
    # find the confusion matrix oand accuracy_score of test data for different Q-value
    conf_matrix = confusion_matrix(test_data['Class'],pred)
    predicted_acc=  accuracy_score(test_data['Class'],pred)

    print('Accuracy for the data predicted for ',Q,' components is :', round(predicted_acc,3))
    print("Confusion matrix for Q =",Q," is ---> ")
    print(conf_matrix)
    if(predicted_acc>Max_acc):
        Max_acc=predicted_acc
        Max_acc_Q=Q
    print("------")
# print the highest accuracy and corrosponding Q-value
print("Highest accuracy of the GMM model is: ",Max_acc," for Q: ",Max_acc_Q)
print("-----------------------------------------------------------------------------------")

Data Preprocessing and Modelling/Lab-5/Part-A-Que1.py


"""
Train model on qbf formulae over already trained models for lower quantification levels.
"""
import argparse
from tqdm import tqdm
import tensorflow as tf

from model import QBF_Model
from qcsp_utils import QCSP_Instance
from data_utils import load_qbf_formulas

tf.compat.v1.enable_eager_execution() # works only in eager mode currently...

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-s', '--state_size', type=int, default=128, help='Size of the variable states in QBF_Model')
    parser.add_argument('-e', '--epochs', type=int, default=25, help='Number of training epochs')
    parser.add_argument('-t', '--t_max', type=int, default=30, help='Number of iterations t_max for which QBF_Model runs on each instance')
    parser.add_argument('-b', '--batch_size', type=int, default=10, help='Batch size for training')
    parser.add_argument('-c', '--train_size', type=int, nargs='+', default=None, help='Scope of training instances in the data directory')
    parser.add_argument('-m', '--model_dirs', type=str, nargs='+', help='Directories in which the models are stored')
    parser.add_argument('-d', '--data_path', help='A path to a training set of formulas in the (Q)DIMACS cnf format.')
    args = parser.parse_args()

    print('Loading qbf formulas...')
    _, formulas = load_qbf_formulas(args.data_path, scope=args.train_size)
    print('Converting formulas to QCSP instances...')
    instances = [QCSP_Instance.qbf_to_instance(f) for f in tqdm(formulas)]

    # Combine instances into batches
    train_batches = QCSP_Instance.batch_instances(instances, args.batch_size)

    # Fetch weights from model directories
    models = QBF_Model.get_models(args.model_dirs, train_batches[0], state_size=args.state_size)

    # Construct and train new network
    trainable_model, inference_models = models[0], models[1:]
    trainable_model.train(train_batches, inference_models, iterations=args.t_max, epochs=args.epochs)

if __name__ == '__main__':
    main()


import sys, googletrans
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QTextEdit, QPushButton, QMenu, QAction, QMainWindow, QShortcut, QDesktopWidget
from googletrans import Translator #pip install googletrans==3.1.0a0
from PyQt5.QtCore import QThread, pyqtSignal, Qt, QEvent
import locale
import json
from PyQt5.QtGui import QKeySequence, QClipboard, QGuiApplication, QPainter, QPainterPath, QRegion

class TranslatorThreat(QThread): # googletrans ile yapılan çeviri işlemini farklı bir threat üzerinden yapıyor
    counter_signal = pyqtSignal(str)

    def setData(self, translatedata, translatesource, translatedest): # ana threat üzerinden inputtext verisi buraya gönderiliyor
        self.translatedata = translatedata
        self.translatesource = translatesource
        self.translatedest= translatedest

    def run(self): # gelen veri çeviri fonksiyonuna sokuluyor

        translator = Translator()
        output = translator.translate(self.translatedata, dest=self.translatedest, src=self.translatesource)
        #print(output.extra_data)
        outputDict = {"src":output.src, "dest": output.dest, "text": output.text} #  çıktının içeriği Dict yapısına dönüştürülüyor
        outputStr= json.dumps(outputDict)
        self.counter_signal.emit(outputStr) # çeviri işlemi yapıldıktan sonra son veri main threat'e gönderiliyor

class PyTranslator(QWidget):
    def __init__(self):
        super().__init__()

        locale.setlocale(locale.LC_ALL, '') # sistem dilini algıla ('tr_TR', 'UTF-8')
        self.systemlang=locale.getlocale()[0].split("_")[0] # tr

        # Pencere özelliklerini ayarla
        self.setWindowTitle("Translator")
        screen = QDesktopWidget().screenGeometry() # ekran çözünürlüğü
        screenWidth, screenHeight = screen.width(), screen.height() # 1920,1080
        self.windowWidth, self.windowHeight = 750, 300
        Xcenter=(screenWidth - self.windowWidth) // 2
        Ycenter=(screenHeight - self.windowHeight) // 5 # tam ortası için 2'ye bölünecek
        self.setGeometry(Xcenter, Ycenter, self.windowWidth, self.windowHeight) # pencerenin konumunu ayarlıyor

        self.setStyleSheet("background-color: #fff; color:black;")

        #Kısayollar
        shortcut1 = QShortcut(QKeySequence("Ctrl+Q"), self)
        shortcut1.activated.connect(self.close_window)
        shortcut2 = QShortcut(QKeySequence("ESC"), self)
        shortcut2.activated.connect(self.close_window)
        shortcut3 = QShortcut(QKeySequence("Alt+C"), self)
        shortcut3.activated.connect(self.changeLangs)
        shortcut4 = QShortcut(QKeySequence("Alt+F"), self)
        shortcut4.activated.connect(self.focus_input)
        shortcut4 = QShortcut(QKeySequence("Alt+A"), self)
        shortcut4.activated.connect(self.set_auto)

        # İçerik widgetlarını ayarla
        self.input_text = QTextEdit()
        self.input_text.setStyleSheet("border:none; background:#E7E7E8; ")
        self.output_text = QTextEdit()
        self.output_text.setReadOnly(True)
        self.output_text.setStyleSheet("border:none; background:#E7E7E8; ")

        # Input alanındaki metin değiştiğinde output alanını güncelle
        self.input_text.textChanged.connect(self.start_translator) # input alanındaki veri değiştiğinde start_translator fonksiyonu tetikleniyor

        self.translator_thread = TranslatorThreat()
        self.translator_thread.counter_signal.connect(self.update_output_text) # çeviri işlemini yapan TranslatorThreat sınıfı sinyal gönderdiği zaman update_output_text fonksiyonu tetikleniyor
        # Buton widgetını ayarla
        self.button1 = QPushButton("auto")
        self.button1.setFixedWidth(100)
        self.button1.clicked.connect(self.show_menu1)

        self.changebutton = QPushButton("<->")
        self.changebutton.setFixedWidth(50)
        self.changebutton.clicked.connect(self.changeLangs)

        self.button2 = QPushButton(googletrans.LANGUAGES[self.systemlang])
        self.button2.setFixedWidth(100)
        self.button2.clicked.connect(self.show_menu2)

        # Menü widgetını ayarla
        self.menu1 = QMenu()

        action = QAction("auto", self)
        action.triggered.connect(lambda checked, text=action.text(): self.button1.setText(text))
        self.menu1.addAction(action)
        for value in googletrans.LANGUAGES.values():
            action = QAction(str(value), self)
            action.triggered.connect(lambda checked, text=action.text(): self.button1.setText(text))
            self.menu1.addAction(action)
            self.menu1.addSeparator()

        self.menu1.setFixedWidth(300)
        self.menu1.setFixedHeight(400)
        self.menu1.setStyleSheet("QMenu {}")

        self.menu2 = QMenu()
        for value in googletrans.LANGUAGES.values():
            action = QAction(str(value), self)
            action.triggered.connect(lambda checked, text=action.text(): self.start_translator(text))
            self.menu2.addAction(action)
            self.menu2.addSeparator()

        self.menu2.setFixedWidth(300)
        self.menu2.setFixedHeight(400)
        self.menu2.setStyleSheet("QMenu {}")

        self.logrecord=QTextEdit()
        self.logrecord.setReadOnly(True)
        self.logrecord.setFixedHeight(33)
        self.logrecord.setStyleSheet("border:none;")

        # Widgetları düzenle
        hbox1 = QHBoxLayout()
        hbox1.addWidget(self.input_text)
        hbox1.addWidget(self.output_text)

        hbox2 = QHBoxLayout()
        hbox2.addWidget(self.button1)
        hbox2.addWidget(self.changebutton)
        hbox2.addWidget(self.button2)

        hbox3 = QHBoxLayout()
        hbox3.addWidget(self.logrecord)

        vbox = QVBoxLayout()
        vbox.addLayout(hbox2)
        vbox.addLayout(hbox1)
        vbox.addLayout(hbox3)

        self.setLayout(vbox)

        self.clipboard = QApplication.clipboard()
        if self.clipboard.mimeData().hasText():
            selected_text = self.clipboard.text()
            self.input_text.setText(selected_text)

        self.input_text.setFocus()
    def show_menu1(self):
        self.menu1.exec_(self.button1.mapToGlobal(self.button1.rect().bottomLeft()))

    def show_menu2(self):
        self.menu2.exec_(self.button2.mapToGlobal(self.button2.rect().bottomLeft()))

    def start_translator(self,text="empty"): # bu fonksiyon tetiklendiğinde farklı threat üzerindeki çeviriyi yapacak olan TranslatorThreat sınıfına input verisi gönderiliyor
        if text != "empty":
            self.button2.setText(text)
        source=self.button1.text()
        dest=self.button2.text()
        inputtext=self.input_text.toPlainText()
        if len(self.input_text.toPlainText()) > 0 : # input alanı boş ise çeviri fonksiyonu çalışmasın
            self.translator_thread.setData(inputtext,source,dest)
            self.translator_thread.start()
        else:
            self.output_text.setText("")
            self.logrecord.setText("Deleted")

    def update_output_text(self, outputStr): # çeviri işlemi yapıldığı zaman output alanı güncelleniyor
        # Input alanındaki metni output alanına kopyala
        self.outputDict = json.loads(outputStr)
        self.output_text.setText(self.outputDict['text'])
        logtext=googletrans.LANGUAGES[self.outputDict['src']] + " Algılandı"
        self.logrecord.setText(logtext)

    def changeLangs(self): # değiştir butonuna tıklandığında çalışacak fonksiyon
        if len(self.input_text.toPlainText()) > 0 : # text alanlarına bir metin girilmiş mi kontrol
            tmpdata = self.button1.text()
            self.button1.setText(self.button2.text()) # button1 butonunun yazısı button2 butonunun yazısı ile değiştiriliyor
            # button2 butonunun yazısı en son algılanmış dil ile değiştiriliyor
            if tmpdata == "auto":
                self.button2.setText(googletrans.LANGUAGES[self.outputDict['src']])
            else:
                self.button2.setText(tmpdata)

            inputtextTmp = self.input_text.toPlainText() # input alanındaki yazı geçici bir değişkene atanıyor
            self.input_text.setText(self.output_text.toPlainText()) # input alanına output alanındaki veri yazılıyor
            self.output_text.setText(inputtextTmp) # output alanına değişkene atadığımız input değişkeni yazılıyor
        elif self.button1.text() == "auto" :
            self.logrecord.setText("Source Lang is Auto")
        else :
            tmpdata=self.button1.text()
            self.button1.setText(self.button2.text())
            self.button2.setText(tmpdata)
            self.button1.text()

    def close_window(self):
        self.close()

    def focus_input(self):
        self.input_text.setFocus()
    def set_auto(self):
        self.button1.setText("auto")
        self.start_translator()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    widget = PyTranslator()
    widget.setWindowFlag(Qt.FramelessWindowHint)
    # Pencere kenarlarını yuvarlaklaştır
    radius = 17
    path = QPainterPath()
    path.addRoundedRect(0,0,750,300, radius, radius)
    region = QRegion(path.toFillPolygon().toPolygon())
    widget.setMask(region)
    widget.show()
    sys.exit(app.exec_())


import boto3, argparse, os, sys, logging
from application import Application
from loghelper import LogHelper
def main():
    LogHelper.start_logging("logdownloader.log")
    parser = argparse.ArgumentParser(
        description="AWS bootstrapper log downloader" +
                    "Downloads instances logs from AWS S3")
    parser.add_argument("--manifestPath", help = "path to a manifest file describing the jobs and data requirements for the application", required=True)
    parser.add_argument("--outputPath", help = "directory to where instance logs will be copied", required=True)

    try:
        args = vars(parser.parse_args())
        manifestPath = os.path.abspath(args["manifestPath"])
        outputdir = os.path.abspath(args["outputPath"])
        s3 = boto3.resource('s3')
        app = Application(s3, manifestPath, outputdir)
        app.downloadLogs(outputdir)

    except Exception as ex:
        logging.exception("error in log downloader")
        sys.exit(1)

if __name__ == "__main__":
    main()


from datetime import datetime
from sys import exit

from ..concurrency import WorkerPool
from ..utils.cmdline import count_items, get_target_nodes
from ..utils.table import ROW_SEPARATOR, render_table
from ..utils.text import (
    blue,
    bold,
    cyan,
    cyan_unless_zero,
    error_summary,
    format_duration,
    green,
    green_unless_zero,
    mark_for_translation as _,
    red,
    red_unless_zero,
)
from ..utils.ui import io

def stats_summary(node_stats, total_duration):
    for node in node_stats.keys():
        node_stats[node]['total'] = sum([
            node_stats[node]['good'],
            node_stats[node]['bad'],
            node_stats[node]['unknown'],
        ])
        try:
            node_stats[node]['health'] = \
                (node_stats[node]['good'] / float(node_stats[node]['total'])) * 100.0
        except ZeroDivisionError:
            node_stats[node]['health'] = 0

    totals = {
        'items': 0,
        'good': 0,
        'bad': 0,
        'unknown': 0,
    }
    node_ranking = []

    for node_name, stats in node_stats.items():
        totals['items'] += stats['total']
        totals['good'] += stats['good']
        totals['bad'] += stats['bad']
        totals['unknown'] += stats['unknown']
        node_ranking.append((
            stats['health'],
            node_name,
            stats['total'],
            stats['good'],
            stats['bad'],
            stats['unknown'],
            stats['duration'],
        ))

    node_ranking = sorted(node_ranking, reverse=True)

    try:
        totals['health'] = (totals['good'] / float(totals['items'])) * 100.0
    except ZeroDivisionError:
        totals['health'] = 0

    rows = [[
        bold(_("node")),
        _("items"),
        green(_("good")),
        red(_("bad")),
        cyan(_("unknown")),
        _("health"),
        _("duration"),
    ], ROW_SEPARATOR]

    for health, node_name, items, good, bad, unknown, duration in node_ranking:
        rows.append([
            node_name,
            str(items),
            green_unless_zero(good),
            red_unless_zero(bad),
            cyan_unless_zero(unknown),
            "{0:.1f}%".format(health),
            format_duration(duration),
        ])

    if len(node_ranking) > 1:
        rows.append(ROW_SEPARATOR)
        rows.append([
            bold(_("total ({} nodes)").format(len(node_stats.keys()))),
            str(totals['items']),
            green_unless_zero(totals['good']),
            red_unless_zero(totals['bad']),
            cyan_unless_zero(totals['unknown']),
            "{0:.1f}%".format(totals['health']),
            format_duration(total_duration),
        ])

    alignments = {
        1: 'right',
        2: 'right',
        3: 'right',
        4: 'right',
        5: 'right',
        6: 'right',
        7: 'right',
    }

    for line in render_table(rows, alignments=alignments):
        io.stdout("{x} {line}".format(x=blue("i"), line=line))

def bw_verify(repo, args):
    errors = []
    node_stats = {}
    pending_nodes = get_target_nodes(repo, args['targets'])
    start_time = datetime.now()
    io.progress_set_total(count_items(pending_nodes))

    def tasks_available():
        return bool(pending_nodes)

    def next_task():
        node = pending_nodes.pop()
        return {
            'target': node.verify,
            'task_id': node.name,
            'kwargs': {
                'autoonly_selector': args['autoonly'],
                'autoskip_selector': args['autoskip'],
                'show_all': args['show_all'],
                'show_diff': args['show_diff'],
                'workers': args['item_workers'],
            },
        }

    def handle_result(task_id, return_value, duration):
        node_stats[task_id] = return_value

    def handle_exception(task_id, exception, traceback):
        msg = "{}: {}".format(
            task_id,
            exception,
        )
        io.stderr(traceback)
        io.stderr(repr(exception))
        io.stderr(msg)
        errors.append(msg)

    worker_pool = WorkerPool(
        tasks_available,
        next_task,
        handle_result=handle_result,
        handle_exception=handle_exception,
        pool_id="verify",
        workers=args['node_workers'],
    )
    worker_pool.run()

    if args['summary'] and node_stats:
        stats_summary(node_stats, datetime.now() - start_time)

    error_summary(errors)

    exit(1 if errors else 0)


#
# @lc app=leetcode id=64 lang=python3
#
# [64] Minimum Path Sum
#
from typing import List
# @lc code=start
class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        h = len(grid)
        w = len(grid[0])
        for i in range(1, w):
            grid[0][i] = grid[0][i-1]+grid[0][i]
        for i in range(1, h):
            grid[i][0] = grid[i-1][0]+grid[i][0]

        for y in range(1, h):
            for x in range(1, w):
                grid[y][x] = min(
                    grid[y][x-1],
                    grid[y-1][x]
                )+grid[y][x]
        return grid[-1][-1]
# @lc code=end

grid = [
  [1,3,1],
  [1,5,1],
  [4,2,1]
]

res = Solution().minPathSum(grid)

print(res)


from aiogram import types, Router
from aiogram.filters import Filter

from .. import assets
from ..app import dp

router = Router(name=__name__)

class MyFilter(Filter):
    def __init__(self, my_text: str) -> None:
        self.my_text = my_text

    async def __call__(self, message: types.Message) -> bool:
        return message.text == self.my_text

@dp.message(MyFilter(assets.reply_keyboards.hello_button.text))
async def hello_message(message: types.Message):
    from ..assets.reply_keyboards import menu_buttons
    from ..assets.message_text import send_question

    keyboard = types.ReplyKeyboardMarkup(keyboard=menu_buttons,resize_keyboard=True)
    await message.answer(text=send_question, reply_markup=keyboard)

    return

@dp.message(MyFilter(assets.reply_keyboards.back_button.text))
async def back_button(message: types.Message):
    await hello_message(message)

    return

@dp.message(MyFilter(assets.reply_keyboards.rsreu_site.text))
async def get_doc(message: types.Message):
    from ..assets.inline_keyboards import menu_button, rsreu_site_button
    from ..assets.message_text import link_to_rsreu

    keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
            [rsreu_site_button],
            [menu_button]])
    await message.answer(text=link_to_rsreu, reply_markup=keyboard)

    return

@dp.message(MyFilter(assets.reply_keyboards.cdo_site.text))
async def get_doc(message: types.Message):
    from ..assets.inline_keyboards import menu_button, cdo_site_button
    from ..assets.message_text import link_to_cdo

    keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
            [cdo_site_button],
            [menu_button]])
    await message.answer(text=link_to_cdo, reply_markup=keyboard)

    return

@dp.message(MyFilter(assets.reply_keyboards.edu_site.text))
async def get_doc(message: types.Message):
    from ..assets.inline_keyboards import menu_button, edu_site_button
    from ..assets.message_text import link_to_edu

    keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
            [edu_site_button],
            [menu_button]])
    await message.answer(text=link_to_edu, reply_markup=keyboard)

    return


# Python 2.7
import urllib
from bs4 import BeautifulSoup

# Finds the average amount of replies (per thread) on the first page of the Starcraft II General Discussion Forums.
def readLog():
        url = 'http://us.battle.net/sc2/en/forum/40568/'
        soup = BeautifulSoup(urllib.urlopen(url).read())

        sumOfReplies = 0
        for thread in range(43):
                replyCount = soup.findAll('td', {'class':'reply-cell'})[thread].contents[0]
                sumOfReplies += int(replyCount)
        replyAverage = (int(sumOfReplies) / 44.00)
        print("The average reply count is: %s" % replyAverage)
readLog()


from django.db import models
from django.contrib.auth import get_user_model
from django.core.validators import MinValueValidator, MaxValueValidator
from reviews.validators import year_validator

User = get_user_model()
CROP_LEN_TEXT = 30

class Genre(models.Model):
    """Модель для работы с жанрами"""

    name = models.CharField(
        max_length=256,
        verbose_name='Название жанра'
    )
    slug = models.SlugField(
        max_length=50,
        unique=True,
        verbose_name='Конвертер пути',
        help_text='Введите данные типа slug',
    )

    class Meta:
        verbose_name = 'Жанр'
        verbose_name_plural = 'Жанры'
        ordering = ['name']

    def __str__(self):
        return self.name

class Category(models.Model):
    """Модель для работы с категориями."""

    name = models.CharField(
        max_length=256,
        verbose_name='Название категории'
    )
    slug = models.SlugField(
        max_length=50,
        unique=True,
        verbose_name='Конвертер пути',
        help_text='Введите данные типа slug'
    )

    class Meta:
        verbose_name = 'Категория'
        verbose_name_plural = 'Категории'
        ordering = ['name']

    def __str__(self):
        return self.name

class Title(models.Model):
    """Модель для работы с произведениями."""

    name = models.CharField(
        max_length=256,
        verbose_name='Название произведения'
    )
    description = models.TextField(
        null=True,
        blank=True,
        verbose_name='Описание произведения'
    )
    year = models.PositiveSmallIntegerField(
        validators=[year_validator],
        verbose_name='Дата написания'

    )
    category = models.ForeignKey(
        Category,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='titles',
        verbose_name='Категория'
    )
    genre = models.ManyToManyField(
        Genre,
        through='GenreToTitle',
        verbose_name='Жанр'
    )

    class Meta:
        verbose_name = 'Произведение'
        verbose_name_plural = 'Произведения'
        indexes = [models.Index(fields=['-year'])]

    def __str__(self):
        return self.name

class GenreToTitle(models.Model):
    """Модель, связывающая произведение с жанром."""

    title = models.ForeignKey(Title, on_delete=models.CASCADE)
    genre = models.ForeignKey(Genre, on_delete=models.CASCADE)

    def __str__(self):
        return f'{self.title} {self.genre}'

class Review(models.Model):
    """Модель отзывов к произведениям."""

    text = models.TextField('Текст')
    author = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='reviews',
        verbose_name='Автор'
    )
    score = models.IntegerField(
        'Оценка',
        validators=[
            MinValueValidator(1),
            MaxValueValidator(10),
        ]
    )

    pub_date = models.DateTimeField(
        'Дата публикации',
        auto_now_add=True,
    )
    title = models.ForeignKey(
        Title,
        on_delete=models.CASCADE,
        related_name='reviews',
        verbose_name='Произведение'
    )

    class Meta:
        verbose_name = 'Отзыв'
        verbose_name_plural = 'Отзывы'
        indexes = [models.Index(fields=['-pub_date'])]
        ordering = ('-pub_date',)
        constraints = [
            models.UniqueConstraint(
                fields=['title', 'author'],
                name='unique_title_author'
            ),
        ]

    def __str__(self):
        return self.text[:CROP_LEN_TEXT]

class Comment(models.Model):
    """Модель комментариев к отзывам."""

    text = models.TextField('Текст')
    author = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='comments',
        verbose_name='Автор'
    )
    review = models.ForeignKey(
        Review,
        on_delete=models.CASCADE,
        related_name='comments',
        verbose_name='Отзыв'
    )
    pub_date = models.DateTimeField(
        'Дата публикации',
        auto_now_add=True,
    )

    class Meta:
        verbose_name = 'Комментарий к отзывам'
        verbose_name_plural = 'Комментарии к отзывам'
        indexes = [models.Index(fields=['-pub_date'])]
        ordering = ('-pub_date',)

    def __str__(self):
        return self.text[:CROP_LEN_TEXT]


import pandas as pd
import en_core_web_sm
import spacy
from spacy import displacy
import nltk
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
import random
import time
import numpy as np

''' Compare the efficiency of spaCy against NLTK '''

# nltk.download('punkt')
# nltk.download('averaged_perceptron_tagger')
# nltk.download('maxent_ne_chunker')
# nltk.download('words')
def relevant_entity(e):
    unwanted = ['ORDINAL', 'CARDINAL', 'QUANTITY', 'MONEY', 'PERCENT', 'TIME', 'DATE']
    return e not in unwanted

def ner_using_spacy(article):
    doc = nlp(article)
    return doc
    # return [(X.text, X.label_) for X in doc.ents]

def ner_using_nltk(article):
    tokens = word_tokenize(article)
    pos = pos_tag(tokens)
    ner = nltk.ne_chunk(pos)
    return ner

nlp = en_core_web_sm.load()
df = pd.read_csv('data/news-2018.csv')
spacy_time = []
nltk_time = []

for i in range(50):
    x = random.randint(1, df.shape[0]-1)
    article = df.loc[x]['article']
    start = time.time()
    ner_using_spacy(article)
    spacy_elapsed = time.time() - start
    spacy_time.append(spacy_elapsed)
    start = time.time()
    ner_using_nltk(article)
    nltk_elpased = time.time() - start
    nltk_time.append(nltk_elpased)
    print("spacy:", spacy_elapsed, "nltk:", nltk_elpased)

print("Spacy average time to recognize entities: ", np.average(np.array(spacy_time)))
print("Nltk average time to recognize entities: ", np.average(np.array(nltk_time)))


import collections
import time
from typing import Tuple, Any, Dict, List
import gym  # type: ignore
import numpy as np

from pyreach.gyms import core
from pyreach.gyms import reach_env

class BenchmarkIntegrationEnv(reach_env.ReachEnv):  # type: ignore
  """Benchmark integration testing environment."""

  def __init__(self, **kwargs: Any) -> None:
    """Initialize the Singulation environment."""
    center_joint_angles: List[float] = [3.06, -1.66, -1.57, -1.10, 1.7, 0.0]
    low_joint_angles: Tuple[float, ...] = tuple(
        [cja - 5.0 for cja in center_joint_angles])
    high_joint_angles: Tuple[float, ...] = tuple(
        [cja + 5.0 for cja in center_joint_angles])

    task_params: Dict[str, str] = {
        "task-code": "9999999999",
    }

    pyreach_config: Dict[str, reach_env.ReachElement] = {
        "arm":
            reach_env.ReachArm(
                "", low_joint_angles, high_joint_angles, is_synchronous=True),
        # pylint: disable=g-bad-todo
        # TODO: These should be re-enabled and checked that there
        # is an observation in there.
        # "camera":
        #     reach_env.ReachColorCamera("", (576, 1024), is_synchronous=True),
        # "depth_camera":
        #     reach_env.ReachDepthCamera(
        #         "", (720, 1280), True, is_synchronous=True),
        "server":
            reach_env.ReachServer("Server"),
        "text_instructions":
            reach_env.ReachTextInstructions("instruction-generator"),
    }

    super().__init__(
        pyreach_config=pyreach_config, task_params=task_params, **kwargs)

  def step(self,
           action: core.Action) -> Tuple[core.Observation, float, bool, Any]:
    """Perform one step."""
    observation: core.Observation
    reward: float
    done: bool
    info: Any

    observation, reward, done, info = super().step(action)

    if done:
      observation, _, _, info = self._ask_for_new_instruction(observation)
      return (observation, reward, done, info)

    return (observation, reward, done, info)

  def _ask_for_new_instruction(
      self, current_observation: core.Observation
  ) -> Tuple[core.Observation, float, bool, Any]:
    """Asks for a new instruction.

    If we time out waiting for a new instruction, that means that
    we have completed all instructions, and we return None,
    otherwise we return the latest observation.

    Args:
      current_observation: the current observation.

    Returns:
      The observation when the instruction is received.
    """
    print(f"{time.time()}: Asking for a new text instruction")

    # End current task
    action = collections.OrderedDict(
        {"text_instructions": collections.OrderedDict({"task_enable": 0})})

    _, _, _, _ = super().step(action)

    # Start new task
    action = collections.OrderedDict(
        {"text_instructions": collections.OrderedDict({"task_enable": 1})})
    return super().step(action)

  def reset(self) -> core.Observation:
    """Resets the benchmark.

    On SIM, this resets the scene and returns an observation. On real, it only
    returns an observation.

    Returns:
      Initial observation.
    """

    # End any current task
    action = collections.OrderedDict(
        {"text_instructions": collections.OrderedDict({"task_enable": 0})})
    _, _, _, _ = super().step(action)
    obs = super().reset()

    # Start a new task
    action = collections.OrderedDict(
        {"text_instructions": collections.OrderedDict({"task_enable": 1})})
    obs, _, _, _ = super().step(action)

    return obs

class BenchmarkIntegrationWrapper(gym.Wrapper):
  """A wrapper for the Benchmark integration testing environment.

  This environment is a stripped-down environment which provides actions for
  moves of joints only.

  == Actions ==

  action["arm"]:
    "joint_angles":
        # The joints to move to, in radians.
        gym.spaces.Box(
            low=np.array((-6.283, -2.059, -3.926, -3.141, 1.692, -6.283)),
            high=np.array((6.283, 2.094, 0.191, 3.141, 3.141, 6.283)),
            dtype=np.dtype(float)),

  == Observations ==

    No filters! See BenchmarkIntegrationEnv!
  """

  def __init__(self, env: BenchmarkIntegrationEnv) -> None:
    super().__init__(env)

    self.env = env

    self.action_space: core.Space = gym.spaces.Dict({
        "arm":
            gym.spaces.Dict({
                "joint_angles": self.env.action_space["arm"]["joint_angles"],
            })
    })
    self.observation_space: core.Space = self.env.observation_space

  def step(self,
           action: core.Action) -> Tuple[core.Observation, float, bool, Any]:
    assert isinstance(action, (dict, collections.OrderedDict))
    arm: Any = action["arm"]
    assert isinstance(arm, (dict, collections.OrderedDict))
    pose: Any = arm["joint_angles"]
    assert isinstance(pose, np.ndarray)
    new_action = {
        "arm": {
            "command": 1,
            "joint_angles": action["arm"]["joint_angles"],
        },
    }

    return self.env.step(new_action)


#!/usr/bin/python3

from gi.repository import Gtk
from gi.repository import GObject
import webbrowser
import urllib.request
import re

def getNyan():
	USER_AGENT = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36"
	r = urllib.request.Request("http://nyanyan.it/", headers={'User-Agent': USER_AGENT, 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'})
	data = urllib.request.urlopen(r)
	data = data.read()
	found = re.findall( '
.*
', str(data) )
	return found[0]
class nyanIcon:
	def __init__( self ):
		self.site = getNyan()
		self.trayicon = Gtk.StatusIcon()
		self.trayicon.set_from_file( "normal.png" )
		self.trayicon.set_visible( True )
		self.trayicon.connect( "activate", self.openNyan )
		self.trayicon.connect( "popup-menu", self.options )
		GObject.timeout_add( 5000, self.checkNyan )
		Gtk.main()
	def options( self, icon, button, time ):
		self.menu = Gtk.Menu()

		exit = Gtk.MenuItem()
		exit.set_label( "Exit" )
		exit.connect( "activate", Gtk.main_quit )

		self.menu.append( exit )
		self.menu.show_all()

		def pos( menu, icon):
			return (Gtk.StatusIcon.position_menu(menu, icon))
		self.menu.popup(None, None, pos, self.trayicon, button, time)
	def checkNyan( self, *args ):
		tempsite = getNyan()
		if tempsite != self.site:
			self.site = tempsite
			self.trayicon.set_from_file( "new.png" )
		GObject.timeout_add( 60000*5, self.checkNyan )
	def openNyan( self, *args ):
		self.trayicon.set_from_file( "normal.png" )
		webbrowser.open( "http://nyanyan.it/" )

app = nyanIcon()


from typing import List, Set, Dict, Tuple, Any, Optional, Iterator, Union, Callable
from pathlib import Path
from tqdm import tqdm

import numpy as np
import tensorflow as tf
from tensorflow.keras.models import load_model

from realestate_core.common.run_config import home, bOnColab

import pandas as pd

class ExteriorClassifier:
  def __init__(self):
    self.model_files = [
                           'resnet50_distill_exteriors.acc.0.9106.h5',
                           'resnet50_distill_exteriors.acc.0.9114.h5',
                           'resnet50_distill_exteriors.acc.0.9131.h5',
                           'resnet50_distill_exteriors.acc.0.9116.h5',
                           'resnet50_distill_exteriors.acc.0.9072.h5'
                           ]

    self.labels = ['facade', 'backyard', 'view', 'exterior']

    self.img_height, self.img_width = 224, 224    # exterior classification model take in 224x224 images

  def predict(self,
              batch_img_ds: tf.data.Dataset = None,
              img_array: np.ndarray = None,
              img_names: List[str] = None,
              data_src: str=None,
              return_pd_dataframe=False) -> Union[pd.DataFrame, np.ndarray]:

    # either img_array or batch_img_ds must be provided
    assert (img_array is not None) or (batch_img_ds is not None), 'Either img_array or batch_img_ds must be provided.'

    if img_array is not None:
      assert img_array.shape[1:] == (self.img_height, self.img_width, 3), f'img_array shape must be (N, {self.img_height}, {self.img_width}, 3)'

    inputs = img_array if img_array is not None else batch_img_ds

    y_preds = []
    for m in self.model_files:
      print(m)
      model = load_model(home/'ListingImageClassification'/'training'/'exteriors'/m)
      input_img_height, input_img_width = model.input.shape[1:3]

      assert input_img_height == self.img_height and input_img_width == self.img_width, 'model input shape is not 224x224'

      y_pred = model.predict(inputs)
      y_pred = tf.nn.sigmoid(y_pred).numpy()     # distill model return logits
      y_preds.append(y_pred)

    y_preds = np.stack(y_preds)
    y_pred = np.mean(y_preds, axis=0)

    if not return_pd_dataframe: return y_pred
    else:
      df = self._convert_pred_to_df(y_pred, img_names, data_src)
      return df

  def predict_from_img_paths(self, img_paths: List[Path], return_pd_dataframe=False) -> Union[pd.DataFrame, np.ndarray]:
    if isinstance(img_paths, str) or isinstance(img_paths, Path): img_paths = [img_paths]

    def read_decode_resize(fname):
      img = tf.image.decode_jpeg(tf.io.read_file(fname), channels=3)
      img = tf.image.resize(img, (224, 224), method=tf.image.ResizeMethod.BILINEAR)
      return img

    img_names = [p.name for p in img_paths]
    img_paths = [str(p) for p in img_paths]

    file_ds = tf.data.Dataset.from_tensor_slices(img_paths)
    img_ds = file_ds.map(read_decode_resize, num_parallel_calls=tf.data.AUTOTUNE)

    batch_img_ds = img_ds.batch(32).prefetch(tf.data.AUTOTUNE)

    return self.predict(batch_img_ds, img_names, return_pd_dataframe=return_pd_dataframe)

  def _convert_pred_to_df(self, y_pred: np.ndarray, img_names: List[str], data_src=None) -> pd.DataFrame:
    df = pd.DataFrame(data={
        'img': img_names,
        'p_facade': np.round(y_pred[:, 1].astype('float'), 4),    # first element was an indicator for hard vs. soft labels during training, should ignore during inference.
        'p_backyard': np.round(y_pred[:, 2].astype('float'), 4),
        'p_view': np.round(y_pred[:, 3].astype('float'), 4),
        'p_exterior': np.round(y_pred[:, 4].astype('float'), 4),
        'data_src': data_src
      })

    return df

class GeneralClassifier:
  INOUT_DOOR_CLASS_NAMES = ['indoor', 'other', 'outdoor']
  ROOM_CLASS_NAMES = ['basement', 'bathroom', 'bedroom', 'dining_room', 'garage', 'gym_room', 'kitchen', 'laundry_room', 'living_room', 'office', 'other', 'storage']
  BOOLEAN_FEATURE_CLASS_NAMES = ['fireplace', 'agpool', 'body_of_water', 'igpool', 'balcony', 'deck_patio_veranda', 'ss_kitchen', 'double_sink', 'upg_kitchen']

  def __init__(self):
    self.model_file = home/'ListingImageClassification'/'training'/'hydra_all'/'resnet50_hydra_all.acc.0.9322.h5'

    self.img_height, self.img_width = 416, 416    # general classification model take in 416x416 images

  def predict(self,
              batch_img_ds: tf.data.Dataset = None,
              img_array: np.ndarray = None,
              img_names: List[str] = None,
              data_src: str=None,
              return_pd_dataframe=False) -> Union[pd.DataFrame, np.ndarray]:

    # either img_array or batch_img_ds must be provided
    assert (img_array is not None) or (batch_img_ds is not None), 'Either img_array or batch_img_ds must be provided.'

    if img_array is not None:
      assert img_array.shape[1:] == (self.img_height, self.img_width, 3), f'img_array shape must be (N, {self.img_height}, {self.img_width}, 3)'

    inputs = img_array if img_array is not None else batch_img_ds

    model = load_model(self.model_file, compile=False)
    input_img_height, input_img_width = model.input.shape[1:3]

    assert input_img_height == self.img_height and input_img_width == self.img_width, 'model input shape is not 416x416'

    yhats = model.predict(inputs)
    if not return_pd_dataframe: return yhats

    df = self._convert_pred_to_df(yhats, img_names, data_src)
    return df

  def predict_from_img_paths(self, img_paths: List[Path], return_pd_dataframe=False) -> Union[pd.DataFrame, np.ndarray]:
    if isinstance(img_paths, str) or isinstance(img_paths, Path): img_paths = [img_paths]

    def read_decode_resize(fname):
      img = tf.image.decode_jpeg(tf.io.read_file(fname), channels=3)
      img = tf.image.resize(img, (416, 416), method=tf.image.ResizeMethod.BILINEAR)
      return img

    img_names = [p.name for p in img_paths]
    img_paths = [str(p) for p in img_paths]

    file_ds = tf.data.Dataset.from_tensor_slices(img_paths)
    img_ds = file_ds.map(read_decode_resize, num_parallel_calls=tf.data.AUTOTUNE)

    batch_img_ds = img_ds.batch(32).prefetch(tf.data.AUTOTUNE)

    return self.predict(batch_img_ds, img_names, return_pd_dataframe=return_pd_dataframe)

  def _convert_pred_to_df(self, yhats: np.ndarray, img_names: List[str], data_src=None) -> pd.DataFrame:
    iodoor_yhats = yhats[0]
    room_yhats = yhats[1]

    fireplace_yhats = yhats[2]
    agpool_yhats = yhats[3]
    body_of_water_yhats = yhats[4]
    igpool_yhats = yhats[5]
    balcony_yhats = yhats[6]
    deck_patio_veranda_yhats = yhats[7]
    ss_kitchen_yhats = yhats[8]
    double_sink_yhats = yhats[9]
    upg_kitchen_yhats = yhats[10]

    room_top_3 = tf.math.top_k(room_yhats, k=3)
    inoutdoor = [GeneralClassifier.INOUT_DOOR_CLASS_NAMES[int(y)] for y in np.squeeze(np.argmax(iodoor_yhats, axis=-1))]

    predictions_df = pd.DataFrame(data={
      # 'img': [Path(img).name for img in imgs],
      'img': img_names,
      'inoutdoor': inoutdoor,
      'p_iodoor': np.round(np.max(iodoor_yhats, axis=-1).astype('float'), 4),

      'room': [GeneralClassifier.ROOM_CLASS_NAMES[int(y)] for y in np.squeeze(np.argmax(room_yhats, axis=-1))],
      'p_room': np.round(np.max(room_yhats, axis=-1).astype('float'), 4),

      'room_1': np.array(GeneralClassifier.ROOM_CLASS_NAMES)[room_top_3.indices.numpy()[:, 1]],
      'p_room_1': np.round(room_top_3.values.numpy()[:, 1].astype('float'), 4),
      'room_2': np.array(GeneralClassifier.ROOM_CLASS_NAMES)[room_top_3.indices.numpy()[:, 2]],
      'p_room_2': np.round(room_top_3.values.numpy()[:, 2].astype('float'), 4),

      'p_fireplace': np.round(np.squeeze(fireplace_yhats).astype('float'), 4),
      'p_agpool': np.round(np.squeeze(agpool_yhats).astype('float'), 4),
      'p_body_of_water': np.round(np.squeeze(body_of_water_yhats).astype('float'), 4),
      'p_igpool': np.round(np.squeeze(igpool_yhats).astype('float'), 4),
      'p_balcony': np.round(np.squeeze(balcony_yhats).astype('float'), 4),
      'p_deck_patio_veranda': np.round(np.squeeze(deck_patio_veranda_yhats).astype('float'), 4),
      'p_ss_kitchen': np.round(np.squeeze(ss_kitchen_yhats).astype('float'), 4),
      'p_double_sink': np.round(np.squeeze(double_sink_yhats).astype('float'), 4),
      'p_upg_kitchen': np.round(np.squeeze(upg_kitchen_yhats).astype('float'), 4),

      'data_src': data_src
    })

    return predictions_df