Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configure doctests #574

Merged
merged 14 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,14 @@ jobs:

- name: Test docstrings
run: |
python -m pytest --doctest-modules aequilibrae/log.py aequilibrae/parameters.py aequilibrae/paths/vdf.py
python -m pytest docs/source/modeling_with_aequilibrae/project_pieces --doctest-glob=*.rst
python -m pytest --doctest-modules aequilibrae/distribution --ignore=aequilibrae/distribution/setup_ipf.py
pedrocamargo marked this conversation as resolved.
Show resolved Hide resolved
python -m pytest --doctest-modules aequilibrae/matrix
python -m pytest --doctest-modules aequilibrae/paths --ignore=aequilibrae/paths/setup_assignment.py
python -m pytest --doctest-modules aequilibrae/project
python -m pytest --doctest-modules aequilibrae/log.py aequilibrae/parameters.py
python -m pytest --doctest-modules aequilibrae/transit
python -m pytest --doctest-glob=*.rst docs/source/modeling_with_aequilibrae/project_pieces
python -m pytest --doctest-glob=*.rst docs/source/modeling_with_aequilibrae/static_traffic_assignment

- name: Build documentation
run: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,4 @@ coverage.xml

#### End snippet
.DS_Store
.vscode
36 changes: 15 additions & 21 deletions aequilibrae/distribution/gravity_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,32 @@ class GravityApplication:
"""Applies a synthetic gravity model.

Model is an instance of SyntheticGravityModel class.

Impedance is an instance of AequilibraEMatrix.

Row and Column vectors are instances of AequilibraeData.

.. code-block:: python

>>> import pandas as pd
>>> from aequilibrae import Project
>>> from aequilibrae.matrix import AequilibraeMatrix, AequilibraeData
>>> from aequilibrae.matrix import AequilibraeData
>>> from aequilibrae.distribution import SyntheticGravityModel, GravityApplication

>>> project = Project.from_path("/tmp/test_project_ga")
>>> project = create_example(project_path)

# We define the model we will use
>>> model = SyntheticGravityModel()

# Before adding a parameter to the model, you need to define the model functional form
>>> model.function = "GAMMA" # "EXPO" or "POWER"
# You can select one of GAMMA, EXPO or POWER.
>>> model.function = "GAMMA"

# Only the parameter(s) applicable to the chosen functional form will have any effect
>>> model.alpha = 0.1
>>> model.beta = 0.0001

# Or you can load the model from a file
# model.load('path/to/model/file')

# We load the impedance matrix
>>> matrix = AequilibraeMatrix()
>>> matrix.load('/tmp/test_project_ga/matrices/skims.omx')
>>> matrix.computational_view(['distance_blended'])
>>> matrix = project.matrices.get_matrix("skims")
>>> matrix.computational_view(["distance_blended"])

# We create the vectors we will use
>>> query = "SELECT zone_id, population, employment FROM zones;"
Expand All @@ -61,8 +58,11 @@ class GravityApplication:
>>> zones = df.index.shape[0]

# We create the vector database
>>> args = {"entries": zones, "field_names": ["productions", "attractions"],
... "data_types": [np.float64, np.float64], "memory_mode": True}
>>> args = {"entries": zones,
... "field_names": ["productions", "attractions"],
... "data_types": [np.float64, np.float64],
... "memory_mode": True}

>>> vectors = AequilibraeData()
>>> vectors.create_empty(**args)

Expand All @@ -81,20 +81,14 @@ class GravityApplication:
... "model": model,
... "columns": vectors,
... "column_field": "attractions",
... "output": '/tmp/test_project_ga/matrices/matrix.aem',
... "output": os.path.join(project_path, 'matrices/gravity_matrix.aem'),
... "nan_as_zero":True
... }
>>> gravity = GravityApplication(**args)

# Solve and save the outputs
>>> gravity.apply()
>>> gravity.output.export('/tmp/test_project_ga/matrices/omx_file.omx')

# To save your report into a file, you can do the following:
# with open('/tmp/test_project_ga/report.txt', 'w') as file:
# for line in gravity.report:
# file.write(f"{line}\\n")

>>> gravity.output.export(os.path.join(project_path, 'matrices/gravity_omx.omx'))
"""

def __init__(self, project=None, **kwargs):
Expand Down
32 changes: 11 additions & 21 deletions aequilibrae/distribution/gravity_calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,32 @@
class GravityCalibration:
"""Calibrate a traditional gravity model

Available deterrence function forms are: 'EXPO' or 'POWER'. 'GAMMA'
Available deterrence function forms are: 'EXPO', 'POWER' or 'GAMMA'.

.. code-block:: python

>>> from aequilibrae import Project
>>> from aequilibrae.matrix import AequilibraeMatrix
>>> from aequilibrae.distribution import GravityCalibration

>>> project = Project.from_path("/tmp/test_project_gc")
>>> project = create_example(project_path)

# We load the impedance matrix
>>> matrix = AequilibraeMatrix()
>>> matrix.load('/tmp/test_project_gc/matrices/demand.omx')
>>> matrix.computational_view(['matrix'])
# We load the demand matrix
>>> demand = project.matrices.get_matrix("demand_omx")
>>> demand.computational_view()

# We load the impedance matrix
>>> impedmatrix = AequilibraeMatrix()
>>> impedmatrix.load('/tmp/test_project_gc/matrices/skims.omx')
>>> impedmatrix.computational_view(['time_final'])
# We load the skim matrix
>>> skim = project.matrices.get_matrix("skims")
>>> skim.computational_view(["time_final"])

# Creates the problem
>>> args = {"matrix": matrix,
... "impedance": impedmatrix,
>>> args = {"matrix": demand,
... "impedance": skim,
... "row_field": "productions",
... "function": 'expo',
... "nan_as_zero": True}
>>> gravity = GravityCalibration(**args)

# Solve and save outputs
>>> gravity.calibrate()
>>> gravity.model.save('/tmp/test_project_gc/dist_expo_model.mod')

# To save the model report in a file
# with open('/tmp/test_project_gc/report.txt', 'w') as f:
# for line in gravity.report:
# f.write(f'{line}\\n')
>>> gravity.model.save(os.path.join(project_path, 'dist_expo_model.mod'))
"""

def __init__(self, project=None, **kwargs):
Expand Down
34 changes: 17 additions & 17 deletions aequilibrae/distribution/ipf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,41 @@ class Ipf:

.. code-block:: python

>>> from aequilibrae import Project
>>> from aequilibrae.distribution import Ipf
>>> from aequilibrae.matrix import AequilibraeMatrix, AequilibraeData
>>> from aequilibrae.matrix import AequilibraeData

>>> project = Project.from_path("/tmp/test_project_ipf")
>>> project = create_example(project_path)

>>> matrix = AequilibraeMatrix()

# Here we can create from OMX or load from an AequilibraE matrix.
>>> matrix.load('/tmp/test_project/matrices/demand.omx')
>>> matrix = project.matrices.get_matrix("demand_omx")
>>> matrix.computational_view()

>>> args = {"entries": matrix.zones, "field_names": ["productions", "attractions"],
... "data_types": [np.float64, np.float64], "memory_mode": True}
>>> dataset_args = {"entries": matrix.zones,
... "field_names": ["productions", "attractions"],
... "data_types": [np.float64, np.float64],
... "memory_mode": True}

>>> vectors = AequilibraeData()
>>> vectors.create_empty(**args)
>>> vectors.create_empty(**dataset_args)

>>> vectors.productions[:] = matrix.rows()[:]
>>> vectors.attractions[:] = matrix.columns()[:]

# We assume that the indices would be sorted and that they would match the matrix indices
>>> vectors.index[:] = matrix.index[:]

>>> args = {
... "matrix": matrix, "rows": vectors, "row_field": "productions", "columns": vectors,
... "column_field": "attractions", "nan_as_zero": False}

>>> fratar = Ipf(**args)
>>> ipf_args = {"matrix": matrix,
... "rows": vectors,
... "row_field": "productions",
... "columns": vectors,
... "column_field": "attractions",
... "nan_as_zero": False}

>>> fratar = Ipf(**ipf_args)
>>> fratar.fit()

# We can get back to our OMX matrix in the end
>>> fratar.output.export("/tmp/to_omx_output.omx")
>>> fratar.output.export("/tmp/to_aem_output.aem")
>>> fratar.output.export(os.path.join(my_folder_path, "to_omx_output.omx"))
>>> fratar.output.export(os.path.join(my_folder_path, "to_omx_output.aem"))
"""

def __init__(self, project=None, **kwargs):
Expand Down
4 changes: 1 addition & 3 deletions aequilibrae/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ class Log:

.. code-block:: python

>>> from aequilibrae import Project

>>> project = Project()
>>> project.new(tmp_path_empty)
>>> project.new(project_path)

>>> log = project.log()

Expand Down
72 changes: 29 additions & 43 deletions aequilibrae/matrix/aequilibrae_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,30 @@


class AequilibraeData(object):
"""AequilibraE dataset"""
"""AequilibraE dataset

.. code-block:: python

>>> from aequilibrae.matrix import AequilibraeData

>>> args = {"file_path": os.path.join(my_folder_path, "vectors.aed"),
... "entries": 3,
... "field_names": ["production"],
... "data_types": [np.float64]}

>>> vectors = AequilibraeData()
>>> vectors.create_empty(**args)

>>> vectors.production[:] = [1, 4, 7]
>>> vectors.index[:] = [1, 2, 3]

>>> vectors.export(os.path.join(my_folder_path, "vectors.csv"))

>>> reload_dataset = AequilibraeData()
>>> reload_dataset.load(os.path.join(my_folder_path, "vectors.aed"))
>>> reload_dataset.production
memmap([1., 4., 7.])
"""

def __init__(self):
self.data = None
Expand All @@ -37,8 +60,8 @@ def create_empty(
Creates a new empty dataset

:Arguments:
**file_path** (:obj:`str`, *Optional*): Full path for the output data file. If *memory_mode* is 'false' and
path is missing, then the file is created in the temp folder
**file_path** (:obj:`str`, *Optional*): Full path for the output data file. If 'memory_mode' is ``False``
and path is missing, then the file is created in the temp folder

**entries** (:obj:`int`, *Optional*): Number of records in the dataset. Default is 1

Expand All @@ -51,27 +74,6 @@ def create_empty(

**memory_mode** (:obj:`bool`, *Optional*): If ``True``, dataset will be kept in memory.
If ``False``, the dataset will be a memory-mapped numpy array

.. code-block:: python

>>> from aequilibrae.matrix import AequilibraeData, AequilibraeMatrix

>>> mat = AequilibraeMatrix()
>>> mat.load('/tmp/test_project/matrices/demand.omx')
>>> mat.computational_view()

>>> vectors = "/tmp/test_project/vectors.aed"

>>> args = {
... "file_path": vectors,
... "entries": mat.zones,
... "field_names": ["origins", "destinations"],
... "data_types": [np.float64, np.float64]
... }

>>> dataset = AequilibraeData()
>>> dataset.create_empty(**args)

"""

if file_path is not None or memory_mode:
Expand Down Expand Up @@ -145,13 +147,6 @@ def load(self, file_path):

:Arguments:
**file_path** (:obj:`str`): Full file path to the AequilibraeData to be loaded

.. code-block:: python

>>> from aequilibrae.matrix import AequilibraeData

>>> dataset = AequilibraeData()
>>> dataset.load("/tmp/test_project/vectors.aed")
"""
f = open(file_path)
self.file_path = os.path.realpath(f.name)
Expand All @@ -173,14 +168,6 @@ def export(self, file_name, table_name="aequilibrae_table"):
**file_name** (:obj:`str`): File name with PATH and extension (csv, or sqlite3, sqlite or db)

**table_name** (:obj:`str`): It only applies if you are saving to an SQLite table. Otherwise ignored

.. code-block:: python

>>> from aequilibrae.matrix import AequilibraeData

>>> dataset = AequilibraeData()
>>> dataset.load("/tmp/test_project/vectors.aed")
>>> dataset.export("/tmp/test_project/vectors.csv")
"""

file_type = os.path.splitext(file_name)[1]
Expand Down Expand Up @@ -237,9 +224,8 @@ def random_name():

>>> from aequilibrae.matrix import AequilibraeData

>>> name = AequilibraeData().random_name() # doctest: +ELLIPSIS

# This is an example of output
# '/tmp/Aequilibrae_data_5werr5f36-b123-asdf-4587-adfglkjhqwe.aed'
>>> dataset = AequilibraeData()
>>> dataset.random_name() # doctest: +ELLIPSIS
'/tmp/Aequilibrae_data_...'
"""
return os.path.join(tempfile.gettempdir(), f"Aequilibrae_data_{uuid.uuid4()}.aed")
Loading