<commit_before>import logging
import random
import numpy as np

try:
    # Import serializable if rllab is installed
    from rllab.core.serializable import Serializable
except ImportError as e:
    Serializable = object

from flow.core.params import InitialConfig
from flow.core.traffic_lights import TrafficLights


VEHICLE_LENGTH = 5  # length of vehicles in the network, in meters


class Scenario(Serializable):
    def __init__(self, name, generator_class, vehicles, net_params,
                 initial_config=InitialConfig(),
                 traffic_lights=TrafficLights()):
        """
        Abstract base class. Initializes a new scenario. This class can be
        instantiated once and reused in multiple experiments. Note that this
        function stores all the relevant parameters. The generate() function
        still needs to be called separately.

        Attributes
        ----------
        name: str
            A tag associated with the scenario
        generator_class: Generator type
            Class for generating configuration and net files with placed
            vehicles, e.g. CircleGenerator
        vehicles: Vehicles type
            see flow/core/vehicles.py
        net_params: NetParams type
            see flow/core/params.py
        initial_config: InitialConfig type
            see flow/core/params.py
        traffic_lights: flow.core.traffic_lights.TrafficLights type
            see flow/core/traffic_lights.py
        """
        # Invoke serializable if using rllab
        if Serializable is not object:
            Serializable.quick_init(self, locals())

        self.name = name
        self.generator_class = generator_class
        self.vehicles = vehicles
        self.net_params = net_params
        self.initial_config = initial_config
        self.traffic_lights = traffic_lights

        # create a generator instance
        self.generator = self.generator_class(self.net_params, self.name)

        # create the network configuration file from the generator
        self._edges, self._connections = self.generator.generate_net(
            self.net_params, self.traffic_lights)

        # list of edges and internal links (junctions)
        self._edge_list = [edge_id for edge_id in self._edges.keys()
                           if edge_id[0] != ":"]
        self._junction_list = list(set(self._edges.keys())-set(self._edge_list))

        # parameters to be specified under each unique subclass's
        # __init__() function
        self.edgestarts = self.specify_edge_starts()

        # these optional parameters need only be used if "no-internal-links"
        # is set to "false" while calling sumo's netconvert function
        self.internal_edgestarts = self.specify_internal_edge_starts()
        self.intersection_edgestarts = self.specify_intersection_edge_starts()

        # in case the user did not write the intersection edge-starts in
        # internal edge-starts as well (because of redundancy), merge the two
        # together
        self.internal_edgestarts += self.intersection_edgestarts
        seen = set()
        self.internal_edgestarts = \
            [item for item in self.internal_edgestarts
             if item[1] not in seen and not seen.add(item[1])]

        # total_edgestarts and total_edgestarts_dict contain all of the above
        # edges, with the former being ordered by position
        if self.net_params.no_internal_links:
            self.total_edgestarts = self.edgestarts
        else:
            self.total_edgestarts = self.edgestarts + self.internal_edgestarts
        self.total_edgestarts.sort(key=lambda tup: tup[1])

        self.total_edgestarts_dict = dict(self.total_edgestarts)

        # length of the network, or the portion of the network in which cars are
        # meant to be distributed (may be overridden by subclass __init__())
        if not hasattr(self, "length"):
            self.length = sum([self.edge_length(edge_id)
                               for edge_id in self.get_edge_list()])

        # generate starting position for vehicles in the network
        if self.initial_config.positions is None:
            self.initial_config.positions, self.initial_config.lanes = \
                self.generate_starting_positions()

        # create the sumo configuration files using the generator class
        cfg_name = self.generator.generate_cfg(self.net_params)
        self.generator.make_routes(self, self.initial_config)

        # specify the location of the sumo configuration file
        self.cfg = self.generator.cfg_path + cfg_name

    def specify_edge_starts(self):
        """
        Defines edge starts for road sections with respect to some global
        reference frame.
        MUST BE implemented in any new scenario subclass.

        Returns
        -------
        edgestarts: list
            list of edge names and starting positions,
            ex: [(edge0, pos0), (edge1, pos1), ...]
        """
        raise NotImplementedError

    def specify_intersection_edge_starts(self):
        """
        Defines edge starts for intersections with respect to some global
        reference frame. Need not be specified if no intersections exist.
        These values can be used to determine the distance of some agent from
        the nearest and/or all intersections.

        Returns
        -------
        intersection_edgestarts: list
            list of intersection names and starting positions,
            ex: [(intersection0, pos0), (intersection1, pos1), ...]
        """
        return []

    def specify_internal_edge_starts(self):
        """
        Defines the edge starts for internal edge nodes (caused by finite-length
        connections between road sections) with respect to some global reference
        frame. Does not need to be specified if "no-internal-links" is set to
        True in net_params.

        Returns
        -------
        internal_edgestarts: list
            list of internal junction names and starting positions,
            ex: [(internal0, pos0), (internal1, pos1), ...]
        """
        return []

    def get_edge(self, x):
        """
        Given an absolute position x on the track, returns the edge (name) and
        relative position on that edge.

        Parameters
        ----------
        x: float
            absolute position in network

        Returns
        -------
        edge position: tup
            1st element: edge name (such as bottom, right, etc.)
            2nd element: relative position on edge
        """
        for (edge, start_pos) in self.total_edgestarts[::-1]:
            if x >= start_pos:
                return edge, x - start_pos

        # return default values if no match was found above
        return "", 0

    def get_x(self, edge, position):
        """
        Given an edge name and relative position, return the absolute position
        on the track.

        Parameters
        ----------
        edge: str
            name of the edge
        position: float
            relative position on the edge

        Returns
        -------
        absolute_position: float<commit_msg>PR fix<commit_after>import logging
import random
import numpy as np

try:
    # Import serializable if rllab is installed
    from rllab.core.serializable import Serializable
except ImportError as e:
    Serializable = object

from flow.core.params import InitialConfig
from flow.core.traffic_lights import TrafficLights


VEHICLE_LENGTH = 5  # length of vehicles in the network, in meters


class Scenario(Serializable):
    def __init__(self, name, generator_class, vehicles, net_params,
                 initial_config=InitialConfig(),
                 traffic_lights=TrafficLights()):
        """
        Abstract base class. Initializes a new scenario. This class can be
        instantiated once and reused in multiple experiments. Note that this
        function stores all the relevant parameters. The generate() function
        still needs to be called separately.

        Attributes
        ----------
        name: str
            A tag associated with the scenario
        generator_class: Generator type
            Class for generating configuration and net files with placed
            vehicles, e.g. CircleGenerator
        vehicles: Vehicles type
            see flow/core/vehicles.py
        net_params: NetParams type
            see flow/core/params.py
        initial_config: InitialConfig type
            see flow/core/params.py
        traffic_lights: flow.core.traffic_lights.TrafficLights type
            see flow/core/traffic_lights.py
        """
        # Invoke serializable if using rllab
        if Serializable is not object:
            Serializable.quick_init(self, locals())

        self.name = name
        self.generator_class = generator_class
        self.vehicles = vehicles
        self.net_params = net_params
        self.initial_config = initial_config
        self.traffic_lights = traffic_lights

        # create a generator instance
        self.generator = self.generator_class(self.net_params, self.name)

        # create the network configuration file from the generator
        self._edges, self._connections = self.generator.generate_net(
            self.net_params, self.traffic_lights)

        # list of edges and internal links (junctions)
        self._edge_list = [edge_id for edge_id in self._edges.keys()
                           if edge_id[0] != ":"]
        self._junction_list = list(set(self._edges.keys())-set(self._edge_list))

        # parameters to be specified under each unique subclass's
        # __init__() function
        self.edgestarts = self.specify_edge_starts()

        # these optional parameters need only be used if "no-internal-links"
        # is set to "false" while calling sumo's netconvert function
        self.internal_edgestarts = self.specify_internal_edge_starts()
        self.intersection_edgestarts = self.specify_intersection_edge_starts()

        # in case the user did not write the intersection edge-starts in
        # internal edge-starts as well (because of redundancy), merge the two
        # together
        self.internal_edgestarts += self.intersection_edgestarts
        seen = set()
        self.internal_edgestarts = \
            [item for item in self.internal_edgestarts
             if item[1] not in seen and not seen.add(item[1])]

        # total_edgestarts and total_edgestarts_dict contain all of the above
        # edges, with the former being ordered by position
        if self.net_params.no_internal_links:
            self.total_edgestarts = self.edgestarts
        else:
            self.total_edgestarts = self.edgestarts + self.internal_edgestarts
        self.total_edgestarts.sort(key=lambda tup: tup[1])

        self.total_edgestarts_dict = dict(self.total_edgestarts)

        # length of the network, or the portion of the network in which cars are
        # meant to be distributed (may be overridden by subclass __init__())
        if not hasattr(self, "length"):
            self.length = sum([self.edge_length(edge_id)
                               for edge_id in self.get_edge_list()])

        # generate starting position for vehicles in the network
        if self.initial_config.positions is None:
            self.initial_config.positions, self.initial_config.lanes = \
                self.generate_starting_positions()

        # create the sumo configuration files using the generator class
        cfg_name = self.generator.generate_cfg(self.net_params)
        self.generator.make_routes(self, self.initial_config)

        # specify the location of the sumo configuration file
        self.cfg = self.generator.cfg_path + cfg_name

    def specify_edge_starts(self):
        """
        Defines edge starts for road sections with respect to some global
        reference frame.
        MUST BE implemented in any new scenario subclass.

        Returns
        -------
        edgestarts: list
            list of edge names and starting positions,
            ex: [(edge0, pos0), (edge1, pos1), ...]
        """
        raise NotImplementedError

    def specify_intersection_edge_starts(self):
        """
        Defines edge starts for intersections with respect to some global
        reference frame. Need not be specified if no intersections exist.
        These values can be used to determine the distance of some agent from
        the nearest and/or all intersections.

        Returns
        -------
        intersection_edgestarts: list
            list of intersection names and starting positions,
            ex: [(intersection0, pos0), (intersection1, pos1), ...]
        """
        return []

    def specify_internal_edge_starts(self):
        """
        Defines the edge starts for internal edge nodes (caused by finite-length
        connections between road sections) with respect to some global reference
        frame. Does not need to be specified if "no-internal-links" is set to
        True in net_params.

        Returns
        -------
        internal_edgestarts: list
            list of internal junction names and starting positions,
            ex: [(internal0, pos0), (internal1, pos1), ...]
        """
        return []

    def get_edge(self, x):
        """
        Given an absolute position x on the track, returns the edge (name) and
        relative position on that edge.

        Parameters
        ----------
        x: float
            absolute position in network

        Returns
        -------
        edge position: tup
            1st element: edge name (such as bottom, right, etc.)
            2nd element: relative position on edge
        """
        for (edge, start_pos) in self.total_edgestarts[::-1]:
            if x >= start_pos:
                return edge, x - start_pos

    def get_x(self, edge, position):
        """
        Given an edge name and relative position, return the absolute position
        on the track.

        Parameters
        ----------
        edge: str
            name of the edge
        position: float
            relative position on the edge

        Returns
        -------
        absolute_position: float
{'fraction_non_alphanumeric': 0.07006950782840694, 'fraction_numerical': 0.002878607035034754, 'mean_word_length': 2.123684210526316, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1532377', 'n_tokens_mistral': 3637, 'n_tokens_neox': 3534, 'n_words': 1241}