Skip to content

Commit

Permalink
Cleaned up code further. In all modules. Added Migration for renaming…
Browse files Browse the repository at this point in the history
… Drive Assignment columns
  • Loading branch information
ribsthakkar committed Aug 19, 2020
1 parent 5956bf3 commit c7e725e
Show file tree
Hide file tree
Showing 38 changed files with 859 additions and 628 deletions.
50 changes: 50 additions & 0 deletions alembic/versions/02b8e7c7fbca_rename_driver_assignment_columns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Rename driver assignment columns
Revision ID: 02b8e7c7fbca
Revises: 69859f4d0367
Create Date: 2020-08-18 23:17:43.161501
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = '02b8e7c7fbca'
down_revision = '69859f4d0367'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('driver_assignment', sa.Column('trip_dropoff_addresses', postgresql.ARRAY(sa.String()), nullable=True))
op.add_column('driver_assignment', sa.Column('trip_estimated_dropoff_times', postgresql.ARRAY(sa.Interval()), nullable=True))
op.add_column('driver_assignment', sa.Column('trip_estimated_pickup_times', postgresql.ARRAY(sa.Interval()), nullable=True))
op.add_column('driver_assignment', sa.Column('trip_pickup_addresses', postgresql.ARRAY(sa.String()), nullable=True))
op.add_column('driver_assignment', sa.Column('trip_scheduled_dropoff_times', postgresql.ARRAY(sa.Interval()), nullable=True))
op.add_column('driver_assignment', sa.Column('trip_scheduled_pickup_times', postgresql.ARRAY(sa.Interval()), nullable=True))
op.drop_column('driver_assignment', 'trip_est_pu')
op.drop_column('driver_assignment', 'trip_sch_pu')
op.drop_column('driver_assignment', 'trip_do')
op.drop_column('driver_assignment', 'trip_pu')
op.drop_column('driver_assignment', 'trip_sch_do')
op.drop_column('driver_assignment', 'trip_est_do')
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('driver_assignment', sa.Column('trip_est_do', postgresql.ARRAY(postgresql.INTERVAL()), autoincrement=False, nullable=True))
op.add_column('driver_assignment', sa.Column('trip_sch_do', postgresql.ARRAY(postgresql.INTERVAL()), autoincrement=False, nullable=True))
op.add_column('driver_assignment', sa.Column('trip_pu', postgresql.ARRAY(sa.VARCHAR()), autoincrement=False, nullable=True))
op.add_column('driver_assignment', sa.Column('trip_do', postgresql.ARRAY(sa.VARCHAR()), autoincrement=False, nullable=True))
op.add_column('driver_assignment', sa.Column('trip_sch_pu', postgresql.ARRAY(postgresql.INTERVAL()), autoincrement=False, nullable=True))
op.add_column('driver_assignment', sa.Column('trip_est_pu', postgresql.ARRAY(postgresql.INTERVAL()), autoincrement=False, nullable=True))
op.drop_column('driver_assignment', 'trip_scheduled_pickup_times')
op.drop_column('driver_assignment', 'trip_scheduled_dropoff_times')
op.drop_column('driver_assignment', 'trip_pickup_addresses')
op.drop_column('driver_assignment', 'trip_estimated_pickup_times')
op.drop_column('driver_assignment', 'trip_estimated_dropoff_times')
op.drop_column('driver_assignment', 'trip_dropoff_addresses')
# ### end Alembic commands ###
2 changes: 1 addition & 1 deletion avicena/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from . import util, parsers, optimizers, models, app
from . import util, parsers, optimizers, models, app
20 changes: 10 additions & 10 deletions avicena/app/run.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
import argparse
import os
import random
from datetime import datetime
from types import ModuleType
from typing import Type, Union, Dict, List, Any
import yaml
import argparse

import yaml
from pandas import DataFrame
from sqlalchemy.orm import Session

from avicena.models.Assignment import generate_visualization_from_df, load_assignment_from_df
from avicena.util.Database import create_db_session, save_and_commit_to_db, close_db_session
from avicena.models.Driver import load_drivers_from_db, load_drivers_from_csv, prepare_drivers_for_optimizer, Driver
from avicena.models.MergeAddress import load_merge_details_from_csv, load_merge_details_from_db, MergeAddress
from avicena.models.RevenueRate import load_revenue_table_from_csv, load_revenue_table_from_db, RevenueRate
from avicena.models.Trip import load_and_filter_valid_trips_from_df, Trip
from avicena.optimizers.GeneralOptimizer import GeneralOptimizer
from avicena.parsers import LogistiCareParser, CSVParser
from avicena.util.ConfigValidation import validate_app_config
from avicena.util.Database import create_db_session, save_and_commit_to_db, close_db_session
from avicena.util.Exceptions import InvalidConfigException
from avicena.optimizers.GeneralOptimizer import GeneralOptimizer
from datetime import datetime

from avicena.util.ParserUtil import verify_and_save_parsed_trips_df_to_csv

# Supported Parser and Optimizer types that will be passed into the Config file
parsers = {'LogistiCare': LogistiCareParser, 'CSV': CSVParser}
optimizers = {'GeneralOptimizer': GeneralOptimizer}


def _run_parser(trip_parser: Union[Type[LogistiCareParser], Type[CSVParser]], trips_file: str,
def _run_parser(trip_parser: Union[Type[ModuleType]], trips_file: str,
revenue_table: Dict[str, List[RevenueRate]], merge_details: Dict[str, MergeAddress], assumed_speed: int,
model_name: str, output_directory: str) -> List[Trip]:
"""
Expand Down Expand Up @@ -68,7 +68,7 @@ def _run_optimizer(trip_optimizer: Union[Type[GeneralOptimizer]], trips: List[Tr


def _retrieve_database_inputs(db_session: Session) -> (
Dict[str, List[RevenueRate]], Dict[str, MergeAddress], List[Driver]):
Dict[str, List[RevenueRate]], Dict[str, MergeAddress], List[Driver]):
"""
Retrieve the static inputs of the model from the database
:param db_session: SQLAlchemy Database connection session
Expand All @@ -83,7 +83,7 @@ def _retrieve_database_inputs(db_session: Session) -> (


def _retrieve_csv_inputs(app_config: Dict[str, Any]) -> (
Dict[str, List[RevenueRate]], Dict[str, MergeAddress], List[Driver]):
Dict[str, List[RevenueRate]], Dict[str, MergeAddress], List[Driver]):
"""
Retrieve static inputs of the model from CSV files
:param app_config: App Configuration
Expand Down Expand Up @@ -155,7 +155,7 @@ def _retrieve_csv_inputs(app_config: Dict[str, Any]) -> (
else:
revenue_table, merge_details, drivers_table = _retrieve_csv_inputs(app_config)
trips = _run_parser(trip_parser, args.trips_file, revenue_table, merge_details, args.speed,
app_config['output_directory'])
args.name, app_config['output_directory'])
drivers = prepare_drivers_for_optimizer(drivers_table, args.driver_ids, args.date)
solution = _run_optimizer(trip_optimizer, trips, drivers, args.name, args.date, args.speed, optimizer_config,
app_config['output_directory'])
Expand Down
22 changes: 11 additions & 11 deletions avicena/models/Assignment.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import random
from typing import Dict, Any, Union, Mapping, Tuple, List
from datetime import datetime, timedelta
from typing import Dict, Any, Tuple, List

import pandas as pd
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from pandas import DataFrame, Series
from plotly.subplots import make_subplots

from datetime import datetime, timedelta
from sqlalchemy import Column, Integer, DateTime, String, Interval, Float
from sqlalchemy.dialects.postgresql import ARRAY as Array
from sqlalchemy.orm import relationship, Session
Expand Down Expand Up @@ -90,7 +89,7 @@ def generate_visualization(self, visualization_file_name: str = 'visualized.html
"""

# Prepare Table Setup
titles = self.driver_names
titles = list(self.driver_names)
titles.insert(0, "Map")
titles.insert(1, "Driver Summary: " + self.name)
subplots = [[{"type": "table"}]] * (len(self.driver_names) + 1)
Expand All @@ -114,14 +113,15 @@ def generate_visualization(self, visualization_file_name: str = 'visualized.html
for i, name in enumerate(self.driver_names):
r = lambda: random.randint(0, 255)
col = '#%02X%02X%02X' % (r(), r(), r())
print(i, name, self.driver_names, self.driver_assignments)
driver_assignment = self.driver_assignments[i]
details = [driver_assignment.trip_ids,
driver_assignment.trip_pu,
driver_assignment.trip_do,
list(map(timedelta_to_hhmmss, driver_assignment.trip_est_pu)),
list(map(timedelta_to_hhmmss, driver_assignment.trip_sch_pu)),
list(map(timedelta_to_hhmmss, driver_assignment.trip_est_do)),
list(map(timedelta_to_hhmmss, driver_assignment.trip_sch_do)),
driver_assignment.trip_pickup_addresses,
driver_assignment.trip_dropoff_addresses,
list(map(timedelta_to_hhmmss, driver_assignment.trip_estimated_pickup_times)),
list(map(timedelta_to_hhmmss, driver_assignment.trip_scheduled_pickup_times)),
list(map(timedelta_to_hhmmss, driver_assignment.trip_estimated_dropoff_times)),
list(map(timedelta_to_hhmmss, driver_assignment.trip_scheduled_dropoff_times)),
driver_assignment.trip_miles,
driver_assignment.trip_los,
driver_assignment.trip_rev]
Expand Down
1 change: 0 additions & 1 deletion avicena/models/Driver.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import datetime
import random
from typing import List, Iterable

Expand Down
4 changes: 1 addition & 3 deletions avicena/models/MergeAddress.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from datetime import timedelta
from typing import Dict

import pandas as pd

from sqlalchemy import Column, Integer, String, Interval
from datetime import timedelta

from sqlalchemy.orm import Session

from . import Base
Expand Down
2 changes: 1 addition & 1 deletion avicena/models/RevenueRate.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def calculate_revenue(self, miles: float) -> float:
:param miles: distance for which revenue is being calculated
:return: revenue made for trip with given distance
"""
if self.lower_mileage_bound <= miles <= self.upper_mileage_bound:
if not self.lower_mileage_bound <= miles <= self.upper_mileage_bound:
raise InvalidRevenueRateMileageException(
f"{miles} miles not within RevenueRate bounds [{self.lower_mileage_bound},{self.upper_mileage_bound}]")
return self.base_rate + self.revenue_per_mile * miles
Expand Down
8 changes: 1 addition & 7 deletions avicena/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,4 @@
metadata = MetaData()
Base = declarative_base(metadata=metadata)

from .Driver import Driver
from .Trip import Trip
from .Location import Location
from .LocationPair import LocationPair
from .Assignment import Assignment
from .DriverAssignment import DriverAssignment
from .RevenueRate import RevenueRate
from . import Assignment, Driver, DriverAssignment, Location, LocationPair, MergeAddress, RevenueRate, Trip
7 changes: 5 additions & 2 deletions avicena/optimizers/BaseOptimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from docplex.mp.model import Model
from pandas import DataFrame

from avicena.models import Trip, Driver
from avicena.models.Trip import Trip
from avicena.models.Driver import Driver


class BaseOptimizer:
Expand All @@ -12,7 +13,9 @@ class BaseOptimizer:
Every optimizer must extend from BaseOptimizer, ensure the initialization details are filled, and implement the
"solve" method.
"""
def __init__(self, trips: List[Trip], drivers: List[Driver], name: str, date: str, speed: int, config: Dict[str, Any]) -> None:

def __init__(self, trips: List[Trip], drivers: List[Driver], name: str, date: str, speed: int,
config: Dict[str, Any]) -> None:
"""
Initialize the Model Base Optimizer. It also sets the configuration details used by all optimizers
:param trips: List of valid Trip objects that were parsed and cleaned from the input file
Expand Down
Loading

0 comments on commit c7e725e

Please sign in to comment.