### Set up virtual environment and install locally Source: https://tsplib95.readthedocs.io/en/stable/pages/contributing.html Create a virtual environment and install your local copy of tsplib95 in development mode. ```bash $ mkvirtualenv tsplib95 $ cd tsplib95/ $ python setup.py develop ``` -------------------------------- ### Install TSPLIB 95 using pip Source: https://tsplib95.readthedocs.io/en/stable/pages/installation.html Run this command in your terminal to install the latest stable release of TSPLIB 95. This is the recommended installation method. ```bash $ pip install tsplib95 ``` -------------------------------- ### Install TSPLIB 95 from sources Source: https://tsplib95.readthedocs.io/en/stable/pages/installation.html After cloning the repository or downloading the tarball, run this command to install TSPLIB 95 from the local source files. ```bash $ python setup.py install ``` -------------------------------- ### Trace Tours and Get Weights Source: https://tsplib95.readthedocs.io/en/stable/pages/modules.html Calculates the weights of provided tours. Each tour is a list of node indices, and the returned weights sum the edge weights including the return to the start node. ```python weights = p.trace_tours(tours) ``` -------------------------------- ### Run linters and tests Source: https://tsplib95.readthedocs.io/en/stable/pages/contributing.html Ensure your changes pass code quality checks and all tests before committing. Install flake8 and tox if you don't have them. ```bash $ flake8 tsplib95 tests $ python setup.py test or py.test $ tox ``` -------------------------------- ### Clone TSPLIB 95 repository Source: https://tsplib95.readthedocs.io/en/stable/pages/installation.html Clone the public repository from GitHub to install TSPLIB 95 from sources. ```bash $ git clone git://github.com/rhgrant10/tsplib95 ``` -------------------------------- ### Get Problem Data as Dictionary Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Returns the problem data as a dictionary. Only includes fields that are set or differ from their default values. ```python def as_dict(self, by_keyword=False): """Return the problem data as a dictionary. :param bool by_keyword: use keywords (True) or names (False) or keys :return: problem data :rtype: dict """ data = {} for name, field in self.__class__.fields_by_name.items(): value = getattr(self, name) if name in self.__dict__ or value != field.get_default_value(): key = field.keyword if by_keyword else name data[key] = value return data ``` -------------------------------- ### Example Special Function for Driving Distance Source: https://tsplib95.readthedocs.io/en/stable/pages/usage.html This example shows how to create a special function that uses a hypothetical helper to calculate driving distance between geocoordinates, converting tuple coordinates to the expected dictionary format. ```python from myapp import helpers def waypoint(coordinates): return {'lat': coordinates[0], 'lng': coordinates[1]} def driving_distance(start, end): """Special distance function for driving distance.""" waypoints = [waypoint(start), waypoint(end)] kilometers = helpers.total_distance(waypoints, method='driving') return kilometers ``` -------------------------------- ### GET /problem_properties Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Methods to check various properties of the problem instance such as symmetry, completeness, and weight types. ```APIDOC ## GET /problem_properties ### Description Check various properties of the problem instance. ### Methods - **is_explicit()**: Returns True if the problem specifies edge weights explicitly. - **is_full_matrix()**: Returns True if the problem is specified as a full matrix. - **is_weighted()**: Returns True if the problem has weighted edges. - **is_special()**: Returns True if the problem requires a special distance function. - **is_complete()**: Returns True if the problem specifies a complete graph. - **is_symmetric()**: Returns True if the problem is symmetrical. - **is_depictable()**: Returns True if the problem can be depicted. ``` -------------------------------- ### Get Problem Data by Field Keyword Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Returns the problem data as a dictionary, using field keywords as keys. This is a convenience method for `as_dict(by_keyword=True)`. ```python def as_keyword_dict(self): """Return the problem data as a dictionary by field keyword. :return: problem data :rtype: dict """ return self.as_dict(by_keyword=True) ``` -------------------------------- ### Get Problem Data by Field Name Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Returns the problem data as a dictionary, using field names as keys. This is a convenience method for `as_dict(by_keyword=False)`. ```python def as_name_dict(self): """Return the problem data as a dictionary by field name. :return: problem data :rtype: dict """ return self.as_dict(by_keyword=False) ``` -------------------------------- ### Trace Tour Weights Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Calculates the total weights for given tours, including the edge back to the start. Assumes pairwise edge calculation. ```python def trace_tours(self, tours): """Return the weights of the given tours. Each tour is a list of node indices. The weights returned are the sum of the individual weights of the edges in each tour including the final edge back to the starting node. The list of weights returned parallels the list of tours given so that ``weights[i]`` corresponds to ``tours[i]``:: weights = p.trace_tours(tours) :param list tours: one or more lists of node indices :return: one weight for each given tour :rtype: list """ solutions = [] for tour in tours: edges = utils.pairwise(tour) ``` -------------------------------- ### Run a subset of tests Source: https://tsplib95.readthedocs.io/en/stable/pages/contributing.html Execute a specific test suite to quickly verify changes. ```bash $ py.test tests.test_tsplib95 ``` -------------------------------- ### GET /get_weight Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Retrieves the weight of the edge between two specified nodes. ```APIDOC ## GET /get_weight ### Description Return the weight of the edge between start and end. This method provides a single way to obtain edge weights regardless of whether the problem uses an explicit matrix or a distance function. ### Parameters #### Query Parameters - **start** (int) - Required - starting node index - **end** (int) - Required - ending node index ### Response #### Success Response (200) - **weight** (float) - weight of the edge between start and end ``` -------------------------------- ### Deploy new version Source: https://tsplib95.readthedocs.io/en/stable/pages/contributing.html Commands for maintainers to update the version, push changes, and push tags for deployment. ```bash $ bumpversion patch # possible: major / minor / patch $ git push $ git push --tags ``` -------------------------------- ### Parse and trace tours Source: https://tsplib95.readthedocs.io/en/stable/pages/usage.html Load tour files and calculate weights using trace_tours or trace_canonical_tour. ```python >>> opt = tsplib95.load('archives/solutions/tour/gr666.opt.tour') >>> opt.type 'TOUR' >>> len(opt.tours) 1 >>> len(opt.tours[0]) 666 ``` ```python >>> problem = tsplib95.load('archives/problems/tsp/gr666.tsp') >>> >>> problem.trace_tours(opt.tours) [294358] ``` ```python >>> weight = problem.trace_canonical_tour() ``` -------------------------------- ### Get Display Data Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Retrieves the display data for a specific node index. ```APIDOC ## GET /api/nodes/{i}/display ### Description Returns the display data for the node at the specified index *i*. Returns None if the problem is not depictable. ### Method GET ### Endpoint /api/nodes/{i}/display ### Parameters #### Path Parameters - **i** (int) - Required - The index of the node. ### Response #### Success Response (200) - **display_data** (any) - The display data for the node, or None if not depictable. #### Response Example ```json { "display_data": "" } ``` ``` -------------------------------- ### Get Graph Representation Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Generates and returns a networkx graph instance representing the problem. ```APIDOC ## GET /api/graph ### Description Returns a networkx graph instance representing the problem. The graph's metadata, nodes, and edges are populated with problem-specific information. Optionally, nodes can be renamed to be sequential and zero-indexed. ### Method GET ### Endpoint /api/graph ### Parameters #### Query Parameters - **normalize** (bool) - Optional - If true, renames nodes to be zero-indexed sequential integers. ### Response #### Success Response (200) - **graph** (networkx.Graph or networkx.DiGraph) - A networkx graph object representing the problem. #### Response Example ```python import networkx as nx G = problem.get_graph() print(G.graph) print(G.nodes[1]) print(G.edges[1, 2]) ``` ``` -------------------------------- ### Retrieve a NetworkX graph from a problem Source: https://tsplib95.readthedocs.io/en/stable/pages/modules.html Demonstrates how to convert a problem instance into a NetworkX graph and access its metadata, node attributes, and edge weights. ```python >>> G = problem.get_graph() >>> G.graph {'name': None, 'comment': '14-Staedte in Burma (Zaw Win)', 'type': 'TSP', 'dimension': 14, 'capacity': None} >>> G.nodes[1] {'coord': (16.47, 96.1), 'display': None, 'demand': None, 'is_depot': False} >>> G.edges[1, 2] {'weight': 2, 'is_fixed': False} ``` -------------------------------- ### Create a new branch for development Source: https://tsplib95.readthedocs.io/en/stable/pages/contributing.html Create a new branch for your bug fixes or new features. ```bash $ git checkout -b name-of-your-bugfix-or-feature ``` -------------------------------- ### Load TSPLIB Problem from Filepath Source: https://tsplib95.readthedocs.io/en/stable/pages/usage.html Use `tsplib95.load()` to load a problem directly from a file on disk. ```python >>> import tsplib95 >>> problem = tsplib95.load('archives/problems/tsp/bay29.tsp') ``` -------------------------------- ### Get Edges Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Retrieves an iterator over the edges of the problem. Handles different data formats for edge specification. ```APIDOC ## GET /api/edges ### Description Provides a way to obtain the edges of a problem, regardless of how the problem is specified. Raises a ValueError if nodes (and therefore edges) are undefined. ### Method GET ### Endpoint /api/edges ### Parameters None ### Response #### Success Response (200) - **edges** (iter) - An iterator over the edges. #### Response Example ```json { "edges": "" } ``` ### Raises - **ValueError**: if the nodes and therefore the edges are undefined ``` -------------------------------- ### Get Nodes Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Retrieves an iterator over the nodes of the problem. Handles different data formats for node specification. ```APIDOC ## GET /api/nodes ### Description Provides a way to obtain the nodes of a problem, regardless of how the problem is specified. Raises a ValueError if nodes are undefined. ### Method GET ### Endpoint /api/nodes ### Parameters None ### Response #### Success Response (200) - **nodes** (iter) - An iterator over the nodes. #### Response Example ```json { "nodes": "" } ``` ### Raises - **ValueError**: if the nodes are undefined ``` -------------------------------- ### tsplib95.loaders.load_solution (Deprecated) Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/loaders.html Deprecated function to load a TSPLIB solution from a file. Use `tsplib95.load` instead. ```APIDOC ## load_solution(filepath) ### Description Load a solution at the given filepath. (Deprecated) ### Method N/A (Python function) ### Parameters #### Path Parameters - **filepath** (str) - Required - path to a TSPLIB solution file ### Response #### Success Response - **Solution** (:class:`~Solution`) - solution instance ### Deprecation - **Version**: 7.0.0 - **Reason**: Will be removed in newer versions. Use `tsplib95.load` instead. ``` -------------------------------- ### tsplib95.loaders.load_solution_fromstring (Deprecated) Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/loaders.html Deprecated function to load a TSPLIB solution from raw text. Use `tsplib95.parse` instead. ```APIDOC ## load_solution_fromstring(text) ### Description Load a solution from raw text. (Deprecated) ### Method N/A (Python function) ### Parameters #### Path Parameters - **text** (str) - Required - text of a TSPLIB solution ### Response #### Success Response - **Solution** (:class:`~Solution`) - solution instance ### Deprecation - **Version**: 7.0.0 - **Reason**: Will be removed in newer versions. Use `tsplib95.parse` instead. ``` -------------------------------- ### Get Edge Weight Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Retrieves the weight of the edge between two nodes, supporting both explicit matrices and distance functions. ```python def get_weight(self, start, end): """Return the weight of the edge between start and end. This method provides a single way to obtain edge weights regardless of whether the problem uses an explicit matrix or a distance function. :param int start: starting node index :param int end: ending node index :return: weight of the edge between start and end :rtype: float """ return self._wfunc(start, end) ``` -------------------------------- ### Clone the tsplib95 repository Source: https://tsplib95.readthedocs.io/en/stable/pages/contributing.html Clone your forked repository locally to begin development. ```bash $ git clone git@github.com:your_name_here/tsplib95.git ``` -------------------------------- ### Commit and push changes Source: https://tsplib95.readthedocs.io/en/stable/pages/contributing.html Stage, commit, and push your changes to your fork on GitHub. ```bash $ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature ``` -------------------------------- ### Problem.load Method Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Loads a problem instance from a specified file path. It reads the file content and then uses the `parse` method to create the Problem instance. ```APIDOC ## POST /api/problems/load ### Description Loads a problem instance from a text file. Any keyword options are passed to the class constructor. If a keyword argument has the same name as a field, it will cause an error. ### Method `load` (classmethod) ### Endpoint N/A (Class method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **filepath** (str) - The path to the problem file. - **options** (dict) - Any keyword arguments to pass to the constructor. ### Request Example ```python # Assuming 'problem.txt' contains problem data problem_instance = Problem.load('problem.txt') ``` ### Response #### Success Response (200) - **instance** (Problem) - A Problem instance loaded from the file. #### Response Example ```json { "field1": "value1", "field2": "value2" } ``` ``` -------------------------------- ### Parse and Render Tours Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/fields.html Handles parsing of tour strings into integer lists and rendering lists back into strings. ```python def parse(self, text): """Parse the text into a list of tours. :param str text: text to parse :return: tours :rtype: list """ text = text.strip() if not text: return [] match = self._end_terminals.search(text) # terminal must terminate, if required if not match and self.require_terminal: terminal = text.split()[-1] error = (f'must terminate in "{self.terminal}", ' f'not {repr(terminal)}') raise exceptions.ParsingError(error) # trim the terminal if present if match: text = text[:match.start()] # split the texts and filter out the empties texts = self._any_terminal.split(text) texts = list(filter(None, texts)) if not texts: return [] # convert the tours from texts to integer lists tours = [] for text in texts: try: tour = [int(n) for n in text.strip().split()] except ValueError as e: error = f'could not convert text to node index: {repr(e)}' raise exceptions.ParsingError(error) else: tours.append(tour) return tours ``` ```python def render(self, tours): """Render the tours as text. :param list tours: tours to render :return: rendered text :rtype: str """ if not tours: return '' tour_strings = [] for tour in tours: if tour: ``` -------------------------------- ### Retrieve nodes and edges Source: https://tsplib95.readthedocs.io/en/stable/pages/usage.html Use get_nodes() and get_edges() to reliably list problem components. ```python >>> list(problem.get_nodes()) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] >>> len(list(problem.get_edges())) # I'll spare you the full listing :P 289 >>> list(problem.get_edges())[0] (0, 0) ``` -------------------------------- ### Import TSPLIB 95 Library Source: https://tsplib95.readthedocs.io/en/stable/pages/usage.html Import the tsplib95 library to begin using its functionalities. ```python >>> import tsplib95 ``` -------------------------------- ### Get Display Data for a Node Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Retrieves display data for a given node index. Returns None if the problem is not depictable. Handles potential KeyErrors or TypeErrors when accessing display_data or node_coords. ```python def get_display(self, i): """Return the display data for node at index *i*. If the problem is not depictable, None is returned instead. :param int i: node index :return: display data for node i """ if self.is_depictable(): try: return self.display_data[i] except (KeyError, TypeError): return self.node_coords[i] else: # TODO: raise an exception instead return None ``` -------------------------------- ### Problem Class Initialization Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html The Problem class is initialized with keyword arguments, where each argument becomes an attribute of the instance. It also maintains a dictionary for default values. ```APIDOC ## Problem Class ### Description Base class for all problems. It initializes attributes from keyword arguments passed during instantiation and maintains default values. ### Method __init__ ### Parameters - **data** (dict) - name-value data passed as keyword arguments. ### Request Example ```python problem_instance = Problem(name='example', value=10) ``` ### Response #### Success Response (200) - **self** (Problem) - The initialized Problem instance. #### Response Example ```json { "name": "example", "value": 10 } ``` ``` -------------------------------- ### Get Nodes from Various Data Formats Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Retrieves nodes from different data structures like node coordinates, display data, edge lists, adjacency lists, or demands. Raises ValueError if nodes are undefined. ```python def get_nodes(self): """Return an iterator over the nodes. This method provides a single way to obtain the nodes of a problem regardless of how it is specified. However, if the nodes are not specified, the EDGE_DATA_FORMAT is not set, and DIMENSION has no value, then nodes are undefined. :return: nodes :rtype: iter :raises ValueError: if the nodes are undefined """ if self.node_coords: return iter(sorted(self.node_coords)) if self.display_data: return iter(sorted(self.display_data)) if self.edge_data_format == 'EDGE_LIST': nodes = set() for a, b in self.edge_data: nodes.update({a, b}) return iter(sorted(nodes)) if self.edge_data_format == 'ADJ_LIST': nodes = set() for a, ends in self.edge_data.items(): nodes.update({a, *ends}) return iter(sorted(nodes)) if self.demands: return iter(sorted(self.demands)) try: return iter(range(self.dimension)) except Exception: raise ValueError('undefined nodes') ``` -------------------------------- ### Format Tour Data to String Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/fields.html Converts a tour sequence into a formatted string with terminal -1 markers. ```python tour_string = ' '.join(str(i) for i in tour) tour_strings.append(f'{tour_string} -1') if tour_strings: tour_strings += ['-1'] return '\n'.join(tour_strings) ``` -------------------------------- ### Get Edges from Different Formats Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Iterates over edges based on the edge data format. For EDGE_LIST, it yields pairs directly. For ADJ_LIST, it generates pairs from the adjacency information. If neither is specified, it generates all possible pairs from the nodes. ```python def get_edges(self): """Return an iterator over the edges. This method provides a single way to obtain the edges of a problem regardless of how it is specified. If the EDGE_DATA_FORMAT is not set and the nodes are undefined, then the edges are also undefined. :return: edges :rtype: iter :raises ValueError: if the nodes and therefore the edges are undefined """ if self.edge_data_format == 'EDGE_LIST': yield from self.edge_data elif self.edge_data_format == 'ADJ_LIST': for i, adj in self.edge_data.items(): yield from ((i, j) for j in adj) else: yield from itertools.product(self.get_nodes(), self.get_nodes()) ``` -------------------------------- ### POST /trace_tours Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Calculates the total weights of the provided tours. ```APIDOC ## POST /trace_tours ### Description Return the weights of the given tours. Each tour is a list of node indices. The weights returned are the sum of the individual weights of the edges in each tour including the final edge back to the starting node. ### Parameters #### Request Body - **tours** (list) - Required - one or more lists of node indices ### Response #### Success Response (200) - **weights** (list) - one weight for each given tour ``` -------------------------------- ### Render Problem Instance to String Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Renders the problem instance into a string format suitable for TSPLIB95 files. It includes all fields that are set or differ from their default values, formatted with appropriate keywords and separators. ```python def render(self): # render each value by keyword rendered = self.as_name_dict() for name in list(rendered): value = rendered.pop(name) field = self.__class__.fields_by_name[name] if name in self.__dict__ or value != field.get_default_value(): rendered[field.keyword] = field.render(value) # build keyword-value pairs with the separator kvpairs = [] for keyword, value in rendered.items(): sep = ':\n' if '\n' in value else ': ' kvpairs.append(f'{keyword}{sep}{value}') kvpairs.append('EOF') # join and return the result return '\n'.join(kvpairs) ``` -------------------------------- ### Read Problem Instance from File-like Object Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Reads a problem instance from a file-like object. Any keyword options are passed to the class constructor. If a keyword argument has the same name as a field, it will cause an error. ```python @classmethod def read(cls, fp, **options): """Read a problem instance from a file-like object. Any keyword options are passed to the class constructor. If a keyword argument has the same name as a field then they will collide and cause an error. :param str fp: a file-like object :param options: any keyword arguments to pass to the constructor :return: problem instance :rtype: :class:`Problem` """ return cls.parse(fp.read(), **options) ``` -------------------------------- ### Handle collections with ContainerT Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/transformers.html Parses text into a collection of items based on a separator and optional terminal markers. ```python class ContainerT(Transformer): """Transformer that acts as a generic container. :param value: transformer for each item :type value: :class:`~tsplib95.transformers.Transformer` :param str sep: separator between items :param str terminal: text that marks the end :param bool terminal_required: whether the terminal is required :param int size: required number of items :param bool filter_empty: filter out empty items (zero-length/blank) """ def __init__(self, *, value=None, sep=None, terminal=None, terminal_required=True, size=None, filter_empty=True): self.child_tf = value or Transformer() self.sep = bisep.from_value(sep) self.terminal = terminal self.terminal_required = terminal_required self.size = size self.filter_empty = filter_empty def parse(self, text): """Parse the text into a container of items. :param str text: the text to parse :return: container """ # start without unpredictable whitespace text = text.strip() # if we have a terminal, make sure it's there and remove it if self.terminal: if not text.endswith(self.terminal) and self.terminal_required: raise exceptions.ParsingError(f'must end with {self.terminal}, ' # noqa: E501 f'not "{text[-len(self.terminal):]}"') # noqa: E501 text = text[:-len(self.terminal)].strip() # split the whole text into multiple texts try: texts = self.split_items(text) except Exception as e: context = 'could not split the text' raise exceptions.ParsingError.wrap(e, context) # filter out the empties, or don't; it's configurable if self.filter_empty: texts = list(filter(None, texts)) # if specified, make sure there's no terminal somwhere in the middle if self.terminal is not None: try: index = texts.index(self.terminal) except ValueError: pass # happy path else: # uh-oh, found one, so raise an exception with the extra items extra = texts[index + 1:] error = (f'found {len(extra)} extra items after terminal ' f'{repr(self.terminal)}, first is {repr(extra[0])}') raise exceptions.ParsingError(error) # parse the texts into items, catching all errors by index items = [] errors = [] for i, text in enumerate(texts): try: item = self.parse_item(text) except Exception as e: errors.append(f'item.{i}=>{repr(e)}') else: items.append(item) # join and report any errors if errors: error = utils.friendly_join(errors, limit=3) ``` -------------------------------- ### StandardProblem Class Methods Source: https://tsplib95.readthedocs.io/en/stable/pages/modules.html Methods for interacting with StandardProblem instances, including graph conversion and data retrieval. ```APIDOC ## StandardProblem Class Methods ### get_display - **Description**: Return the display data for node at index i. - **Parameters**: - **i** (int) - Required - Node index. ### get_edges - **Description**: Return an iterator over the edges. ### get_graph - **Description**: Return a networkx graph instance representing the problem. - **Parameters**: - **normalize** (bool) - Optional - Rename nodes to be zero-indexed. ### get_nodes - **Description**: Return an iterator over the nodes. ``` -------------------------------- ### Matrix Class Methods Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/matrix.html Core methods available for all matrix types in the tsplib95.matrix module. ```APIDOC ## Matrix.value_at(i, j) ### Description Get the element at row i and column j. ### Parameters #### Path Parameters - **i** (int) - Required - row - **j** (int) - Required - column ### Response - **value** (any) - value of element at (i,j) ## Matrix.is_valid_row_column(i, j) ### Description Return True if (i,j) is a row and column within the matrix. ### Parameters #### Path Parameters - **i** (int) - Required - row - **j** (int) - Required - column ### Response - **is_valid** (bool) - whether (i,j) is within the bounds of the matrix ## Matrix.get_index(i, j) ### Description Return the linear index for the element at (i,j). ### Parameters #### Path Parameters - **i** (int) - Required - row - **j** (int) - Required - column ### Response - **index** (int) - linear index for element (i,j) ``` -------------------------------- ### Export Problem as Dictionary Source: https://tsplib95.readthedocs.io/en/stable/pages/usage.html Export all problem data into a dictionary using either name-based or keyword-based keys. ```python >>> problem.as_name_dict() {'name': 'gr17', 'comment': '17-city problem (Groetschel)', 'type': 'TSP', 'dimension': 17, 'capacity': 0, 'node_coord_type': None, 'edge_weight_type': 'EXPLICIT', 'display_data_type': None, 'edge_weight_format': 'LOWER_DIAG_ROW', 'edge_data_format': None, 'node_coords': {}, 'edge_data': {}, 'edge_weights': [[0, 633, 0, 257, 390, 0, 91, 661, 228, 0, 412, 227], [169, 383, 0, 150, 488, 112, 120, 267, 0, 80, 572, 196], [77, 351, 63, 0, 134, 530, 154, 105, 309, 34, 29, 0], [259, 555, 372, 175, 338, 264, 232, 249, 0, 505, 289, 262], [476, 196, 360, 444, 402, 495, 0, 353, 282, 110, 324, 61], [208, 292, 250, 352, 154, 0, 324, 638, 437, 240, 421, 329], [297, 314, 95, 578, 435, 0, 70, 567, 191, 27, 346, 83], [47, 68, 189, 439, 287, 254, 0, 211, 466, 74, 182, 243], [105, 150, 108, 326, 336, 184, 391, 145, 0, 268, 420, 53], [239, 199, 123, 207, 165, 383, 240, 140, 448, 202, 57, 0], [246, 745, 472, 237, 528, 364, 332, 349, 202, 685, 542, 157], [289, 426, 483, 0, 121, 518, 142, 84, 297, 35, 29, 36], [236, 390, 238, 301, 55, 96, 153, 336, 0]], 'display_data': {}, 'fixed_edges': [], 'depots': [], 'demands': {}, 'tours': []} >>> problem.as_keyword_dict() {'NAME': 'gr17', 'COMMENT': '17-city problem (Groetschel)', 'TYPE': 'TSP', 'DIMENSION': 17, 'CAPACITY': 0, 'NODE_COORD_TYPE': None, 'EDGE_WEIGHT_TYPE': 'EXPLICIT', 'DISPLAY_DATA_TYPE': None, 'EDGE_WEIGHT_FORMAT': 'LOWER_DIAG_ROW', 'EDGE_DATA_FORMAT': None, 'NODE_COORD_SECTION': {}, 'EDGE_DATA_SECTION': {}, 'EDGE_WEIGHT_SECTION': [[0, 633, 0, 257, 390, 0, 91, 661, 228, 0, 412, 227], [169, 383, 0, 150, 488, 112, 120, 267, 0, 80, 572, 196], [77, 351, 63, 0, 134, 530, 154, 105, 309, 34, 29, 0], [259, 555, 372, 175, 338, 264, 232, 249, 0, 505, 289, 262], [476, 196, 360, 444, 402, 495, 0, 353, 282, 110, 324, 61], [208, 292, 250, 352, 154, 0, 324, 638, 437, 240, 421, 329], [297, 314, 95, 578, 435, 0, 70, 567, 191, 27, 346, 83], [47, 68, 189, 439, 287, 254, 0, 211, 466, 74, 182, 243], [105, 150, 108, 326, 336, 184, 391, 145, 0, 268, 420, 53], [239, 199, 123, 207, 165, 383, 240, 140, 448, 202, 57, 0], [246, 745, 472, 237, 528, 364, 332, 349, 202, 685, 542, 157], [289, 426, 483, 0, 121, 518, 142, 84, 297, 35, 29, 36], [236, 390, 238, 301, 55, 96, 153, 336, 0]], 'DISPLAY_DATA_SECTION': {}, 'FIXED_EDGES_SECTION': [], 'DEPOT_SECTION': [], 'DEMAND_SECTION': {}, 'TOUR_SECTION': []} ``` -------------------------------- ### Write TSPLIB Problem to File-like Object Source: https://tsplib95.readthedocs.io/en/stable/pages/usage.html Use the `Problem.write()` method to write the problem instance to an open file-like object. ```python >>> with open('path/to/other.name', 'w') as f: ... problem.write(f) ... ``` -------------------------------- ### Explicit Matrix Instantiation Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Instantiates the appropriate matrix class based on the edge weight format and dimensions. ```python def _create_explicit_matrix(self): # instantiate the right matrix class for the problem m = min(self.get_nodes()) Matrix = matrix.TYPES[self.edge_weight_format] weights = list(itertools.chain(*self.edge_weights)) return Matrix(weights, self.dimension, min_index=m) ``` -------------------------------- ### tsplib95.loaders.load_unknown (Deprecated) Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/loaders.html Deprecated function to load any TSPLIB file (problem or solution). Use `tsplib95.load` instead. ```APIDOC ## load_unknown(filepath) ### Description Load any TSPLIB file. This is particularly useful when you do not know in advance whether the file contains a problem or a solution. (Deprecated) ### Method N/A (Python function) ### Parameters #### Path Parameters - **filepath** (str) - Required - path to a TSPLIB problem file ### Response #### Success Response - **Instance** - either a problem or solution instance ### Deprecation - **Version**: 7.0.0 - **Reason**: Will be removed in newer versions. Use `tsplib95.load` instead. ``` -------------------------------- ### Build Transformer for Depots Fields Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/fields.html Configures a transformer for a list of depot integers terminated by -1. ```python @classmethod def build_transformer(cls): depot = T.FuncT(func=int) return T.ListT(value=depot, terminal='-1') ``` -------------------------------- ### ContainerT Transformer Methods Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/transformers.html Base methods for rendering, parsing, and packing items within a container. ```python def render(self, container): """Render the container into text. :param container: container to render :return: text """ # unpack the items from the container and render them items = self.unpack(container) rendered = list(self.render_item(i) for i in items) # if there is a terminal, append it if self.terminal: rendered.append(self.terminal) # return the rendered items joined together return self.join_items(rendered) def parse_item(self, text): """Parse the text into a single item. :param str text: the text to parse :return: container """ return self.child_tf.parse(text) def render_item(self, item): """Render the item into text. :param item: item to render :return: text """ return self.child_tf.render(item) def split_items(self, text): """Split the text into multiple items. :param str text: text to split :return: muliple items :rtype: list """ return self.sep.split(text) def join_items(self, items): """Join zero or more items into a single text. :param list items: items to join :return: joined text :rtype: str """ return self.sep.join(items) def pack(self, items): """Pack the given items into a container. :param list items: items to pack :return: container with items in it """ raise NotImplementedError() def unpack(self, container): """Unpack items from the container. :param container: container with items in it :return: items from container :rtype: list """ raise NotImplementedError() ``` -------------------------------- ### Convert to NetworkX graph Source: https://tsplib95.readthedocs.io/en/stable/pages/usage.html Transform problem data into a NetworkX graph instance for further analysis. ```python >>> G = problem.get_graph() >>> G.nodes NodeView((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) ``` ```python >>> G.graph {'name': 'gr17', 'comment': '17-city problem (Groetschel)', 'type': 'TSP', 'dimension': 17, 'capacity': 0} >>> G.nodes[0] {'coord': None, 'display': None, 'demand': None, 'is_depot': False} >>> G.edges[0, 1] {'weight': 633, 'is_fixed': False} ``` -------------------------------- ### Download TSPLIB 95 tarball Source: https://tsplib95.readthedocs.io/en/stable/pages/installation.html Download the tarball of the TSPLIB 95 source code from GitHub. ```bash $ curl -OL https://github.com/rhgrant10/tsplib95/tarball/master ``` -------------------------------- ### Write Problem Instance to File-like Object Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Writes the rendered problem instance to a file-like object. This is used by the `save` method. ```python def write(self, fp): fp.write(self.render()) ``` -------------------------------- ### Initialize Problem with Special Function Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Initializes the Problem object, optionally accepting a special distance function. ```python def __init__(self, special=None, **data): super().__init__(**data) self._wfunc = None self.special = special ``` -------------------------------- ### tsplib95.loaders.read Source: https://tsplib95.readthedocs.io/en/stable/pages/modules.html Reads a problem from a file-like object. ```APIDOC ## tsplib95.loaders.read ### Description Read a problem from a file-like object. ### Parameters #### Request Body - **f** (file) - Required - file-like object - **problem_class** (type) - Optional - special/custom problem class - **special** (callable) - Optional - special/custom distance function ### Response - **Returns** (Problem) - problem instance ``` -------------------------------- ### Read TSPLIB Problem from File-like Object Source: https://tsplib95.readthedocs.io/en/stable/pages/usage.html Use `tsplib95.read()` to load a problem from an already open file-like object. ```python >>> import tsplib95 >>> with open('archives/problems/tsp/gr17.tsp') as f: ... problem = tsplib95.read(f) ... ``` -------------------------------- ### Save Problem Instance to File Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Saves the problem instance to a file with the specified filename. This method internally uses `write` to handle the file operations. ```python def save(self, filename): with open(filename, 'w') as f: self.write(f) ``` -------------------------------- ### Problem Class Methods Source: https://tsplib95.readthedocs.io/en/stable/pages/modules.html Methods for interacting with the base Problem class, including data export and loading from various sources. ```APIDOC ## Problem Class Methods ### as_dict - **Description**: Return the problem data as a dictionary. - **Parameters**: - **by_keyword** (bool) - Optional - Use keywords (True) or names (False) or keys. ### load - **Description**: Load a problem instance from a text file. - **Parameters**: - **filepath** (str) - Required - Path to a problem file. - **options** (dict) - Optional - Keyword arguments to pass to the constructor. ### parse - **Description**: Parse text into a problem instance. - **Parameters**: - **text** (str) - Required - Problem text. - **options** (dict) - Optional - Keyword arguments to pass to the constructor. ### read - **Description**: Read a problem instance from a file-like object. - **Parameters**: - **fp** (file-like) - Required - A file-like object. - **options** (dict) - Optional - Keyword arguments to pass to the constructor. ``` -------------------------------- ### Utility Functions Source: https://tsplib95.readthedocs.io/en/stable/pages/modules.html Helper functions for rounding and coordinate parsing. ```APIDOC ## tsplib95.utils.nint ### Description Round a value to an integer. ### Parameters - **x** (float) - Required - Original value ### Response - **result** (int) - Rounded integer ## tsplib95.utils.parse_degrees ### Description Parse an encoded geocoordinate value into real degrees. ### Parameters - **coord** (float) - Required - Encoded geocoordinate value ### Response - **result** (float) - Real degrees ``` -------------------------------- ### Trace Canonical Tour Source: https://tsplib95.readthedocs.io/en/stable/_modules/tsplib95/models.html Calculates and returns the weight of the canonical tour. ```APIDOC ## GET /api/tours/canonical/weight ### Description Returns the weight of the canonical tour, which uses the nodes in their default order. This method is primarily for testing purposes. ### Method GET ### Endpoint /api/tours/canonical/weight ### Parameters None ### Response #### Success Response (200) - **weight** (float) - The weight of the canonical tour. #### Response Example ```json { "weight": 123.45 } ``` ```