هل يمكنك اعادة كتابة كود بايثون التالي بالماتلاب مع مراعاة الفهارس في ماتلاب تبدأ ب 1  بدل 0  #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Sep 13 13:23:01 2018

@author: krupa
"""


# =============================================================================
#   INITIAL ENCODING GA
#       1. For each particle record: 
#           a. Route list [[cust1, cust20,...]....[cust7,cust80...]]
#           b Distance list [Dr1, .......Drk]
#           c distance
#           d num_routes
#       2. record fitness table : distance, num_routes, fitness function value
#
# =============================================================================
#%%

import os
import math
import multiprocessing
import numpy as np
import pandas as pd
import random
from initial_pop_generation import initial_population
from initial_routing_phase2 import initial_routing_phase2
#%%
#Paths
cwd = os.getcwd()
customer_path  = cwd +'/solomon25_csv/customers'
dataInfo_path = cwd +'/solomon25_csv/data_info'
distanceMatrix_path = cwd +'/solomon25_csv/distance_matrix'
initial_path = cwd + '/initial'

#%%

# LIST FILE NAMES
r1_list_datasets = []
c1_list_datasets = []
rc1_list_datasets = []
r2_list_datasets = []
c2_list_datasets = []
rc2_list_datasets = []


for i in range(101,110):
    c1_list_datasets.append('c'+'%s' %(i) )

for i in range(101,113):
    r1_list_datasets.append('r'+'%s' %(i) )
    
for i in range(101,109):
    rc1_list_datasets.append('rc'+'%s' %(i) )

for i in range(201,209):
    c2_list_datasets.append('c'+'%s' %(i) )
    
for i in range(201,212):
    r2_list_datasets.append('r'+'%s' %(i) )

for i in range(201,209):
    rc2_list_datasets.append('rc'+'%s' %(i) )

dataset_list = c1_list_datasets + r1_list_datasets + rc1_list_datasets + c2_list_datasets + r2_list_datasets + rc2_list_datasets

r1_list_dataInfo = []
c1_list_dataInfo = []
rc1_list_dataInfo = []
r2_list_dataInfo = []
c2_list_dataInfo = []
rc2_list_dataInfo = []

for i in range(101,110):
    c1_list_dataInfo.append('c'+'%s' %(i) + 'dataInfo.csv')

for i in range(101,113):
    r1_list_dataInfo.append('r'+'%s' %(i) + 'dataInfo.csv')
    
for i in range(101,109):
    rc1_list_dataInfo.append('rc'+'%s' %(i) + 'dataInfo.csv')

for i in range(201,209):
    c2_list_dataInfo.append('c'+'%s' %(i) + 'dataInfo.csv')
    
for i in range(201,212):
    r2_list_dataInfo.append('r'+'%s' %(i) + 'dataInfo.csv')

for i in range(201,209):
    rc2_list_dataInfo.append('rc'+'%s' %(i) + 'dataInfo.csv')

dataInfo_files_list = c1_list_dataInfo + r1_list_dataInfo + rc1_list_dataInfo + c2_list_dataInfo + r2_list_dataInfo + rc2_list_dataInfo

#customers
r1_list_customers = []
c1_list_customers = []
rc1_list_customers = []
r2_list_customers = []
c2_list_customers = []
rc2_list_customers = []

for i in range(101,110):
    c1_list_customers.append('c'+'%s' %(i) + 'customers.csv')

for i in range(101,113):
    r1_list_customers.append('r'+'%s' %(i) + 'customers.csv')
    
for i in range(101,109):
    rc1_list_customers.append('rc'+'%s' %(i) + 'customers.csv')

for i in range(201,209):
    c2_list_customers.append('c'+'%s' %(i) + 'customers.csv')
    
for i in range(201,212):
    r2_list_customers.append('r'+'%s' %(i) + 'customers.csv')

for i in range(201,209):
    rc2_list_customers.append('rc'+'%s' %(i) + 'customers.csv')

customers_files_list = c1_list_customers + r1_list_customers + rc1_list_customers + c2_list_customers + r2_list_customers + rc2_list_customers

#distance matrix
#customers
r1_list_distanceMatrix = []
c1_list_distanceMatrix = []
rc1_list_distanceMatrix = []
r2_list_distanceMatrix = []
c2_list_distanceMatrix = []
rc2_list_distanceMatrix = []

for i in range(101,110):
    c1_list_distanceMatrix.append('c'+'%s' %(i) + 'distanceMatrix.csv')

for i in range(101,113):
    r1_list_distanceMatrix.append('r'+'%s' %(i) + 'distanceMatrix.csv')
    
for i in range(101,109):
    rc1_list_distanceMatrix.append('rc'+'%s' %(i) + 'distanceMatrix.csv')

for i in range(201,209):
    c2_list_distanceMatrix.append('c'+'%s' %(i) + 'distanceMatrix.csv')
    
for i in range(201,212):
    r2_list_distanceMatrix.append('r'+'%s' %(i) + 'distanceMatrix.csv')

for i in range(201,209):
    rc2_list_distanceMatrix.append('rc'+'%s' %(i) + 'distanceMatrix.csv')

distanceMatrix_files_list = c1_list_distanceMatrix + r1_list_distanceMatrix + rc1_list_distanceMatrix + c2_list_distanceMatrix + r2_list_distanceMatrix + rc2_list_distanceMatrix


#write out files

r1_list_initialPop = []
c1_list_initialPop = []
rc1_list_initialPop = []
r2_list_initialPop = []
c2_list_initialPop = []
rc2_list_initialPop = []

for i in range(101,110):
    c1_list_initialPop.append('c'+'%s' %(i) + 'initialPop.npy')

for i in range(101,113):
    r1_list_initialPop.append('r'+'%s' %(i) + 'initialPop.npy')
    
for i in range(101,109):
    rc1_list_initialPop.append('rc'+'%s' %(i) + 'initialPop.npy')

for i in range(201,209):
    c2_list_initialPop.append('c'+'%s' %(i) + 'initialPop.npy')
    
for i in range(201,212):
    r2_list_initialPop.append('r'+'%s' %(i) + 'initialPop.npy')

for i in range(201,209):
    rc2_list_initialPop.append('rc'+'%s' %(i) + 'initialPop.npy')

initialPop_files_list = c1_list_initialPop + r1_list_initialPop + rc1_list_initialPop + c2_list_initialPop + r2_list_initialPop + rc2_list_initialPop


r1_list_initialDistance = []
c1_list_initialDistance = []
rc1_list_initialDistance = []
r2_list_initialDistance = []
c2_list_initialDistance = []
rc2_list_initialDistance = []

for i in range(101,110):
    c1_list_initialDistance.append('c'+'%s' %(i) + 'initialDistance.npy')

for i in range(101,113):
    r1_list_initialDistance.append('r'+'%s' %(i) + 'initialDistance.npy')
    
for i in range(101,109):
    rc1_list_initialDistance.append('rc'+'%s' %(i) + 'initialDistance.npy')

for i in range(201,209):
    c2_list_initialDistance.append('c'+'%s' %(i) + 'initialDistance.npy')
    
for i in range(201,212):
    r2_list_initialDistance.append('r'+'%s' %(i) + 'initialDistance.npy')

for i in range(201,209):
    rc2_list_initialDistance.append('rc'+'%s' %(i) + 'initialDistance.npy')

initialDistance_files_list = c1_list_initialDistance + r1_list_initialDistance + rc1_list_initialDistance + c2_list_initialDistance + r2_list_initialDistance + rc2_list_initialDistance


r1_list_initialResults = []
c1_list_initialResults = []
rc1_list_initialResults = []
r2_list_initialResults = []
c2_list_initialResults = []
rc2_list_initialResults = []

for i in range(101,110):
    c1_list_initialResults.append('c'+'%s' %(i) + 'initialResults.csv')

for i in range(101,113):
    r1_list_initialResults.append('r'+'%s' %(i) + 'initialResults.csv')
    
for i in range(101,109):
    rc1_list_initialResults.append('rc'+'%s' %(i) + 'initialResults.csv')

for i in range(201,209):
    c2_list_initialResults.append('c'+'%s' %(i) + 'initialResults.csv')
    
for i in range(201,212):
    r2_list_initialResults.append('r'+'%s' %(i) + 'initialResults.csv')

for i in range(201,209):
    rc2_list_initialResults.append('rc'+'%s' %(i) + 'initialResults.csv')

initialResults_files_list = c1_list_initialResults + r1_list_initialResults + rc1_list_initialResults + c2_list_initialResults + r2_list_initialResults + rc2_list_initialResults

#%%
#EXPERIMENTAL VARIABLES
num_experiments = 30
num_cores = multiprocessing.cpu_count() #number of cores to use

#GLOBAL VARIABLES:
N = 300#population size
greedy_percent = 0.10#percentage to be greedily initialised
random_percent = 0.90#percentage to be randomily initialised
alpha = 100
beta = 0.001
    
#%%
i = 0
experiment = 0
#%%
#FOR EACH DATASET
for i in range(len(dataset_list)):
    dataSet = dataset_list[i]
    #READ IN DATA PERTAINING TO THE DATASET
    customer_file = os.path.join(customer_path, customers_files_list[i])
    dataInfo_file = os.path.join(dataInfo_path, dataInfo_files_list[i])
    distanceMatrix_file = os.path.join(distanceMatrix_path, distanceMatrix_files_list[i])
    
    df_customers = pd.read_csv(customer_file)
    df_distance_matrix = pd.read_csv(distanceMatrix_file)
    df_dataInfo = pd.read_csv(dataInfo_file)
    
    num_customers = df_customers.shape[0]
    num_customers_depot = num_customers + 1
    df_customers.index = range(1,num_customers_depot)
    
    number_random_chromosomes = math.floor(N*random_percent)-1
    number_nearest_nn_chromosomes = 1
    number_greedy_chromosomes = N-number_random_chromosomes-1#int(N*greedy_percent)
    
    #CONVERT TO NUMPY ARRAY
    #distance array
    arr_distance_matrix = np.asarray(df_distance_matrix)
    #greedy radius 
    dataset_radius = (np.nanmax(arr_distance_matrix) - np.nanmin(arr_distance_matrix))/2
    #customer array
#    customer_index = 0
#    demand = 1
#    service_time = 2
#    ready_time = 3
#    due_time = 4
#    complete_time = 5
    arr_customers = np.empty((num_customers, 6))
    arr_customers[:,0] = np.arange(1, num_customers_depot) 
    arr_customers[:,1] = df_customers.loc[:,'demand']
    arr_customers[:,2] = df_customers.loc[:,'serviceTime']
    arr_customers[:,3] = df_customers.loc[:,'readyTime']
    arr_customers[:,4] = df_customers.loc[:,'dueTime']
    arr_customers[:,5] = df_customers.loc[:,'completeTime']
    
#   fleet max details
    total_time = df_dataInfo.loc[0, 'fleet_max_working_time']
    total_capacity = df_dataInfo.loc[0, 'fleet_capacity']
    
    all_customers_list = list(range(1,num_customers_depot))
    
#   FOR EACH EXPERIMENT
    for experiment in range(num_experiments):
#       READ OUT FILES
        initial_pop_output_file = os.path.join(initial_path + '/%s/experiment%d' %(dataSet,experiment), initialPop_files_list[i])
        initial_pop_distance_output_file = os.path.join(initial_path + '/%s/experiment%d' %(dataSet,experiment), initialDistance_files_list[i])
        initial_result_output_file = os.path.join(initial_path + '/%s/experiment%d' %(dataSet,experiment), initialResults_files_list[i])
        
        radius = dataset_radius*(random.uniform(0.5,1)) #assumed NOTE: NOT STATED IN PAPER
        #phase1
        pop_chromosome_routeList_array, pop_chromosome_distanceList_array, pop_num_routes, pop_total_distance = initial_population(N, num_cores, number_random_chromosomes, number_greedy_chromosomes, number_nearest_nn_chromosomes, num_customers, arr_customers, arr_distance_matrix,  total_capacity, total_time, all_customers_list, radius)
        #phase2
#        pop_chromosome_routeList_array, pop_chromosome_distanceList_array, pop_num_routes, pop_total_distance = initial_population_phase2(N, num_cores, arr_customers, arr_distance_matrix, total_capacity, total_time, pop_chromosome_routeList_array, pop_chromosome_distanceList_array, pop_num_routes, pop_total_distance, alpha, beta)
        pop_chromosome_routeList_array, pop_chromosome_distanceList_array, arr_pop_results = initial_routing_phase2(num_cores,N, alpha, beta, pop_chromosome_routeList_array, pop_chromosome_distanceList_array, arr_distance_matrix, arr_customers, total_time, total_capacity)
        
        np.save(initial_pop_output_file, pop_chromosome_routeList_array)
        np.save(initial_pop_distance_output_file, pop_chromosome_distanceList_array)
        
        df_initial_results = pd.DataFrame(np.zeros((N, 3)))
        df_initial_results.columns = ['num_vehicles', 'distance', 'fitness']
        df_initial_results.loc[:, 'num_vehicles'] = pop_num_routes
        df_initial_results.loc[:, 'distance'] = pop_total_distance
        #METRIC: GA PAPER alpha*numV + beta*distance
        df_initial_results.loc[:,'fitness'] = (alpha*pop_num_routes)+(beta*pop_total_distance)
        
        df_initial_results.to_csv(initial_result_output_file, index=False)
        
        print('experiment: ', experiment)
    print('Dataset:', dataSet)
        
    
    
    
 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Sep 14 13:32:53 2018

@author: krupa
"""
# =============================================================================
# GENERATE THE INITIAL POPULATION ROUTES USING THE 3 SCHEMES;
#   1. RANDOM
#   2. GREEDY
# =============================================================================
from initial_routing import random_neighbour, greedy_neighbour, nearest_neighbour
import concurrent.futures as cf
from itertools import chain
import numpy as np
#%%


def initial_population(N, num_cores, number_random_chromosomes, number_greedy_chromosomes, number_nearest_nn_chromosomes, num_customers, arr_customers, arr_distance_matrix,  total_capacity, total_time, all_customers_list, radius):
    with cf.ProcessPoolExecutor(num_cores) as executor:
        results_list = []
        for i in range(number_random_chromosomes):
            results_list.append(executor.submit(random_neighbour, num_customers, arr_customers, arr_distance_matrix,  total_capacity, total_time, all_customers_list))
        for j in range(number_greedy_chromosomes):
            results_list.append(executor.submit(greedy_neighbour, num_customers, arr_customers, arr_distance_matrix,  total_capacity, total_time, all_customers_list, radius))
#        results_list.append(nearest_neighbour(num_customers, arr_customers, arr_distance_matrix,  total_capacity, total_time, all_customers_list))
        
#    chromosome_route_list, chromosome_distance_list, num_routes, total_distance
    temp = list(chain.from_iterable(f.result() for f in cf.as_completed(results_list))) 
    
    pop_chromosome_routeList_array = np.empty(N, object)
    pop_chromosome_distanceList_array = np.empty(N, object)
    pop_num_routes = np.empty(N)
    pop_total_distance = np.empty(N)
    
    chromosome_route_list, chromosome_distance_list, num_routes, total_distance = nearest_neighbour(num_customers, arr_customers, arr_distance_matrix,  total_capacity, total_time, all_customers_list)
    pop_chromosome_routeList_array[0] = chromosome_route_list
    pop_chromosome_distanceList_array[0] = chromosome_distance_list
    pop_num_routes[0] = num_routes
    pop_total_distance[0] = total_distance
    
    pop_chromosome_routeList_array[1::] = temp[0::4]
    pop_chromosome_distanceList_array[1::] = temp[1::4]
    pop_num_routes[1::] = temp[2::4]
    pop_total_distance[1::] = temp[3::4]
    
    return pop_chromosome_routeList_array, pop_chromosome_distanceList_array, pop_num_routes, pop_total_distance



#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Sep 14 14:41:23 2018

@author: krupa

"""
#%%
# =============================================================================
# PHASE II ROUTING:
#   1. REMOVE LAST CUSTOMER OF R1
#   2. ADD LASTE CUSTOMER TO BE FIRST CUSTOME OF R2
#   3. IF BOTH FEASIBLE AND NEW SUM DISTANCE IS LESS OR REDUCES NUMBER OF VEHICLES THEN ACCEPT
# =============================================================================
#%%
#import copy
#import collections
from validity import route_validity
import numpy as np
from joblib import Parallel, delayed


#%%
    
def routing_phase2(alpha, beta, chromosome, chromosome_distance_list,  total_capacity, total_time, arr_distance_matrix, arr_customers):
    index_list = np.arange(0, len(chromosome)+1)
    index_list[len(chromosome)] = 0
    for i in range(len(index_list)-1):
        r1_index = index_list[i]
        r2_index = index_list[i+1]
        route_r1 = chromosome[r1_index].copy()
        route_r2 = chromosome[r2_index].copy()
        dist_r1 = chromosome_distance_list[r1_index]
        dist_r2 = chromosome_distance_list[r2_index]
        customer_r1 = route_r1[-2]
        route_r2.insert(1, customer_r1)
        route_validity_status, new_r2_dist = route_validity(route_r2, arr_distance_matrix, arr_customers, total_time, total_capacity)
        if route_validity == True:
            if len(route_r1)>3:
                new_r1_dist = dist_r1 - arr_distance_matrix[route_r1[-2],0]+ arr_distance_matrix[route_r1[-3],0]
                if (dist_r1+dist_r2)>(new_r1_dist+new_r2_dist):
                    del route_r1[-1]
                    chromosome[r1_index] = route_r1
                    chromosome[r2_index] = route_r2
                    chromosome_distance_list[r1_index] = new_r1_dist
                    chromosome_distance_list[r2_index] = new_r2_dist
            else:
                del chromosome[r1_index]
                chromosome[r2_index] = route_r2
                del chromosome_distance_list[r1_index]
                chromosome_distance_list[r2_index] = new_r2_dist
    total_distance = sum(chromosome_distance_list)
    num_vehicles = len(chromosome)
    fitness = (alpha*num_vehicles)+(beta*total_distance)
    return chromosome, chromosome_distance_list,  num_vehicles, total_distance, fitness

#%%
                
def initial_routing_phase2(num_cores,N, alpha, beta, pop_chromosome_routeList_array, pop_chromosome_distanceList_array, arr_distance_matrix, arr_customers, total_time, total_capacity):
    inputs = range(0,N)
    results_list = Parallel(num_cores)(delayed(routing_phase2)(alpha, beta, pop_chromosome_routeList_array[i], pop_chromosome_distanceList_array[i],  total_capacity, total_time, arr_distance_matrix, arr_customers ) for i in inputs)
#    chromosome, chromosome_distance_list,  num_vehicles, total_distance, fitness
    unzipped = zip(*results_list) #groups the same return for each particle and returns a list of tuples each of lenth M
    results_list = list(unzipped)
    pop_chromosome_routeList_array = np.empty(N, object)
    pop_chromosome_distanceList_array = np.empty(N, object)
    pop_chromosome_routeList_array[:] = results_list[0]
    pop_chromosome_distanceList_array[:] = results_list[1]
    arr_pop_results = np.empty((N,3), float)
    arr_pop_results[:,0] = results_list[2]
    arr_pop_results[:,1] = results_list[3]
    arr_pop_results[:,2] = results_list[4]
    return pop_chromosome_routeList_array, pop_chromosome_distanceList_array, arr_pop_results
    
    

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Sep 13 17:04:34 2018

@author: krupa
"""
from feasible_neighbours import feasible_neighbours
import random
#%%
# =============================================================================
#  INITIAL ROUTING SCHEME
#   1. Random
#   2. Greedy
#   3. Phase 2
# =============================================================================

#%%
def random_neighbour(num_customers, arr_customers, arr_distance_matrix,  total_capacity, total_time, all_customers_list):
    available_customers_list = all_customers_list.copy()

    chromosome_route_list = []
    chromosome_distance_list = []
    route_list = [0] 
    curr_capacity = 0
    curr_time = 0
    curr_customer = 0
    curr_distance = 0
    
    while len(available_customers_list)!=0:
        arr_feasible_neighbours =  feasible_neighbours(num_customers, arr_customers, arr_distance_matrix, available_customers_list, total_time, total_capacity, curr_time, curr_capacity, curr_customer)    
        if arr_feasible_neighbours.shape[0]!=0:#has neighbours, append them
            feasible_neighbours_list = arr_feasible_neighbours[:,0].tolist()
            curr_customer = int(random.choice(feasible_neighbours_list))
            curr_customer_index = feasible_neighbours_list.index(curr_customer)
            route_list.append(curr_customer)
            curr_distance += arr_feasible_neighbours[curr_customer_index, 6]
            curr_capacity = arr_feasible_neighbours[curr_customer_index, 1]
            curr_time = arr_feasible_neighbours[curr_customer_index, 10]
            available_customers_list.remove(curr_customer)
        else: #end route and initialise a new route
            route_list.append(0)
            chromosome_route_list.append(route_list)
            curr_distance += arr_distance_matrix[curr_customer,0]
            chromosome_distance_list.append(curr_distance)
            #initialise new route 
            route_list = [0] 
            curr_capacity = 0
            curr_time = 0
            curr_customer = 0
            curr_distance = 0
    #end last route        
    route_list.append(0)
    chromosome_route_list.append(route_list)
    curr_distance += arr_distance_matrix[curr_customer,0]
    chromosome_distance_list.append(curr_distance)
    
    num_routes= len(chromosome_distance_list)
    total_distance = sum(chromosome_distance_list)
    
    random_route_results = (chromosome_route_list, chromosome_distance_list, num_routes, total_distance)
    return random_route_results   


#%%
def greedy_neighbour(num_customers, arr_customers, arr_distance_matrix,  total_capacity, total_time, all_customers_list, radius):
    available_customers_list = all_customers_list.copy()

    chromosome_route_list = []
    chromosome_distance_list = []
    route_list = [0] 
    curr_capacity = 0
    curr_time = 0
    curr_customer = 0
    curr_distance = 0
    
    while len(available_customers_list)!=0:
        arr_feasible_neighbours =  feasible_neighbours(num_customers, arr_customers, arr_distance_matrix, available_customers_list, total_time, total_capacity, curr_time, curr_capacity, curr_customer)    
        if arr_feasible_neighbours.shape[0]!=0:#has neighbours, append them
            if arr_feasible_neighbours[arr_feasible_neighbours[:,6]<=radius].shape[0] !=0:
                arr_feasible_neighbours = arr_feasible_neighbours[arr_feasible_neighbours[:,6]<=radius] #reduce search space to feasible neighbours withn radius
            feasible_neighbours_list = arr_feasible_neighbours[:,0].tolist()
            curr_customer = int(random.choice(feasible_neighbours_list))
            curr_customer_index = feasible_neighbours_list.index(curr_customer)
            route_list.append(curr_customer)
            curr_distance += arr_feasible_neighbours[curr_customer_index, 6]
            curr_capacity = arr_feasible_neighbours[curr_customer_index, 1]
            curr_time = arr_feasible_neighbours[curr_customer_index, 10]
            available_customers_list.remove(curr_customer)

                
        else: #end route and initialise a new route
            route_list.append(0)
            chromosome_route_list.append(route_list)
            curr_distance += arr_distance_matrix[curr_customer,0]
            chromosome_distance_list.append(curr_distance)
            #initialise new route 
            route_list = [0] 
            curr_capacity = 0
            curr_time = 0
            curr_customer = 0
            curr_distance = 0
    #end last route        
    route_list.append(0)
    chromosome_route_list.append(route_list)
    curr_distance += arr_distance_matrix[curr_customer,0]
    chromosome_distance_list.append(curr_distance)
    
    num_routes= len(chromosome_distance_list)
    total_distance = sum(chromosome_distance_list)
    
    greedy_route_results = (chromosome_route_list, chromosome_distance_list, num_routes, total_distance)
    return greedy_route_results
#    

#%%
def nearest_neighbour(num_customers, arr_customers, arr_distance_matrix,  total_capacity, total_time, all_customers_list):
    available_customers_list = all_customers_list.copy()

    chromosome_route_list = []
    chromosome_distance_list = []
    route_list = [0] 
    curr_capacity = 0
    curr_time = 0
    curr_customer = 0
    curr_distance = 0
    
    while len(available_customers_list)!=0:
        arr_feasible_neighbours =  feasible_neighbours(num_customers, arr_customers, arr_distance_matrix, available_customers_list, total_time, total_capacity, curr_time, curr_capacity, curr_customer)    
        if arr_feasible_neighbours.shape[0]!=0:#has neighbours, append them
            #find minimum travel distance
            curr_customer_index = arr_feasible_neighbours[:,6].argmin()
            curr_customer = int(arr_feasible_neighbours[curr_customer_index,0] )
            route_list.append(curr_customer)
            curr_distance += arr_feasible_neighbours[curr_customer_index, 6]
            curr_capacity = arr_feasible_neighbours[curr_customer_index, 1]
            curr_time = arr_feasible_neighbours[curr_customer_index, 10]
            available_customers_list.remove(curr_customer)
        else: #end route and initialise a new route
            route_list.append(0)
            chromosome_route_list.append(route_list)
            curr_distance += arr_distance_matrix[curr_customer,0]
            chromosome_distance_list.append(curr_distance)
            #initialise new route 
            route_list = [0] 
            curr_capacity = 0
            curr_time = 0
            curr_customer = 0
            curr_distance = 0
    #end last route        
    route_list.append(0)
    chromosome_route_list.append(route_list)
    curr_distance += arr_distance_matrix[curr_customer,0]
    chromosome_distance_list.append(curr_distance)
    
    num_routes= len(chromosome_distance_list)
    total_distance = sum(chromosome_distance_list)

    return chromosome_route_list, chromosome_distance_list, num_routes, total_distance


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Sep 13 16:08:53 2018

@author: krupa
"""
#%%
import numpy as np

#%%
# =============================================================================
# FEASIBLE NEIGHBOURS 
#   copy array  of all customers from arr_customers
#   to arr_feasible_customers with the following columns 
#    customer_index = 0
#    demand = 1
#    service_time = 2
#    ready_time = 3
#    due_time = 4
#    complete_time = 5
#   distance_curr_next = 6
#   arrival_time = 7
#   waiting_time = 8
#   start_time = 9
#   finish_time = 10
#   return_time = 11
# =============================================================================
#%%
def feasible_neighbours(num_customers, arr_customers, arr_distance_matrix, available_customers_list, total_time, total_capacity, curr_time, curr_capacity, curr_customer):
    arr_feasible_customers = np.empty((len(available_customers_list), 12))
    available_customers_list_index = available_customers_list.copy()
    available_customers_list_index[:] = [x - 1 for x in available_customers_list_index]
    arr_feasible_customers[:,0:6] = arr_customers[available_customers_list_index, :]
    
    #curr capacity 
    arr_feasible_customers[:, 1] = arr_feasible_customers[:, 1] + curr_capacity 
    #distance_curr_next
    arr_feasible_customers[:, 6] = arr_distance_matrix[curr_customer, available_customers_list]
    #arrival_time 
    arr_feasible_customers[:, 7] = arr_feasible_customers[:, 6] + curr_time
    #waiting_time
    arr_feasible_customers[:, 8] = arr_feasible_customers[:, 3] - arr_feasible_customers[:, 7]
    arr_feasible_customers[:, 8] = arr_feasible_customers[:, 8].clip(min=0)
    #start time
    arr_feasible_customers[:, 9] = arr_feasible_customers[:, 7] + arr_feasible_customers[:, 8] #arrival + waiting
    #finish_time 
    arr_feasible_customers[:, 10] = arr_feasible_customers[:, 9] + arr_feasible_customers[:, 2] #(arrival + waiting )+ service
    #return_time 
    arr_feasible_customers[:, 11] = arr_distance_matrix[available_customers_list, 0] + arr_feasible_customers[:, 10]
    
    
    #keep only those that adhere to constraints    
    arr_feasible_customers = arr_feasible_customers[(arr_feasible_customers[:,1]<=total_capacity) & (arr_feasible_customers[:,11]<=total_time) & (arr_feasible_customers[:,9]>=arr_feasible_customers[:,3]) & (arr_feasible_customers[:,10]<=arr_feasible_customers[:,5])]
    
    return arr_feasible_customers

    
    
    
 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Sep 17 10:46:08 2018

@author: krupa
"""

#import numpy as np
#%%
# =============================================================================
#   Given a route [depot, c1, ....cn, 0]
#       check validity of the route: time, capacity constraints. 
#       want to see if the sequence of the route is valid
# =============================================================================

#%%
def route_validity(route, arr_distance_matrix, arr_customers, total_time, total_capacity):
    route_validity_status = True
    curr_dist = arr_distance_matrix[route[0], route[1]]
    curr_capacity = arr_customers[route[1]-1, 1] #demand of customer (route[1]) -1 index postion
    ready_time = arr_customers[route[1]-1, 3]
    due_time = arr_customers[route[1]-1, 4]
    curr_time = arr_distance_matrix[route[0], route[1]] 
    waiting_time = max(0, ready_time-curr_time)
    curr_time += waiting_time + arr_customers[route[1]-1, 2] #service time
    
    route_customers = route[1:-1]
    for i in range(len(route_customers)-1):
        curr_dist += arr_distance_matrix[route_customers[i], route_customers[i+1]]
        curr_time += arr_distance_matrix[route_customers[i], route_customers[i+1]]
        ready_time = arr_customers[route_customers[i+1]-1, 3]
        due_time = arr_customers[route_customers[i+1]-1, 4]
        service_time = arr_customers[route_customers[i+1]-1, 2]
        curr_capacity += arr_customers[route_customers[i+1]-1, 1]
        if curr_time<=due_time and curr_capacity<total_capacity:
            #accept
            waiting_time = max(0, ready_time - curr_time)
            if (curr_time + waiting_time>=ready_time) and (curr_time + waiting_time + service_time <= total_time):
                #accept next customer 
                curr_time += waiting_time + service_time
            else:
                #route invalid
                route_validity_status = False
                break
        else:
            #route invalid
            route_validity_status = False
            break
    
    if route_validity_status == True:
        curr_dist += arr_distance_matrix[route[-2], route[-1]]
        curr_time += arr_distance_matrix[route[-2], route[-1]]
        if curr_time>total_time:
            route_validity_status = False
            
    return route_validity_status, curr_dist