import krippendorff
import pandas as pd
import os
import numpy as np

choice_dict = {"Yes": 0, "No": 1, "Not Sure":2}
column_types = {
	"Valid": "binary",
	"Syntactic correctness": "binary",
	"Misunderstanding": "binary",
	"Factual Correctness": "three-level",
	"structural correspondence": "likert",
	"Relational similarity": "likert",
	"Familiarity": "likert",
	"Helpfulness": "likert",
	"Transferability": "likert",
	"Simplicity": "likert",
	"Domain": "string",
	"Relation Type": "string"
}

binary_list = ['Yes', 'No']
factual_list = ['Yes without switch', 'Yes with switch', 'No']
likert_list = [1, 2, 3, 4, 5]

def read_data_valid(data_folder, filename):
	df = pd.read_csv(os.path.join(data_folder, filename))
	# df = df.astype({"structural correspondence": int, "Relational similarity": int, "Familiarity":int, "Helpfulness":int, "Transferability":int, "Simplicity":int,})
	# df.fillna("None")
	# df.replace('#REF!', "None")
	data_records = df.to_dict('record')
	# print(tp_dict.keys())
	# print(tp_dict[0])
	invalid_dict = {}
	annotation_dict = {}
	invalid_analogy_set = set()
	annotation_key_set = set()
	for one_row in data_records:
		assert one_row['Valid'] in ['Yes', 'No']
		tp_key = (one_row['participant_id'], one_row['task_id'])
		annotation_dict[tp_key] = one_row
		annotation_key_set.add(tp_key)
		if one_row['Valid'] == 'No':
			invalid_analogy_set.add(tp_key)
			continue
		else:
			invalid_flag = False
			try:
				if one_row['Factual Correctness'] == 'No':
					assert int(one_row['Helpfulness']) == 1
					assert int(one_row['Transferability']) == 1
			except:
				print("Rule not followed", filename)
				print(one_row)
			for col_name in column_types:
				tp_type = column_types[col_name]
				tp_data = one_row[col_name]
				try:
					if tp_type == "binary":
						assert tp_data in binary_list
					elif tp_type == "three-level":
						assert tp_data in factual_list
					elif tp_type == "likert":
						assert int(tp_data) in likert_list
					elif tp_type == "string":
						assert len(tp_data) > 0
					else:
						raise NotImplementedError
				except:
					invalid_flag = True
					# print(col_name, tp_type, tp_data)
					if col_name not in invalid_dict:
						invalid_dict[col_name] = 0
					invalid_dict[col_name] += 1
			# if not invalid_flag:
			# annotation_dict[tp_key] = one_row
	# print("For file {}, we find {} invalid rows, and other invalid case: {}".format(filename, len(invalid_analogy_set), invalid_dict))
	# print("For file {}, we have {} keys in annotation_dict".format(filename, len(annotation_dict)))
	return annotation_dict, annotation_key_set, invalid_analogy_set, invalid_dict

def calc_krippendorff_alpha(annotation_list, used_keys, col_name):
	tp_type = column_types[col_name]
	if tp_type == "likert":
		data_length = len(likert_list)
	elif tp_type == "binary":
		data_length = len(binary_list)
	elif tp_type == "three-level":
		data_length = len(factual_list)
	else:
		raise NotImplementedError
	value_counts = []
	number_value_used = 0
	for tp_key in used_keys:
		cur_val_ct = [0] * data_length
		for annotation_dict in annotation_list:
			try:
				assert tp_key in annotation_dict
			except:
				print(tp_key, annotation_dict.keys())
				exit(-1)
			tp_data = annotation_dict[tp_key][col_name]
			if tp_type == "likert":
				tp_data_index = likert_list.index(int(tp_data))
			elif tp_type == "binary":
				tp_data_index = binary_list.index(tp_data)
			elif tp_type == "three-level":
				tp_data_index = factual_list.index(tp_data)
			else:
				raise NotImplementedError
			cur_val_ct[tp_data_index] += 1
			number_value_used += 1
		value_counts.append(cur_val_ct)
	value_counts = np.array(value_counts)
	# print("Shape of value_counts: {}, {} values used in total".format(value_counts.shape, number_value_used))
	# print(value_counts)
	print('alpha for {} is: {:.2f}'.format(col_name, krippendorff.alpha(value_counts=value_counts,level_of_measurement='nominal') ))

def calc_krippendorff_alpha_special(annotation_list, used_keys, col_name):
	tp_type = column_types[col_name]
	new_likert_list = [1, 2, 3]
	if tp_type == "likert":
		data_length = len(new_likert_list)
	elif tp_type == "binary":
		data_length = len(binary_list)
	elif tp_type == "three-level":
		data_length = len(factual_list)
	else:
		raise NotImplementedError
	value_counts = []
	number_value_used = 0
	for tp_key in used_keys:
		cur_val_ct = [0] * data_length
		for annotation_dict in annotation_list:
			try:
				assert tp_key in annotation_dict
			except:
				print(tp_key, annotation_dict.keys())
				exit(-1)
			tp_data = annotation_dict[tp_key][col_name]
			if tp_type == "likert":
				original_value = int(tp_data)
				transformed_value = 0
				if original_value <= 2:
					transformed_value = 1
				elif original_value == 3:
					transformed_value = 2
				else:
					transformed_value = 3
				tp_data_index = new_likert_list.index(transformed_value)
			elif tp_type == "binary":
				tp_data_index = binary_list.index(tp_data)
			elif tp_type == "three-level":
				tp_data_index = factual_list.index(tp_data)
			else:
				raise NotImplementedError
			cur_val_ct[tp_data_index] += 1
			number_value_used += 1
		value_counts.append(cur_val_ct)
	value_counts = np.array(value_counts)
	# print("Shape of value_counts: {}, {} values used in total".format(value_counts.shape, number_value_used))
	# print(value_counts)
	print('alpha for {} is: {:.2f}'.format(col_name, krippendorff.alpha(value_counts=value_counts,level_of_measurement='nominal') ))

def find_disagreement(annotation_list, used_keys):
	value_counts = []
	for tp_key in used_keys:
		print(tp_key, annotation_list[0][tp_key]["Factual Correctness"])
		for col_name in ["Syntactic correctness", "Factual Correctness", "Misunderstanding"]:
			tp_str = col_name
			for annotation_dict in annotation_list:
				tp_data = annotation_dict[tp_key][col_name]
				tp_str += "& " + tp_data
			tp_str += "&" + tp_data
			print(col_name, tp_str)
		for col_name in ["structural correspondence", "Relational similarity", "Familiarity", "Helpfulness", "Transferability", "Simplicity"]:
			# print(col_name)
			tp_str = col_name
			cur_val_ct = [0] * 5
			for annotation_dict in annotation_list:
				try:
					assert tp_key in annotation_dict
				except:
					print(tp_key, annotation_dict.keys())
					exit(-1)
				tp_data = annotation_dict[tp_key][col_name]
				tp_data_index = likert_list.index(int(tp_data))
				tp_str += "&" + str(int(tp_data))
				cur_val_ct[tp_data_index] += 1
			# print(col_name, cur_val_ct)
			print(col_name, tp_str)
		print("-" * 17)

def calc_common_coverage():
	data_folder = "../data/"
	filenames = ["Analogy_evaluation_expert - E1.csv", "Analogy_evaluation_expert - E2.csv", "Analogy_evaluation_expert - E3.csv", "Analogy_evaluation_expert - E4.csv", "Analogy_evaluation_expert - E5.csv"]
	user_data_dict = {}
	for filename in filenames:
		user_data_dict[filename] = {}
		# annotation_dict, annotation_key_set, invalid_analogy_set = read_data_valid(data_folder, filename)
		user_data_dict[filename] = read_data_valid(data_folder, filename)
	common_keys = user_data_dict[filenames[0]][1]
	for i in range(1, 5):
		common_keys = common_keys & user_data_dict[filenames[i]][1]
	print("There are {} rows overlap by each annotator".format(len(common_keys)))
	# for i in range(5):
	# 	if len(user_data_dict[filenames[i]][3]) > 0:
	# 		invalid_keys = user_data_dict[filenames[i]][3].keys()
	# 		print("Invlaid annotation: {} - {}".format(filenames[i], invalid_keys))
	invalid_ct = {}
	for filename in filenames:
		invalid_analogy_set = user_data_dict[filename][2]
		number_invalid = len(common_keys & invalid_analogy_set)
		for ckey_ in common_keys & invalid_analogy_set:
			if ckey_ not in invalid_ct:
				invalid_ct[ckey_] = []
			invalid_ct[ckey_].append(filename.split(" ")[2])
		# print("Among {} overlap case, {} think {} are invalid analogy".format(len(common_keys), filename.split(" ")[2], number_invalid ))
	annotation_list = [user_data_dict[filename][0] for filename in filenames]
	used_keys = common_keys - set(invalid_ct.keys())
	# calculate the agreement on valid with 29 overlap
	print('-' * 17)
	print("Calculate krippendorff_alpha for Valid, Based on 29 overlap rows")
	calc_krippendorff_alpha(annotation_list, common_keys, col_name= "Valid")
	print('-' * 17)

	print("Calculate krippendorff_alpha for other dimensions, Based on 22 valid rows, 5 annotators")
	# calculate the agreement on other dimensions with 22 valid rows
	calc_krippendorff_alpha(annotation_list, used_keys, col_name= "Syntactic correctness")
	calc_krippendorff_alpha(annotation_list, used_keys, col_name= "Factual Correctness")
	calc_krippendorff_alpha(annotation_list, used_keys, col_name= "Misunderstanding")
	# calc_krippendorff_alpha(annotation_list, used_keys, col_name= "structural correspondence")
	# calc_krippendorff_alpha(annotation_list, used_keys, col_name= "Relational similarity")
	# calc_krippendorff_alpha(annotation_list, used_keys, col_name= "Familiarity")
	# calc_krippendorff_alpha(annotation_list, used_keys, col_name= "Helpfulness")
	# print('-' * 17)

	# Garrett hasn't finished 'Transferability', 'Simplicity', 'Domain', 'Relation Type'
	# annotation_list = [user_data_dict[filename][0] for filename in filenames[1:]]
	# assert len(annotation_list) == 4
	# print("Calculate krippendorff_alpha for Transferability and Simplicity, Based on 22 valid rows, 4 annotators, Garrett will finish this part by Monday")
	# calc_krippendorff_alpha(annotation_list, used_keys, col_name= "Transferability")
	# calc_krippendorff_alpha(annotation_list, used_keys, col_name= "Simplicity")
	print('-' * 17)
	calc_krippendorff_alpha_special(annotation_list, used_keys, col_name= "structural correspondence")
	calc_krippendorff_alpha_special(annotation_list, used_keys, col_name= "Relational similarity")
	calc_krippendorff_alpha_special(annotation_list, used_keys, col_name= "Familiarity")
	calc_krippendorff_alpha_special(annotation_list, used_keys, col_name= "Helpfulness")
	calc_krippendorff_alpha_special(annotation_list, used_keys, col_name= "Transferability")
	calc_krippendorff_alpha_special(annotation_list, used_keys, col_name= "Simplicity")
	# print(used_keys)
	# find_disagreement(annotation_list, used_keys)

if __name__ == '__main__':
	calc_common_coverage()
	# calc_common_correctness()


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import os
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor as dtr
from sklearn.ensemble import RandomForestRegressor as rfr
from scipy import stats  # I might use this
from scipy.stats import norm
from ModelBuild import getModel,plotResults
from Feature_Ranking import Feature_Ranking
from sklearn.model_selection import cross_val_score
from sklearn.metrics import mean_squared_error

PATH= "DataSets/housing/"
os.environ['PATH']

#use pandas to read in csv files . The pd,read_csv() method creates a DataFram fro a csv file
train =pd.read_csv(f'{PATH}train.csv',low_memory=False)
test= pd.read_csv(f'{PATH}test.csv',low_memory=False)

#checkout  the size of the data
# print ("Train data shape:",train.shape)
# print("Test data shape:",test.shape)

# look at a few rows using the DataFrame.head() method
# train.head()
# print(train.head())

#to do some plotting
plt.style.use(style='ggplot')
# plt.rcParams['figure.figsize'] = (10, 7)

#######################################################
#  2. Explore the data and engineer Features
#######################################################
numeric_features = train.select_dtypes(include=[np.number])
QFact=numeric_features.drop(['Id'],axis=1)
# Side-by-side: skew and Kurtosis
# ==============================================================
fig=plt.figure(1,figsize=(16,8))
title=fig.suptitle("Skewness and Kurtosis in data ", fontsize=16, fontweight='bold')
fig.subplots_adjust(top=0.88,wspace=0.3)
dataSk=QFact.skew()
dataKu=QFact.kurt()
# ----------
# skew #
#----------
ax1=fig.add_subplot(1,2,1)
# ax1.set_xlabel("features")
ax1.set_ylabel("Skewness")

bars1 = ax1.bar(QFact.columns,dataSk,color='darksalmon',edgecolor='darkred', linewidth=1)
ax1.tick_params(axis='both', which='major', labelsize=8)
plt.xticks(rotation=90)
# ----------
# Kurtosis #
# ----------
ax2 = fig.add_subplot(1,2,2)
# ax2.set_xlabel("features")
ax2.set_ylabel("Kurtosis")
bars2 = ax2.bar(QFact.columns,dataKu,color='darksalmon',edgecolor='darkred', linewidth=1)
plt.xticks(rotation=90)
ax2.tick_params(axis='both', which='major', labelsize=8)
# ----------
# Save Figure #
# ----------
fig.savefig('Housing-Price-Prediction/skew_kurt.png')
plt.show()
# -------------------------------------------------------------------------------------
# Target Variable Analysis: Is it Normal?
# ---------------------------------------
# histogram and normal probability plot
sns.distplot(train["SalePrice"], fit=norm)
fig = plt.figure()
res = stats.probplot(train["SalePrice"], plot=plt)
plt.show()
# Scale target
# ----------
train["SalePrice"] = np.log(train["SalePrice"])
sns.distplot(train["SalePrice"], fit=norm)
fig = plt.figure()
res = stats.probplot(train["SalePrice"], plot=plt)
plt.show()
# -------------------------------------------------------------------------------------
# displays the correlation between the columns and examine the correlations between the features and the target.
# -------------------------------------------------------------------------------------
fig=plt.figure(5,figsize=(10,6))
corr = QFact.corr()
ax=fig.add_subplot(1,1,1)
hm = sns.heatmap(corr,
            ax=ax,           # Axes in which to draw the plot, otherwise use the currently-active Axes.
            cmap="coolwarm", # Color Map.
            #square=True,    # If True, set the Axes aspect to “equal” so each cell will be square-shaped.
            annot=False,
            fmt='.2f',       # String formatting code to use when adding annotations.
            #annot_kws={"size": 14},
            linewidths=.05)
plt.show()

#investigate the relationship between OverallQual and SalePrice.
#We set index='OverallQual' and values='SalePrice'. We chose to look at the median here.
quality_pivot = train.pivot_table(index='OverallQual', values='SalePrice', aggfunc=np.median)

#visualize this pivot table more easily, we can create a bar plot
#Notice that the median sales price strictly increases as Overall Quality increases.
# ======================================================================================
quality_pivot.plot(kind='bar', color='blue')
plt.xlabel('Overall Quality')
plt.ylabel('Median Sale Price')
plt.xticks(rotation=0)
plt.show()

#to generate some scatter plots and visualize the relationship between the Ground Living Area(GrLivArea) and SalePrice
target=train["SalePrice"]
plt.scatter(x=train['GrLivArea'], y=target)
plt.ylabel('Sale Price')
plt.xlabel('Above grade (ground) living area square feet')
plt.show()

# do the same for GarageArea.
plt.scatter(x=train['GarageArea'], y=target)
plt.ylabel('Sale Price')
plt.xlabel('Garage Area')
plt.show()
#######################################################
# create a new dataframe with some outliers removed ###
#######################################################
train = train[train['GarageArea'] < 1200]

# display the previous graph again without outliers
plt.scatter(x=train['GarageArea'], y=train['SalePrice'])
plt.xlim(-200,1600)     # This forces the same scale as before
plt.ylabel('Sale Price')
plt.xlabel('Garage Area')
plt.show()
######################################################
#   Handling Null Values                            ##
######################################################
# create a DataFrame to view the top null columns and return the counts of the null values in each column
nulls = pd.DataFrame(train.isnull().sum().sort_values(ascending=False)[:25])
nulls.columns = ['Null Count']
nulls.index.name = 'Feature'
#nulls
print(nulls)
#to return a list of the unique values
print ("Unique values are:", train.MiscFeature.unique())
######################################################
#   Wrangling the non-numeric Features              ##
######################################################
# consider the non-numeric features and display details of columns
categoricals = train.select_dtypes(exclude=[np.number])
#categoricals.describe()
print(categoricals.describe())
######################################################
#   Transforming and engineering features           ##
######################################################
# When transforming features, it's important to remember that any transformations that you've applied to the training data before
# fitting the model must be applied to the test data.

#Eg:
print ("Original: \n")
print (train.Street.value_counts(), "\n")

# our model needs numerical data, so we will use one-hot encoding to transform the data into a Boolean column.
# create a new column called enc_street. The pd.get_dummies() method will handle this for us
train['enc_street'] = pd.get_dummies(train.Street, drop_first=True)
test['enc_street'] = pd.get_dummies(test.Street, drop_first=True)

print ('Encoded: \n')
print (train.enc_street.value_counts())  # Pave and Grvl values converted into 1 and 0

# look at SaleCondition by constructing and plotting a pivot table, as we did above for OverallQual
condition_pivot = train.pivot_table(index='SaleCondition', values='SalePrice', aggfunc=np.median)
condition_pivot.plot(kind='bar', color='blue')
plt.xlabel('Sale Condition')
plt.ylabel('Median Sale Price')
plt.xticks(rotation=0)
plt.show()

# encode this SaleCondition as a new feature by using a similar method that we used for Street above
def encode(x): return 1 if x == 'Partial' else 0
train['enc_condition'] = train.SaleCondition.apply(encode)
test['enc_condition'] = test.SaleCondition.apply(encode)

# explore this newly modified feature as a plot.
condition_pivot = train.pivot_table(index='enc_condition', values='SalePrice', aggfunc=np.median)
condition_pivot.plot(kind='bar', color='blue')
plt.xlabel('Encoded Sale Condition')
plt.ylabel('Median Sale Price')
plt.xticks(rotation=0)
plt.show()
######################################################################################################
#   Dealing with missing values                                                                      #
#   We'll fill the missing values with an average value and then assign the results to data          #
#   This is a method of interpolation                                                                #
######################################################################################################
data = train.select_dtypes(include=[np.number]).interpolate().dropna()

# Check if the all of the columns have 0 null values.
# sum(data.isnull().sum() != 0)
print(sum(data.isnull().sum() != 0))

#========= Begin modelling =========================#
#    Random Forest Regression Model                        #
#===================================================#

# separate the features and the target variable for modeling.
# We will assign the features to X and the target variable(Sales Price)to y.
X = data.drop(['SalePrice', 'Id'], axis=1)
# exclude ID from features since Id is just an index with no relationship to SalePrice.

#======= partition the data ===================================================================================================#
#   Partitioning the data in this way allows us to evaluate how our model might perform on data that it has never seen before.
#   If we train the model on all of the test data, it will be difficult to tell if overfitting has taken place.
#==============================================================================================================================#
# also state how many percentage from train data set, we want to take as test data set
# In this example, about 33% of the data is devoted to the hold-out set.
X_train, X_test, y_train, y_test = train_test_split(X, data['SalePrice'], random_state=42, test_size=.33)

# fitting a decision tree regression model...
#==============================================================================================================================#
print('fitting a decision tree regression model...')
DTR_1 = dtr(max_depth=None)  # declare the regression model form. Let the depth be default.
# DTR_1.fit(X,Y) # fit the training data
scores_dtr = cross_val_score(DTR_1, X_train, y_train, cv=10, scoring="explained_variance")  # 10-fold cross validation
print("scores for k=10 fold validation:", scores_dtr)
print("Est. explained variance: %0.2f (+/- %0.2f)"% (scores_dtr.mean(), scores_dtr.std() * 2))
#==============================================================================================================================#
sorted_scores=Feature_Ranking(X_train,y_train)
estimators=[10,20, 30, 40, 50, 60, 70, 80]
# top 15...
mean_rfrs, std_rfrs_upper, std_rfrs_lower = getModel(X_train,y_train,sorted_scores, 15,estimators)
plotResults(mean_rfrs, std_rfrs_upper, std_rfrs_lower, 15,estimators)

# # top 20...
# mean_rfrs, std_rfrs_upper, std_rfrs_lower = getModel(X_train,y_train,sorted_scores, 20,estimators)
# plotResults(mean_rfrs, std_rfrs_upper, std_rfrs_lower, 20,estimators)

# # top 30...
# mean_rfrs, std_rfrs_upper, std_rfrs_lower = getModel(X_train,y_train,sorted_scores, 30,estimators)
# plotResults(mean_rfrs, std_rfrs_upper, std_rfrs_lower, 30,estimators)

# # top 40...
# mean_rfrs, std_rfrs_upper, std_rfrs_lower = getModel(X_train,y_train,sorted_scores, 40,estimators)
# plotResults(mean_rfrs, std_rfrs_upper, std_rfrs_lower, 40,estimators)

# # top 50...
# mean_rfrs, std_rfrs_upper, std_rfrs_lower = getModel(X_train,y_train,sorted_scores, 50,estimators)
# plotResults(mean_rfrs, std_rfrs_upper, std_rfrs_lower, 50,estimators)

# =================================================================================
# The Finale: Building the Output for Submission
# ==============================================
# build the model with the desired parameters...
numFeatures = 10  # the number of features to inlcude
trees = 40  # trees in the forest
included_features = np.array(sorted_scores)[:, 0][:numFeatures]
# define the training data X...
X = X_train[included_features]
yt = y_train
model = rfr(n_estimators=trees, max_depth=None)
scores_rfr = cross_val_score(model, X, yt, cv=10, scoring="explained_variance")
print("explained variance scores for k=10 fold validation:", scores_rfr)
print("Est. explained variance: %0.2f (+/- %0.2f)"% (scores_rfr.mean(), scores_rfr.std() * 2))
# fit the model
model.fit(X, yt)
# =================================================================================
# testing
# =================================================================================
# ---- Evaluate the performance and visualize results
# r-squared value is a measure of how close the data are to the fitted regression line
# a higher r-squared value means a better fit(very close to value 1)
X_t=X_test[included_features]

print("R^2 is: \n", model.score(X_t, y_test))
# use the model we have built to make predictions on the test data set.
predictions = model.predict(X_t)

# calculates the rmse
print('RMSE is: \n', mean_squared_error(y_test, predictions))

# view this relationship between predictions and actual_values graphically with a scatter plot.
actual_values = y_test
plt.scatter(predictions, actual_values, alpha=.75,color='b')  # alpha helps to show overlapping data
plt.xlabel('Predicted Price')
plt.ylabel('Actual Price')
plt.title('Random Forest Regression Model')
overlay = 'R^2 is: {}\nRMSE is: {}'.format(model.score(X_t, y_test),mean_squared_error(y_test, predictions))
plt.annotate(s=overlay,xy=(12.2,10.6),size='x-large')
plt.show()


from tkinter import*
from subprocess import call
from datetime import datetime
from time  import strftime
from tkinter import messagebox
from subprocess import call

##Authority

def main():
    root=Tk()
    root.title("Authority page")
    root.attributes('-fullscreen', True)

    fone=Frame(root,height=100,background='white').pack(fill=X)
    ftwo=Frame(root,height=1000,background='#5449F1').pack(fill=X)
    lone=Label(root,text="Authority",font=("lato",40,"bold"),foreground='#5449F1',background='white').place(relx=.5,rely=.05,anchor=CENTER)

    def account():

        call(["python","create_acc.py"])
        quit()

    def withdraw():
        call(["python","withdraw.py"])
        quit()

    def Deposite():
        call(["python","deposite.py"])
        quit()

    def withdraw_record():
        call(["python","withdraw_rec.py"])
        quit()

    def deposite_record():
        call(["python","withdraw_rec.py"])
        quit()

    def add_employee():

        call(["python","employye.py"])
        quit()

    def customer_record():
        call(["python","account_rec.py"])
        quit()

    def employee_recond():
        call(["python","emplyee_rec.py"])
        quit()

    def update_customer():
        call(["python","update_customer_info.py"])
        quit()

    def update_employee_info():
        call(["python","update_employee_info.py"])
        quit()

    def find_information():

        call(["python","search.py"])
        quit()

    create=Button(root,text="Create New Account ",width=25,bd=5,font=('times romans',15,'bold'),command=account).place(relx=.2,rely=.3)
    Withdraw=Button(root,text="Withdraw",width=25,bd=5,font=('times romans',15,'bold'),command=withdraw).place(relx=.2,rely=.4)
    deposite=Button(root,text="Deposite ",width=25,bd=5,font=('times romans',15,'bold'),command=Deposite).place(relx=.2,rely=.5)
    add_emp=Button(root,text="Add Employee",width=25,bd=5,font=('times romans',15,'bold'),command=add_employee).place(relx=.2,rely=.6)
    wdr=Button(root,text="Withdraw record",width=25,bd=5,font=('times romans',15,'bold'),command=withdraw_record).place(relx=.2,rely=.7)
    dr=Button(root,text="Deposite record",width=25,bd=5,font=('times romans',15,'bold'),command=deposite_record).place(relx=.2,rely=.8)

    cu_rec=Button(root,text="Customer record",width=25,bd=5,font=('times romans',15,'bold'),command=customer_record).place(relx=.6,rely=.3)
    record=Button(root,text="Employee record",width=25,bd=5,font=('times romans',15,'bold'),command=employee_recond).place(relx=.6,rely=.4)
    record=Button(root,text="Update customer information",width=25,bd=5,font=('times romans',15,'bold'),command=update_customer).place(relx=.6,rely=.5)
    updateinformation=Button(root,text="Update employee information",width=25,bd=5,font=('times romans',15,'bold'),command=update_employee_info).place(relx=.6,rely=.6)
    serch_information=Button(root,text="Search information",width=25,bd=5,font=('times romans',15,'bold'),command=find_information).place(relx=.6,rely=.7)
    quit=Button(root,text="Quit",width=25,bd=5,font=('times romans',15,'bold'),command=root.destroy).place(relx=.6,rely=.8)

    root.mainloop()

if __name__=="__main__":
    main()


class Solution:
    def findNumOfValidWords(self, words: List[str], puzzles: List[str]) -> List[int]:

        # words to sets
        word_set = [frozenset(word) for word in words]
        count = Counter(word_set)
        ans = []

        for p in puzzles:
            # find sub-strings with dp
            subs = [p[0]]
            for char in p[1:]:
                subs += [char + i for i in subs]
            # count occurance of these sub strings
            valids = 0
            for sub in subs:
                if frozenset(sub) in count:
                    valids += count[frozenset(sub)]
            ans.append(valids)
        return ans


def solution(new_id):
    answer = ''
    answer = phase1(new_id)

    answer = phase2(answer)

    answer = phase3(answer)

    answer = phase4(answer)
    print(answer)
    answer = phase6(answer)
    print(answer)
    answer = phase7(answer)
    print(answer)
    return answer

def phase1(new_id):
    result = ""
    for word in new_id:
        if word.isalpha():
            word = word.lower()
        result += word
    return result

def phase2(new_id):
    result = ""
    for word in new_id:
        if word.isalpha() or word.isdigit() or word == "-" or word == "_" or word == ".":
            result += word
    return result

def phase3(new_id):
    result = ""
    check = True
    for i in range(0,len(new_id)):
        #print(word)
        if new_id[i] == ".":
            if check:
                result += "."
                check = False
            else:
                i += 1
        else:
            result += new_id[i]
            check = True
    return result

def phase4(new_id):
    result = ""
    temp = ""
#     if new_id.startswith("."):
#         result = ""
#         check = False
#         for word in new_id:
#             if word == "." and check:
#                 result += word
#             elif word =="." and not check:
#                 check = False
#             else:
#                 result +=word
#                 check = True
#     if result.endswith("."):
#         check = 0
#         temp = ""
#         for i in range(len(result)-1,0,-1):
#             if new_id[i] != ".":
#                 check = i
#                 break

#         for i in range(0,check+1):
#             temp += result[i]
#         result = temp
    for word in new_id:
        if word == ".":
            temp += " "
        else:
            temp += word
    temp = temp.strip()
    for word in temp:
        if word == " ":
            result += "."
        else:
            result += word
    if result == "":
        result = "a"
    return result

def phase6(new_id):
    result = ""
    if len(new_id)>=16:
        for i in range(0,15):
            result += new_id[i]
        result = phase4(result)
    else:
        result = new_id
    return result

def phase7(new_id):
    temp = new_id
    result = ""
    if len(new_id)<=2:
        while(len(temp)<3):
            temp += new_id[len(new_id)-1]
        print(temp)
        for i in range(0,3):
            result += temp[i]
        print("result : ",result)
    else:
        result = new_id

    return result


from pathlib import Path
#Imports for streamlit
import streamlit as st
import av
import cv2
from streamlit_webrtc import (
    RTCConfiguration,
    VideoProcessorBase,
    WebRtcMode,
    webrtc_streamer,
)
from streamlit_extras.switch_page_button import switch_page
from streamlit_extras.app_logo import add_logo

#Imports for ml model
import numpy as np
import mediapipe as mp
from keras.models import load_model

st.set_page_config(
    page_title="Vibescape",
    page_icon="🎵",
)

page_bg_img = """
<style>

div.stButton > button:first-child {
    all: unset;
    width: 120px;
    height: 40px;
    font-size: 32px;
    background: transparent;
    border: none;
    position: relative;
    color: #f0f0f0;
    cursor: pointer;
    z-index: 1;
    padding: 10px 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
    user-select: none;
    -webkit-user-select: none;
    touch-action: manipulation;

}
div.stButton > button:before, div.stButton > button:after {
    content: '';
    position: absolute;
    bottom: 0;
    right: 0;
    z-index: -99999;
    transition: all .4s;
}

div.stButton > button:before {
    transform: translate(0%, 0%);
    width: 100%;
    height: 100%;
    background: #0f001a;
    border-radius: 10px;
}
div.stButton > button:after {
  transform: translate(10px, 10px);
  width: 35px;
  height: 35px;
  background: #ffffff15;
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  border-radius: 50px;
}

div.stButton > button:hover::before {
    transform: translate(5%, 20%);
    width: 110%;
    height: 110%;
}

div.stButton > button:hover::after {
    border-radius: 10px;
    transform: translate(0, 0);
    width: 100%;
    height: 100%;
}

div.stButton > button:active::after {
    transition: 0s;
    transform: translate(0, 5%);
}

[data-testid="stAppViewContainer"] {
background-image: url("https://images.unsplash.com/photo-1613327986042-63d4425a1a5d?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1470&q=80");
background-size: cover;
background-position: top left;
background-repeat: no-repeat;
background-attachment: local;
}

[data-testid="stSidebar"] > div:first-child {
background-position: center;
background-repeat: no-repeat;
background-attachment: fixed;
background : black;
}

[data-testid="stHeader"] {
background: rgba(0,0,0,0);
}

[data-testid="stToolbar"] {
right: 2rem;
}
</style>
"""
add_logo("https://github.com/NebulaTris/vibescape/blob/main/logo.png?raw=true")
st.markdown(page_bg_img, unsafe_allow_html=True)
st.title("Vibescape 🎉🎶")
st.sidebar.success("Select a page below.")
st.sidebar.text("Developed by Shambhavi")

st.markdown("**Hey there, emotion explorer! Are you ready for a wild ride through the rollercoaster of feelings?** 🎢🎵")
st.markdown("**Welcome to Vibescape, where our snazzy AI meets your wacky emotional world head-on! We've got our virtual goggles on (nope, not really, but it sounds cool** 😎 **) to analyze your emotions using a webcam. And what do we do with all those emotions, you ask? We turn them into the most toe-tapping, heartwarming, and occasionally hilarious music playlists you've ever heard!** 🕺💃")
st.markdown("**You've heard of Spotify, SoundCloud, and YouTube, right? Well, hold onto your hats because Vibescape combines these musical behemoths into one epic entertainment extravaganza! Now you can dive into your favorite streaming services with a twist — they'll be serving up songs based on your mood!** 🎶")
st.markdown("**Feeling like a happy-go-lucky panda today? We've got a playlist for that! Or perhaps you've got the moody blues? No worries, Vibescape has your back. Our AI wizardry detects your vibes and serves up the tunes that match your moment.** 🐼🎉")
st.markdown("**So, get ready for a whirlwind of emotions and music. Vibescape is here to turn your webcam into a mood ring, your screen into a dance floor, and your heart into a DJ booth. What's next? Well, that's entirely up to you and your ever-changing feelings!**")
st.markdown("**So, strap in** 🚀 **, hit that webcam** 📷 **, and let the musical journey begin! Vibescape is your ticket to a rollercoaster of emotions, all set to your favorite tunes.** 🎢🎵")

RTC_CONFIGURATION = RTCConfiguration(
    {"iceServers": [{
        "urls": ["stun:stun.l.google.com:19302"]
    }]})

# CWD path
HERE = Path(__file__).parent

model = load_model("model.h5")
label = np.load("label.npy")

holistic = mp.solutions.holistic
hands = mp.solutions.hands
holis = holistic.Holistic()
drawing = mp.solutions.drawing_utils

if "run" not in st.session_state:
    st.session_state["run"] = ""

run = np.load("emotion.npy")[0]

try:
    emotion = np.load("emotion.npy")[0]
except:
    emotion = ""

class EmotionProcessor(VideoProcessorBase):
    def recv(self, frame: av.VideoFrame) -> av.VideoFrame:
        frm = frame.to_ndarray(format="bgr24")
        frm = cv2.flip(frm, 1)
        res = holis.process(cv2.cvtColor(frm, cv2.COLOR_BGR2RGB))

        lst = []
        if res.face_landmarks:
            for i in res.face_landmarks.landmark:
                lst.append(i.x - res.face_landmarks.landmark[1].x)
                lst.append(i.y - res.face_landmarks.landmark[1].y)

            if res.left_hand_landmarks:
                for i in res.left_hand_landmarks.landmark:
                    lst.append(i.x - res.left_hand_landmarks.landmark[8].x)
                    lst.append(i.y - res.left_hand_landmarks.landmark[8].y)
            else:
                for i in range(42):
                    lst.append(0.0)

            if res.right_hand_landmarks:
                for i in res.right_hand_landmarks.landmark:
                    lst.append(i.x - res.right_hand_landmarks.landmark[8].x)
                    lst.append(i.y - res.right_hand_landmarks.landmark[8].y)
            else:
                for i in range(42):
                    lst.append(0.0)

            lst = np.array(lst).reshape(1, -1)

            pred = label[np.argmax(model.predict(lst))]
            print(pred)
            cv2.putText(frm, pred, (50,50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)

            np.save("emotion.npy",np.array([pred]))

            emotion = pred

        drawing.draw_landmarks(frm, res.face_landmarks, holistic.FACEMESH_CONTOURS)
        drawing.draw_landmarks(frm, res.left_hand_landmarks, hands.HAND_CONNECTIONS)
        drawing.draw_landmarks(frm, res.right_hand_landmarks, hands.HAND_CONNECTIONS)

        return av.VideoFrame.from_ndarray(frm, format="bgr24")

if st.session_state["run"] != "false":
    webrtc_streamer(key="key", desired_playing_state=True ,mode=WebRtcMode.SENDRECV,  rtc_configuration=RTC_CONFIGURATION, video_processor_factory=EmotionProcessor, media_stream_constraints={
            "video": True,
            "audio": False
        },
        async_processing=True)
btn = st.button("Check your emotion")

if btn:
    if not(emotion):
        st.warning("Please wait for the emotion to be detected")

    else:
        np.save("emotion.npy",np.array([""]))
        st.session_state["run"] = run
        st.write("Your current emotion is: " ,emotion)
        st.subheader("Choose your streaming service")

col1, col2, col3 = st.columns(3)

with col2:
    btn = st.button("Spotify")
    if btn:
        switch_page("Spotify")

with col3:
    btn2 = st.button("Youtube")
    if btn2:
        switch_page("Youtube")

with col1:
    btn3 = st.button("Soundcloud")
    if btn3:
        switch_page("Soundcloud")


#!/usr/bin/python3
def safe_print_integer(value):
    """ Function Prints an integer with "{:d}".format().
    Args:
        value (int): The integer being printed.
    Returns:
        False if  a TypeError or ValueError occurs
        Otherwise return True.
    """
    try:
        print("{:d}".format(value))
        return (True)
    except (TypeError, ValueError):
        return (False)


#!/usr/bin/env python
"""
Modelica parse Tree to AST tree.
"""
from __future__ import print_function, absolute_import, division, unicode_literals

import os
import glob
import unittest
import itertools

import casadi as ca
import numpy as np

import pymoca.backends.casadi.generator as gen_casadi
from pymoca.backends.casadi.alias_relation import AliasRelation
from pymoca.backends.casadi.model import CASADI_ATTRIBUTES, Model, Variable, DelayArgument
from pymoca.backends.casadi.api import transfer_model, CachedModel
from pymoca import parser, ast

MODEL_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'models')

# noinspection PyPep8Naming,PyUnresolvedReferences
class GenCasadiTest(unittest.TestCase):
    def assert_model_equivalent(self, A, B):
        def sstr(a): return set([str(e) for e in a])

        for l in ["states", "der_states", "inputs", "outputs", "constants", "parameters"]:
            self.assertEqual(sstr(getattr(A, l)), sstr(getattr(B, l)))

    def assert_model_equivalent_numeric(self, A, B, tol=1e-9):
        self.assertEqual(len(A.states), len(B.states))
        self.assertEqual(len(A.der_states), len(B.der_states))
        self.assertEqual(len(A.alg_states), len(B.alg_states))
        self.assertEqual(len(A.inputs), len(B.inputs))
        self.assertEqual(len(A.outputs), len(B.outputs))
        self.assertEqual(len(A.constants), len(B.constants))
        self.assertEqual(len(A.parameters), len(B.parameters))
        self.assertEqual(len(A.delay_states), len(B.delay_states))

        if not isinstance(A, CachedModel) and not isinstance(B, CachedModel):
            self.assertEqual(len(A.equations), len(B.equations))
            self.assertEqual(len(A.initial_equations), len(B.initial_equations))
            self.assertEqual(len(A.delay_arguments), len(B.delay_arguments))

        for f_name in ['dae_residual', 'initial_residual', 'variable_metadata', 'delay_arguments']:
            this = getattr(A, f_name + '_function')
            that = getattr(B, f_name + '_function')

            np.random.seed(0)

            args_in = []
            for i in range(this.n_in()):
                sp = this.sparsity_in(i)
                r = ca.DM(sp, np.random.random(sp.nnz()))
                args_in.append(r)

            this_out = this.call(args_in)
            that_out = that.call(args_in)

            # N.B. Here we require that the order of the equations in the two models is identical.
            for i, (a, b) in enumerate(zip(this_out, that_out)):
                for j in range(a.size1()):
                    for k in range(a.size2()):
                        if a[j, k].is_regular() or b[j, k].is_regular():
                            test = float(ca.norm_2(ca.vec(a[j, k] - b[j, k]))) <= tol
                            if not test:
                                print(j)
                                print(k)
                                print(a[j,k])
                                print(b[j,k])
                                print(f_name)
                            self.assertTrue(test)

        return True

    def test_spring(self):
        with open(os.path.join(MODEL_DIR, 'Spring.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'Spring')
        ref_model = Model()
        print(casadi_model)
        x = ca.MX.sym("x")
        v_x = ca.MX.sym("v_x")
        der_x = ca.MX.sym("der(x)")
        der_v_x = ca.MX.sym("der(v_x)")
        k = ca.MX.sym("k")
        c = ca.MX.sym("c")
        ref_model.states = list(map(Variable, [x, v_x]))
        ref_model.der_states = list(map(Variable, [der_x, der_v_x]))
        ref_model.parameters = list(map(Variable, [c, k]))
        ref_model.parameters[0].value = 0.1
        ref_model.parameters[1].value = 2
        ref_model.equations = [der_x - v_x, der_v_x - (-k * x - c * v_x)]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_estimator(self):
        with open(os.path.join(MODEL_DIR, 'Estimator.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'Estimator')
        ref_model = Model()
        print(casadi_model)

        x = ca.MX.sym("x")
        der_x = ca.MX.sym("der(x)")
        y = ca.MX.sym("y")

        ref_model.states = list(map(Variable, [x]))
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [y]))
        ref_model.outputs = list(map(Variable, [y]))
        ref_model.equations = [der_x + x, y - x]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_aircraft(self):
        with open(os.path.join(MODEL_DIR, 'Aircraft.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        # noinspection PyUnusedLocal
        casadi_model = gen_casadi.generate(ast_tree, 'Aircraft')
        # noinspection PyUnusedLocal
        ref_model = Model()
        self.assertTrue(True)

    def test_connector_hq(self):
        with open(os.path.join(MODEL_DIR, 'ConnectorHQ.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'System')
        ref_model = Model()
        print(casadi_model)

        a__up__H = ca.MX.sym("a.up.H")
        a__up__Q = ca.MX.sym("a.up.Q")
        a__down__H = ca.MX.sym("a.down.H")
        a__down__Q = ca.MX.sym("a.down.Q")

        b__up__H = ca.MX.sym("b.up.H")
        b__up__Q = ca.MX.sym("b.up.Q")
        b__down__H = ca.MX.sym("b.down.H")
        b__down__Q = ca.MX.sym("b.down.Q")

        c__up__H = ca.MX.sym("c.up.H")
        c__up__Q = ca.MX.sym("c.up.Q")
        c__down__H = ca.MX.sym("c.down.H")
        c__down__Q = ca.MX.sym("c.down.Q")

        qa__down__H = ca.MX.sym("qa.down.H")
        qa__down__Q = ca.MX.sym("qa.down.Q")

        p__H = ca.MX.sym("p.H")
        p__Q = ca.MX.sym("p.Q")

        hb__up__H = ca.MX.sym("hb.up.H")
        hb__up__Q = ca.MX.sym("hb.up.Q")

        zerotest__H = ca.MX.sym("zerotest.H")
        zerotest__Q = ca.MX.sym("zerotest.Q")

        ref_model.alg_states = list(map(Variable, [
            a__up__H, a__down__H, b__up__H, b__down__H, c__up__H, c__down__H,
            qa__down__H, p__H, hb__up__H, zerotest__H,
            a__up__Q, a__down__Q, b__up__Q, b__down__Q, c__up__Q, c__down__Q,
            qa__down__Q, p__Q, hb__up__Q, zerotest__Q]))
        ref_model.equations = [a__up__H - a__down__H,
                               b__up__H - b__down__H,
                               c__up__H - c__down__H,
                               qa__down__Q,
                               hb__up__H,
                               p__Q,
                               qa__down__H - a__up__H,
                               p__H - c__up__H,
                               a__down__H - b__up__H,
                               c__down__H - b__up__H,
                               b__down__H - hb__up__H,
                               a__up__Q + a__down__Q,
                               b__up__Q + b__down__Q,
                               c__up__Q + c__down__Q,
                               qa__down__Q + a__up__Q,
                               -p__Q + c__up__Q,
                               a__down__Q + (b__up__Q + c__down__Q),
                               b__down__Q + hb__up__Q,
                               zerotest__Q]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_connector_hqz(self):
        with open(os.path.join(MODEL_DIR, 'ConnectorHQZ.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'SystemZ')
        ref_model = Model()
        print(casadi_model)

        a__up__H = ca.MX.sym("a.up.H")
        a__up__Q = ca.MX.sym("a.up.Q")
        a__up__Z = ca.MX.sym("a.up.Z")
        a__down__H = ca.MX.sym("a.down.H")
        a__down__Q = ca.MX.sym("a.down.Q")
        a__down__Z = ca.MX.sym("a.down.Z")

        b__up__H = ca.MX.sym("b.up.H")
        b__up__Q = ca.MX.sym("b.up.Q")
        b__up__Z = ca.MX.sym("b.up.Z")
        b__down__H = ca.MX.sym("b.down.H")
        b__down__Q = ca.MX.sym("b.down.Q")
        b__down__Z = ca.MX.sym("b.down.Z")

        c__up__H = ca.MX.sym("c.up.H")
        c__up__Q = ca.MX.sym("c.up.Q")
        c__up__Z = ca.MX.sym("c.up.Z")
        c__down__H = ca.MX.sym("c.down.H")
        c__down__Q = ca.MX.sym("c.down.Q")
        c__down__Z = ca.MX.sym("c.down.Z")

        d__up__H = ca.MX.sym("d.up.H")
        d__up__Q = ca.MX.sym("d.up.Q")
        d__down__H = ca.MX.sym("d.down.H")
        d__down__Q = ca.MX.sym("d.down.Q")
        d__down__Z = ca.MX.sym("d.down.Z")

        qa__down__H = ca.MX.sym("qa.down.H")
        qa__down__Q = ca.MX.sym("qa.down.Q")
        qa__down__Z = ca.MX.sym("qa.down.Z")
        qc__down__H = ca.MX.sym("qc.down.H")
        qc__down__Q = ca.MX.sym("qc.down.Q")
        qc__down__Z = ca.MX.sym("qc.down.Z")

        hb__up__H = ca.MX.sym("hb.up.H")
        hb__up__Q = ca.MX.sym("hb.up.Q")
        hb__up__Z = ca.MX.sym("hb.up.Z")

        ref_model.alg_states = list(map(Variable, [
            a__up__H, a__down__H, b__up__H, b__down__H,
            c__up__H, c__down__H, d__up__H, d__down__H,
            qa__down__H, qc__down__H, hb__up__H,
            a__up__Q, a__down__Q, b__up__Q, b__down__Q,
            c__up__Q, c__down__Q, d__up__Q, d__down__Q,
            qa__down__Q, qc__down__Q, hb__up__Q,
            a__up__Z, a__down__Z, b__up__Z, b__down__Z,
            c__up__Z, c__down__Z, d__down__Z,
            qa__down__Z, qc__down__Z, hb__up__Z]))

        ref_model.equations = [a__up__H - a__down__H,
                               a__up__Q + a__down__Q,
                               b__up__H - b__down__H,
                               b__up__Q + b__down__Q,
                               c__up__H - c__down__H,
                               c__up__Q + c__down__Q,
                               d__up__H - d__down__H,
                               d__up__Q + d__down__Q,
                               qa__down__Q,
                               qc__down__Q,
                               hb__up__H,
                               qa__down__H - a__up__H,
                               qa__down__Z - a__up__Z,
                               qc__down__H - c__up__H,
                               qc__down__Z - c__up__Z,
                               a__down__H - b__up__H,
                               a__down__Z - b__up__Z,
                               c__down__H - b__up__H,
                               c__down__Z - b__up__Z,
                               b__down__H - hb__up__H,
                               b__down__Z - hb__up__Z,
                               qa__down__Q + a__up__Q,
                               qc__down__Q + c__up__Q,
                               a__down__Q + (b__up__Q + c__down__Q),
                               b__down__Q + hb__up__Q,
                               d__up__Q,
                               d__down__Q]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_tree_lookup(self):
        with open(os.path.join(MODEL_DIR, 'TreeLookup.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)

        casadi_model = gen_casadi.generate(ast_tree, 'Level1.Level2.Level3.Test')
        ref_model = Model()
        print(casadi_model)

        elem__tc__i = ca.MX.sym("elem.tc.i")
        elem__tc__a = ca.MX.sym("elem.tc.a")
        b = ca.MX.sym("b")

        ref_model.alg_states = list(map(Variable, [elem__tc__i, elem__tc__a, b]))

        ref_model.equations = [elem__tc__i - 1,
                               elem__tc__a - b]

        print(ref_model)
        self.assert_model_equivalent(ref_model, casadi_model)

    def test_duplicate(self):
        with open(os.path.join(MODEL_DIR, 'DuplicateState.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'DuplicateState')
        print(casadi_model)
        ref_model = Model()

        x = ca.MX.sym("x")
        der_x = ca.MX.sym("der(x)")
        y = ca.MX.sym("y")
        der_y = ca.MX.sym("der(y)")

        ref_model.states = list(map(Variable, [x, y]))
        ref_model.der_states = list(map(Variable, [der_x, der_y]))
        ref_model.equations = [der_x + der_y - 1, der_x - 2]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_if_else(self):
        with open(os.path.join(MODEL_DIR, 'IfElse.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'IfElse')
        ref_model = Model()

        x = ca.MX.sym("x")
        y1 = ca.MX.sym("y1")
        y2 = ca.MX.sym("y2")
        y3 = ca.MX.sym("y3")
        y_max = ca.MX.sym("y_max")

        ref_model.inputs = list(map(Variable, [x]))
        ref_model.outputs = list(map(Variable, [y1, y2, y3]))
        ref_model.alg_states = list(map(Variable, [y1, y2, y3]))
        ref_model.parameters = list(map(Variable, [y_max]))
        ref_model.parameters[0].value = 10
        ref_model.equations = [
            y1 - ca.if_else(x > 0, 1, 0) * y_max,
            ca.if_else(x > 1, ca.vertcat(y2 - y_max, y3 - 100),
                       ca.if_else(x > 2, ca.vertcat(y2 - y_max - 1, y3 - 1000),
                                  ca.vertcat(y2, y3 - 10000)))]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_inheritance(self):
        with open(os.path.join(MODEL_DIR, 'Inheritance.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'Sub')
        ref_model = Model()

        x = ca.MX.sym("x")
        der_x = ca.MX.sym("der(x)")
        y = ca.MX.sym("y")
        # noinspection PyUnusedLocal
        der_y = ca.MX.sym("y")
        k = ca.MX.sym("k")

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].max = 30.0
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [y]))
        ref_model.parameters = list(map(Variable, [k]))
        ref_model.parameters[0].value = -1.0
        ref_model.equations = [der_x - k * x, x + y - 3]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_inheritance_instantiation(self):
        with open(os.path.join(MODEL_DIR, 'InheritanceInstantiation.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'C2')
        ref_model = Model()
        print(casadi_model)

        bcomp1_a = ca.MX.sym('bcomp1.a')
        bcomp1_b = ca.MX.sym('bcomp1.b')
        bcomp2_a = ca.MX.sym('bcomp2.a')
        bcomp2_b = ca.MX.sym('bcomp2.b')
        bcomp3_a = ca.MX.sym('bcomp3.a')
        bcomp3_b = ca.MX.sym('bcomp3.b')

        bcomp1_v = ca.MX.sym('bcomp1.v', 3)
        bcomp2_v = ca.MX.sym('bcomp2.v', 4)
        bcomp3_v = ca.MX.sym('bcomp3.v', 2)

        ref_model.states = []
        ref_model.der_states = []
        ref_model.alg_states = list(map(Variable, [bcomp1_v, bcomp2_v, bcomp3_v]))
        ref_model.parameters = list(map(Variable, [bcomp1_a, bcomp2_a, bcomp3_a, bcomp1_b, bcomp2_b, bcomp3_b]))
        ref_model.parameters[0].value = 0
        ref_model.parameters[1].value = 0
        ref_model.parameters[2].value = 1
        ref_model.parameters[3].value = 3
        ref_model.parameters[4].value = 4
        ref_model.parameters[5].value = 2
        ref_model.equations = []

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_nested_classes(self):
        with open(os.path.join(MODEL_DIR, 'NestedClasses.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'C2')
        ref_model = Model()
        print(casadi_model)

        v1 = ca.MX.sym('v1')
        v2 = ca.MX.sym('v2')

        ref_model.states = []
        ref_model.der_states = []
        ref_model.alg_states = list(map(Variable, [v1, v2]))
        ref_model.equations = []
        ref_model.alg_states[0].nominal = 1000.0
        ref_model.alg_states[1].nominal = 1000.0

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_builtin(self):
        with open(os.path.join(MODEL_DIR, 'BuiltinFunctions.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'BuiltinFunctions')
        print("BuiltinFunctions", casadi_model)
        ref_model = Model()

        x = ca.MX.sym("x")
        y = ca.MX.sym("y")
        z = ca.MX.sym("z")
        w = ca.MX.sym("w")
        u = ca.MX.sym("u")

        ref_model.inputs = list(map(Variable, [x]))
        ref_model.outputs = list(map(Variable, [y, z, w, u]))
        ref_model.alg_states = list(map(Variable, [y, z, w, u]))
        ref_model.equations = [y - ca.sin(ref_model.time), z - ca.cos(x), w - ca.fmin(y, z), u - ca.fabs(w)]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_function_call(self):
        with open(os.path.join(MODEL_DIR, 'FunctionCall.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'FunctionCall')
        print("FunctionCall", casadi_model)
        ref_model = Model()

        radius = ca.MX.sym('radius')
        diameter = radius * 2
        circle_properties = ca.Function('circle_properties', [radius], [3.14159*diameter, 3.14159*radius**2, ca.if_else(3.14159*radius**2 > 10, 1, 2), ca.if_else(3.14159*radius**2 > 10, 10, 3.14159*radius**2), 8, 3, 12])

        c = ca.MX.sym("c")
        a = ca.MX.sym("a")
        d = ca.MX.sym("d")
        e = ca.MX.sym("e")
        S1 = ca.MX.sym("S1")
        S2 = ca.MX.sym("S2")
        r = ca.MX.sym("r")
        ref_model.alg_states = list(map(Variable, [r, c, a, d, e, S1, S2]))
        ref_model.outputs = list(map(Variable, [c, a, d, e, S1, S2]))
        ref_model.equations = [ca.vertcat(c, a, d, e, S1, S2) - ca.vertcat(*circle_properties.call([r])[0:-1])]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    @unittest.skip
    def test_double_function_call(self):
        with open(os.path.join(MODEL_DIR, 'DoubleFunctionCall.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'FunctionCall')
        print("FunctionCall", casadi_model)
        ref_model = Model()

        # Check that both instances of the function call refer to the same node in the tree
        func_a = casadi_model.equations[0].dep(1).dep(0).dep(0).dep(0).getFunction().__hash__()
        func_b = casadi_model.equations[1].dep(1).dep(0).dep(0).dep(0).getFunction().__hash__()

        self.assertEqual(func_a, func_b)

    def test_forloop(self):
        with open(os.path.join(MODEL_DIR, 'ForLoop.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'ForLoop')
        print(casadi_model)
        ref_model = Model()

        x = ca.MX.sym("x", 10)
        y = ca.MX.sym("y", 10)
        z = ca.MX.sym("z", 10)
        u = ca.MX.sym('u', 10, 2)
        v = ca.MX.sym('v', 2, 10)
        w = ca.MX.sym('w', 2, 10)
        b = ca.MX.sym("b")
        n = ca.MX.sym("n")
        s = ca.MX.sym('s', 10)
        Arr = ca.MX.sym('Arr', 2, 2)
        der_s = ca.MX.sym('der(s)', 10)

        ref_model.states = list(map(Variable, [s]))
        ref_model.der_states = list(map(Variable, [der_s]))
        ref_model.alg_states = list(map(Variable, [x, y, z, u, v, w, b, Arr]))
        ref_model.parameters = list(map(Variable, [n]))
        ref_model.parameters[0].value = 10
        ref_model.equations = [
            ca.horzcat(x - (np.arange(1, 11) + b), w[0, :].T - np.arange(1, 11), w[1, :].T - np.arange(2, 21, 2), u - np.ones((10, 2)), v.T - np.ones((10, 2))),
            y[0:5] - np.zeros(5), y[5:] - np.ones(5),
            ca.horzcat(z[0:5] - np.array([2, 2, 2, 2, 2]), z[5:10] - np.array([1, 1, 1, 1, 1])), der_s - np.ones(10),
            ca.horzcat(Arr[:, 1], Arr[:, 0]) - np.array([[2, 1], [2, 1]])]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_arrayexpressions(self):
        with open(os.path.join(MODEL_DIR, 'ArrayExpressions.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'ArrayExpressions')
        print(casadi_model)
        ref_model = Model()

        a = ca.MX.sym("a", 3)
        b = ca.MX.sym("b", 4)
        c = ca.MX.sym("c", 3)
        d = ca.MX.sym("d", 3)
        e = ca.MX.sym("e", 3)
        g = ca.MX.sym("g", 1)
        h = ca.MX.sym("h", 1)
        i = ca.MX.sym('i', 2, 3)
        B = ca.MX.sym("B", 3)
        C = ca.MX.sym("C", 2)
        D = ca.MX.sym("D", 3)
        E = ca.MX.sym("E", 2)
        arx = ca.MX.sym("ar.x", 3)
        arcy = ca.MX.sym("arc.y", 2)
        arcw = ca.MX.sym("arc.w", 2)
        nested1z = ca.MX.sym('nested1.z', 3)
        nested2z = ca.MX.sym('nested2.z', 2, 3)
        nested1n = ca.MX.sym('nested1.n', 1)
        nested2n = ca.MX.sym('nested2.n', 2)

        scalar_f = ca.MX.sym("scalar_f")
        c_dim = ca.MX.sym("c_dim")
        d_dim = ca.MX.sym("d_dim")

        ref_model.alg_states = list(map(Variable, [arx, arcy, arcw, nested1z, nested2z, a, c, d, e, scalar_f, g, h, i]))
        ref_model.alg_states[6].min = [0, 0, 0]
        ref_model.parameters = list(map(Variable, [nested2n, nested1n, d_dim]))
        parameter_values = [np.array([3, 3]), 3, 3]
        for const, val in zip(ref_model.parameters, parameter_values):
            const.value = val
        ref_model.outputs = list(map(Variable, [h]))
        ref_model.constants = list(map(Variable, [b, c_dim, B, C, D, E]))
        constant_values = [np.array([2.7, 3.7, 4.7, 5.7]), 2, ca.linspace(1., 2., 3), 1.7 * ca.DM.ones(2),
                                     ca.DM.zeros(3), ca.DM.ones(2)]
        for const, val in zip(ref_model.constants, constant_values):
            const.value = val
        ref_model.equations = [c - (a + b[0:3] * e), d - (ca.sin(a / b[1:4])), e - (d + scalar_f), g - ca.sum1(c),
                               h - B[1], arx[1] - scalar_f, nested1z - ca.DM.ones(3), nested2z[0, :].T - np.array([4, 5, 6]),
                               nested2z[1, 0] - 3, nested2z[1, 1] - 2, nested2z[1, 2] - 1, i[0, :] - ca.transpose(ca.DM.ones(3)), i[1, :] - ca.transpose(ca.DM.ones(3)), arcy[0] - arcy[1],
                               arcw[0] + arcw[1], a - np.array([1, 2, 3]), scalar_f - 1.3]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_matrixexpressions(self):
        with open(os.path.join(MODEL_DIR, 'MatrixExpressions.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'MatrixExpressions')
        print(casadi_model)
        ref_model = Model()

        A = ca.MX.sym("A", 3, 3)
        b = ca.MX.sym("b", 3)
        c = ca.MX.sym("c", 3)
        d = ca.MX.sym("d", 3)
        C = ca.MX.sym("C", 2, 3)
        D = ca.MX.sym("D", 3, 2)
        E = ca.MX.sym("E", 2, 3)
        I = ca.MX.sym("I", 5, 5)
        F = ca.MX.sym("F", 3, 3)

        ref_model.alg_states = list(map(Variable, [A, b, c, d]))
        ref_model.constants = list(map(Variable, [C, D, E, I, F]))
        constant_values = [1.7 * ca.DM.ones(2, 3), ca.DM.zeros(3, 2), ca.DM.ones(2, 3), ca.DM.eye(5),
                                     ca.DM.triplet([0, 1, 2], [0, 1, 2], [1, 2, 3], 3, 3)]
        for const, val in zip(ref_model.constants, constant_values):
            const.value = val
        ref_model.equations = [ca.mtimes(A, b) - c, ca.mtimes(A.T, b) - d, F[1, 2]]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_delay(self):
        with open(os.path.join(MODEL_DIR, 'Delay.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)

        casadi_model = gen_casadi.generate(ast_tree, 'Delay')
        # Important to also test expansion of delay expressions of scalar size
        ast_tree = parser.parse(txt)
        casadi_model_expanded = gen_casadi.generate(ast_tree, 'Delay')
        casadi_model_expanded.simplify({'expand_vectors': True})

        ref_model = Model()

        x = ca.MX.sym("x")
        x_delayed = ca.MX.sym("_pymoca_delay_0")
        y = ca.MX.sym("y")
        hour = ca.MX.sym("hour")

        ref_model.alg_states = list(map(Variable, [x, y]))
        ref_model.parameters = list(map(Variable, [hour]))
        ref_model.inputs = list(map(Variable, [x_delayed]))
        ref_model.parameters[0].value = 3600
        ref_model.equations = [y - x_delayed]
        ref_model.delay_states = [x_delayed]
        ref_model.delay_arguments = [DelayArgument(x, 6 * hour)]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)
        self.assert_model_equivalent_numeric(ref_model, casadi_model_expanded)

    def test_delay_for_loop(self):
        with open(os.path.join(MODEL_DIR, 'DelayForLoop.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'DelayForLoop')
        casadi_model.simplify({'detect_aliases': True})
        print(casadi_model)

        ref_model = Model()

        x = ca.MX.sym("x", 2)
        y = ca.MX.sym("y", 2)
        z = ca.MX.sym("z", 2)
        at3_delayed = ca.MX.sym("_pymoca_delay_0", 2)
        delay_time = ca.MX.sym("delay_time")

        ref_model.alg_states = list(map(Variable, [x, y]))
        ref_model.inputs = list(map(Variable, [at3_delayed, z, delay_time]))
        ref_model.inputs[-1].fixed = True
        ref_model.equations = [ca.horzcat(x - 5 * z, y - at3_delayed)]
        ref_model.delay_states = [at3_delayed]
        ref_model.delay_arguments = [DelayArgument(3 * x, delay_time)]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_delay_for_loop_with_expand_vectors(self):
        with open(os.path.join(MODEL_DIR, 'DelayForLoop.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'DelayForLoop')
        casadi_model.simplify({'expand_vectors': True, 'detect_aliases': True})
        print(casadi_model)

        ref_model = Model()

        def _array_mx(name, n):
            return np.array([ca.MX.sym("{}[{}]".format(name, i)) for i in range(n)])

        x = _array_mx("x", 2)
        y = _array_mx("y", 2)
        a = _array_mx("a", 2)
        z = _array_mx("z", 2)
        at3_delayed = _array_mx("_pymoca_delay_0", 2)
        delay_time = ca.MX.sym("delay_time")

        ref_model.alg_states = list(map(Variable, [*x, *y, *a]))
        ref_model.inputs = list(map(Variable, [*at3_delayed, *z, delay_time]))
        ref_model.inputs[-1].fixed = True
        # TODO: "a" is not yet deteced as an alias of "x" when expanding.
        ref_model.equations = [*(x - 5 * z), *(y - at3_delayed), *(a - x)]
        ref_model.delay_states = [*at3_delayed]
        ref_model.delay_arguments = [DelayArgument(3 * a_i, delay_time) for a_i in a]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_array_3d(self):
        casadi_model = transfer_model(MODEL_DIR, 'Array3D', {'expand_vectors': True})

        target_param_values = np.array([[[ -5.326999,  54.050758,  0.000000],
                                    [ -1.0,        0.0,       0.0]],
                                   [[  0.000426,  -0.001241,  2.564056],
                                    [ -1.0,        0.0,       0.0]],
                                   [[  2.577975,  -5.203480,  0.000000],
                                    [ -1.0,        0.0,       0.0]],
                                   [[ 13.219650,  -3.097600, -7.551339],
                                    [ -1.0,        0.0,       0.0]]])

        param_symbols = [x.symbol for x in casadi_model.parameters]

        for ind in np.ndindex(target_param_values.shape):
            flat_index = np.ravel_multi_index(ind, target_param_values.shape)
            self.assertEqual(param_symbols[flat_index].name(), "x[{}]".format(",".join((str(x + 1) for x in ind))))
            self.assertEqual(casadi_model.parameters[flat_index].value, target_param_values[ind])

    def test_attributes(self):
        with open(os.path.join(MODEL_DIR, 'Attributes.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'Attributes')
        print(casadi_model)
        ref_model = Model()

        nested_p1 = ca.MX.sym('nested.p1')
        nested_p = ca.MX.sym('nested.p')
        nested_s = ca.MX.sym('nested.s')
        i = ca.MX.sym("int")
        b = ca.MX.sym("bool")
        r = ca.MX.sym("real")
        der_r = ca.MX.sym("der(real)")
        test_state = ca.MX.sym("test_state")
        i1 = ca.MX.sym("i1")
        i2 = ca.MX.sym("i2")
        i3 = ca.MX.sym("i3")
        i4 = ca.MX.sym("i4")
        cst = ca.MX.sym("cst")
        prm = ca.MX.sym("prm")
        protected_variable = ca.MX.sym("protected_variable")

        ref_model.states = list(map(Variable, [r]))
        ref_model.states[0].start = 20
        ref_model.der_states = list(map(Variable, [der_r]))
        ref_model.alg_states = list(map(Variable, [nested_s, i, b, i4, test_state, protected_variable]))
        ref_model.alg_states[1].min = -5
        ref_model.alg_states[1].max = 10
        ref_model.inputs = list(map(Variable, [i1, i2, i3]))
        ref_model.inputs[0].fixed = True
        ref_model.outputs = list(map(Variable, [i4, protected_variable]))
        ref_model.constants = list(map(Variable, [cst]))
        constant_values = [1]
        for c, v in zip(ref_model.constants, constant_values):
            c.value = v
        ref_model.parameters = list(map(Variable, [nested_p1, nested_p, prm]))
        parameter_values = [1, 2 * nested_p1, 2]
        for c, v in zip(ref_model.parameters, parameter_values):
            c.value = v
        ref_model.equations = [i4 - ((i1 + i2) + i3), der_r - (i1 + ca.if_else(b, 1, 0, True) * i),
                               protected_variable - (i1 + i2), nested_s - 3 * nested_p, test_state - r]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_type(self):
        with open(os.path.join(MODEL_DIR, 'Type.mo'), 'r') as f:
            txt = f.read()
        # noinspection PyUnusedLocal
        ast_tree = parser.parse(txt)
        self.assertTrue(True)

    def test_variable_metadata_function(self):
        # Clear cache
        db_file = os.path.join(MODEL_DIR, 'ParameterAttributes')
        try:
            os.remove(db_file)
        except FileNotFoundError:
            pass

        # Alias detection results in fmin/fmax function calls in the attributes
        compiler_options = \
            {'cache': True,
             'detect_aliases': True}

        ref_model = transfer_model(MODEL_DIR, 'ParameterAttributes', compiler_options)
        self.assertIsInstance(ref_model, Model)
        self.assertNotIsInstance(ref_model, CachedModel)

        cached_model = transfer_model(MODEL_DIR, 'ParameterAttributes', compiler_options)
        self.assertIsInstance(cached_model, Model)
        self.assertIsInstance(cached_model, CachedModel)

        in_var = ca.veccat(*ref_model._symbols(ref_model.parameters))
        function_metadata = ref_model.variable_metadata_function(in_var)

        cached_in_var = ca.veccat(*cached_model._symbols(cached_model.parameters))

        orig_metadata = []
        cached_metadata = []

        variables_with_metadata = ['states', 'alg_states', 'inputs', 'parameters', 'constants']

        for model, metadata in [(ref_model, orig_metadata), (cached_model, cached_metadata)]:
            for variable_list in variables_with_metadata:
                attribute_lists = [[] for i in range(len(CASADI_ATTRIBUTES))]
                for variable in getattr(model, variable_list):
                    for attribute_list_index, attribute in enumerate(CASADI_ATTRIBUTES):
                        value = ca.MX(getattr(variable, attribute))
                        value = value if value.numel() != 1 else ca.repmat(
                            value, *variable.symbol.size())
                        attribute_lists[attribute_list_index].append(value)
                expr = ca.horzcat(*[
                    ca.veccat(*attribute_list) for attribute_list in attribute_lists])
                metadata.append(expr)

        # Check that the output of the variable metadata function matches the
        # original metadata and cached metadata
        for a, b, c in zip(orig_metadata, function_metadata, cached_metadata):
            f_a = ca.Function('tmp', [in_var], [a])
            f_b = ca.Function('tmp', [in_var], [b])
            f_c = ca.Function('tmp', [cached_in_var], [c])

            args_in = ca.DM([2, 11])

            a_out = np.array(f_a(args_in))
            b_out = np.array(f_b(args_in))
            c_out = np.array(f_c(args_in))

            self.assertTrue(np.allclose(a_out, b_out, 0, 0, True))
            self.assertTrue(np.allclose(a_out, c_out, 0, 0, True))

    def test_cache(self):
        # Clear cache
        db_file = os.path.join(MODEL_DIR, 'Aircraft')
        try:
            os.remove(db_file)
        except FileNotFoundError:
            pass

        # Create model, cache it, and load the cache
        compiler_options = \
            {'cache': True}

        ref_model = transfer_model(MODEL_DIR, 'Aircraft', compiler_options)
        self.assertIsInstance(ref_model, Model)
        self.assertNotIsInstance(ref_model, CachedModel)

        cached_model = transfer_model(MODEL_DIR, 'Aircraft', compiler_options)
        self.assertIsInstance(cached_model, Model)
        self.assertIsInstance(cached_model, CachedModel)

        # Compare
        self.assert_model_equivalent_numeric(ref_model, cached_model)

    def test_cache_delay_arguments(self):
        # Clear cache
        db_file = os.path.join(MODEL_DIR, 'Delay')
        try:
            os.remove(db_file)
        except FileNotFoundError:
            pass

        compiler_options = {'cache': True}

        ref_model = transfer_model(MODEL_DIR, 'Delay', compiler_options)
        self.assertIsInstance(ref_model, Model)
        self.assertNotIsInstance(ref_model, CachedModel)

        cached_model = transfer_model(MODEL_DIR, 'Delay', compiler_options)
        self.assertIsInstance(cached_model, Model)
        self.assertIsInstance(cached_model, CachedModel)

        self.assert_model_equivalent_numeric(ref_model, cached_model)

    def test_codegen(self):
        # Clear cache
        db_file = os.path.join(MODEL_DIR, 'Aircraft')
        try:
            os.remove(db_file)
        except FileNotFoundError:
            pass

        for f in glob.glob(os.path.join(MODEL_DIR, "Aircraft*.so")):
            os.remove(f)
        for f in glob.glob(os.path.join(MODEL_DIR, "Aircraft*.dll")):
            os.remove(f)
        for f in glob.glob(os.path.join(MODEL_DIR, "Aircraft*.dylib")):
            os.remove(f)

        # Create model, cache it, and load the cache
        compiler_options = \
            {'codegen': True}

        ref_model = transfer_model(MODEL_DIR, 'Aircraft', compiler_options)
        self.assertIsInstance(ref_model, Model)
        self.assertNotIsInstance(ref_model, CachedModel)

        cached_model = transfer_model(MODEL_DIR, 'Aircraft', compiler_options)
        self.assertIsInstance(cached_model, Model)
        self.assertIsInstance(cached_model, CachedModel)

        # Compare
        self.assert_model_equivalent_numeric(ref_model, cached_model)

    def test_simplify_replace_constant_values(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'replace_constant_values': True}

        casadi_model = transfer_model(MODEL_DIR, 'Simplify', compiler_options)

        ref_model = Model()

        p1 = ca.MX.sym('p1')
        p2 = ca.MX.sym('p2')
        p3 = ca.MX.sym('p3')
        p4 = ca.MX.sym('p4')
        x = ca.MX.sym('x')
        der_x = ca.MX.sym('der(x)')
        alias = ca.MX.sym('alias')
        y = ca.MX.sym('y')
        _tmp = ca.MX.sym('_tmp')
        cst = ca.MX.sym('cst')

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].min = 0
        ref_model.states[0].max = 3
        ref_model.states[0].nominal = 10
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [alias, y, _tmp, cst]))
        ref_model.alg_states[0].min = 1
        ref_model.alg_states[0].max = 2
        ref_model.alg_states[0].nominal = 1
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.constants = list(map(Variable, []))
        constant_values = []
        for _cst, v in zip(ref_model.constants, constant_values):
            _cst.value = v
        ref_model.parameters = list(map(Variable, [p1, p2, p3, p4]))
        parameter_values = [2.0, 2 * p1, np.nan, 2 * p3]
        for par, v in zip(ref_model.parameters, parameter_values):
            par.value = v
        ref_model.equations = [der_x - x - p1 - p2 - p3 - p4, alias - x, y - x - 3 - _tmp - cst, _tmp - 0.1 * x, cst - 4]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)

    def test_simplify_replace_parameter_expressions(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'replace_parameter_expressions': True}

        casadi_model = transfer_model(MODEL_DIR, 'Simplify', compiler_options)

        ref_model = Model()

        c = ca.MX.sym('c')
        p1 = ca.MX.sym('p1')
        p3 = ca.MX.sym('p3')
        x = ca.MX.sym('x')
        der_x = ca.MX.sym('der(x)')
        alias = ca.MX.sym('alias')
        y = ca.MX.sym('y')
        _tmp = ca.MX.sym('_tmp')
        cst = ca.MX.sym('cst')

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].min = 0
        ref_model.states[0].max = 3
        ref_model.states[0].nominal = 10
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [alias, y, _tmp, cst]))
        ref_model.alg_states[0].min = 1
        ref_model.alg_states[0].max = 2
        ref_model.alg_states[0].nominal = 1
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.constants = list(map(Variable, [c]))
        constant_values = [3]
        for _cst, v in zip(ref_model.constants, constant_values):
            _cst.value = v
        ref_model.parameters = list(map(Variable, [p1, p3]))
        parameter_values = [2.0, np.nan]
        for par, v in zip(ref_model.parameters, parameter_values):
            par.value = v
        ref_model.equations = [der_x - x - 3 * p1 - 3 * p3, alias - x, y - x - c - _tmp - cst, _tmp - 0.1 * x, cst - 4]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)

    def test_simplify_replace_parameter_values(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'replace_parameter_values': True}

        casadi_model = transfer_model(MODEL_DIR, 'Simplify', compiler_options)

        ref_model = Model()

        c = ca.MX.sym('c')
        p2 = ca.MX.sym('p2')
        p3 = ca.MX.sym('p3')
        p4 = ca.MX.sym('p4')
        x = ca.MX.sym('x')
        der_x = ca.MX.sym('der(x)')
        alias = ca.MX.sym('alias')
        y = ca.MX.sym('y')
        _tmp = ca.MX.sym('_tmp')
        cst = ca.MX.sym('cst')

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].min = 0
        ref_model.states[0].max = 3
        ref_model.states[0].nominal = 10
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [alias, y, _tmp, cst]))
        ref_model.alg_states[0].min = 1
        ref_model.alg_states[0].max = 2
        ref_model.alg_states[0].nominal = 1
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.constants = list(map(Variable, [c]))
        constant_values = [3]
        for _cst, v in zip(ref_model.constants, constant_values):
            _cst.value = v
        ref_model.parameters = list(map(Variable, [p2, p3, p4]))
        parameter_values = [4, np.nan, 2 * p3]
        for par, v in zip(ref_model.parameters, parameter_values):
            par.value = v
        ref_model.equations = [der_x - x - 2 - p2 - p3 - p4, alias - x, y - x - c - _tmp - cst, _tmp - 0.1 * x, cst - 4]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)

    def test_simplify_replace_parameter_values_and_expressions(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'replace_parameter_values': True,
             'replace_parameter_expressions': True}

        casadi_model = transfer_model(MODEL_DIR, 'Simplify', compiler_options)

        ref_model = Model()

        c = ca.MX.sym('c')
        p3 = ca.MX.sym('p3')
        x = ca.MX.sym('x')
        der_x = ca.MX.sym('der(x)')
        alias = ca.MX.sym('alias')
        y = ca.MX.sym('y')
        _tmp = ca.MX.sym('_tmp')
        cst = ca.MX.sym('cst')

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].min = 0
        ref_model.states[0].max = 3
        ref_model.states[0].nominal = 10
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [alias, y, _tmp, cst]))
        ref_model.alg_states[0].min = 1
        ref_model.alg_states[0].max = 2
        ref_model.alg_states[0].nominal = 1
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.constants = list(map(Variable, [c]))
        constant_values = [3]
        for _cst, v in zip(ref_model.constants, constant_values):
            _cst.value = v
        ref_model.parameters = list(map(Variable, [p3]))
        parameter_values = [np.nan]
        for par, v in zip(ref_model.parameters, parameter_values):
            par.value = v
        ref_model.equations = [der_x - x - 6 - 3 * p3, alias - x, y - x - c - _tmp - cst, _tmp - 0.1 * x, cst - 4]

        print(casadi_model)
        print(ref_model)
        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)

    def test_simplify_eliminate_constant_assignments(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'eliminate_constant_assignments': True}

        casadi_model = transfer_model(MODEL_DIR, 'Simplify', compiler_options)

        ref_model = Model()

        c = ca.MX.sym('c')
        p1 = ca.MX.sym('p1')
        p2 = ca.MX.sym('p2')
        p3 = ca.MX.sym('p3')
        p4 = ca.MX.sym('p4')
        x = ca.MX.sym('x')
        der_x = ca.MX.sym('der(x)')
        alias = ca.MX.sym('alias')
        y = ca.MX.sym('y')
        _tmp = ca.MX.sym('_tmp')
        cst = ca.MX.sym('cst')

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].min = 0
        ref_model.states[0].max = 3
        ref_model.states[0].nominal = 10
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [alias, y, _tmp]))
        ref_model.alg_states[0].min = 1
        ref_model.alg_states[0].max = 2
        ref_model.alg_states[0].nominal = 1
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.constants = list(map(Variable, [c, cst]))
        constant_values = [3, 4]
        for _cst, v in zip(ref_model.constants, constant_values):
            _cst.value = v
        ref_model.parameters = list(map(Variable, [p1, p2, p3, p4]))
        parameter_values = [2.0, 2 * p1, np.nan, 2 * p3]
        for par, v in zip(ref_model.parameters, parameter_values):
            par.value = v
        ref_model.equations = [der_x - x - p1 - p2 - p3 - p4, alias - x, y - x - c - _tmp - cst, _tmp - 0.1 * x]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)

    def test_simplify_eliminable_variable_expression(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'eliminable_variable_expression': r'_\w+'}

        casadi_model = transfer_model(MODEL_DIR, 'Simplify', compiler_options)

        ref_model = Model()

        c = ca.MX.sym('c')
        p1 = ca.MX.sym('p1')
        p2 = ca.MX.sym('p2')
        p3 = ca.MX.sym('p3')
        p4 = ca.MX.sym('p4')
        x = ca.MX.sym('x')
        der_x = ca.MX.sym('der(x)')
        alias = ca.MX.sym('alias')
        y = ca.MX.sym('y')
        cst = ca.MX.sym('cst')

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].min = 0
        ref_model.states[0].max = 3
        ref_model.states[0].nominal = 10
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [alias, y, cst]))
        ref_model.alg_states[0].min = 1
        ref_model.alg_states[0].max = 2
        ref_model.alg_states[0].nominal = 1
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.constants = list(map(Variable, [c]))
        constant_values = [3]
        for _cst, v in zip(ref_model.constants, constant_values):
            _cst.value = v
        ref_model.parameters = list(map(Variable, [p1, p2, p3, p4]))
        parameter_values = [2.0, 2 * p1, np.nan, 2 * p3]
        for par, v in zip(ref_model.parameters, parameter_values):
            par.value = v
        ref_model.equations = [der_x - x - p1 - p2 - p3 - p4, alias - x, y - x - c - 0.1 * x - cst, cst - 4]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)

    def test_simplify_detect_aliases(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'detect_aliases': True}

        casadi_model = transfer_model(MODEL_DIR, 'Simplify', compiler_options)

        ref_model = Model()

        c = ca.MX.sym('c')
        p1 = ca.MX.sym('p1')
        p2 = ca.MX.sym('p2')
        p3 = ca.MX.sym('p3')
        p4 = ca.MX.sym('p4')
        x = ca.MX.sym('x')
        der_x = ca.MX.sym('der(x)')
        y = ca.MX.sym('y')
        _tmp = ca.MX.sym('_tmp')
        cst = ca.MX.sym('cst')

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].min = 1
        ref_model.states[0].max = 2
        ref_model.states[0].nominal = 10
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [y, _tmp, cst]))
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.constants = list(map(Variable, [c]))
        constant_values = [3]
        for _cst, v in zip(ref_model.constants, constant_values):
            _cst.value = v
        ref_model.parameters = list(map(Variable, [p1, p2, p3, p4]))
        parameter_values = [2.0, 2 * p1, np.nan, 2 * p3]
        for par, v in zip(ref_model.parameters, parameter_values):
            par.value = v
        ref_model.equations = [der_x - x - p1 - p2 - p3 - p4, y - x - c - _tmp - cst, _tmp - 0.1 * x, cst - 4]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)
        self.assertEquals(casadi_model.states[0].aliases, ['alias'])

    def test_simplify_detect_negative_alias(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'detect_aliases': True}

        casadi_model = transfer_model(MODEL_DIR, 'NegativeAlias', compiler_options)

        ref_model = Model()

        x = ca.MX.sym('x')
        der_x = ca.MX.sym('der(x)')

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].min = 1
        ref_model.states[0].max = 2
        ref_model.states[0].nominal = 10
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, []))
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.equations = [der_x - x]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)
        self.assertEquals(casadi_model.states[0].aliases, ['-alias'])

    def test_simplify_expand_vectors(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'expand_vectors': True}

        casadi_model = transfer_model(MODEL_DIR, 'SimplifyVector', compiler_options)

        ref_model = Model()

        x0 = ca.MX.sym('x[0]')
        x1 = ca.MX.sym('x[1]')
        der_x0 = ca.MX.sym('der(x)[0]')
        der_x1 = ca.MX.sym('der(x)[1]')

        ref_model.states = list(map(Variable, [x0, x1]))
        ref_model.der_states = list(map(Variable, [der_x0, der_x1]))
        ref_model.alg_states = list(map(Variable, []))
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.equations = [der_x0 - x0, der_x1 - x1]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)

    def test_simplify_reduce_affine_expression_loop(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'expand_vectors': True,
             'detect_aliases': True,
             'reduce_affine_expression': True,
             'replace_constant_expressions': True,
             'replace_constant_values': True,
             'replace_parameter_expressions': True,
             'replace_parameter_values': True}

        casadi_model = transfer_model(MODEL_DIR, 'SimplifyLoop', compiler_options)

        ref_model = Model()

        x = ca.MX.sym('x')
        y0 = ca.MX.sym('y[0]')
        y1 = ca.MX.sym('y[1]')

        A = ca.MX(2, 3)
        A[0, 0] = -1
        A[0, 1] = 1
        A[0, 2] = 0
        A[1, 0] = -2
        A[1, 1] = 0
        A[1, 2] = 1
        b = ca.MX(2, 1)
        b[0, 0] = 0
        b[1, 0] = 0

        ref_model.states = list(map(Variable, []))
        ref_model.der_states = list(map(Variable, []))
        ref_model.alg_states = list(map(Variable, [x, y0, y1]))
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        x = ca.vertcat(x, y0, y1)
        ref_model.equations = [ca.mtimes(A, x) + b]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)

    def test_simplify_reduce_affine_expression(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'reduce_affine_expression': True}

        casadi_model = transfer_model(MODEL_DIR, 'Simplify', compiler_options)

        ref_model = Model()

        c = ca.MX.sym('c')
        p1 = ca.MX.sym('p1')
        p2 = ca.MX.sym('p2')
        p3 = ca.MX.sym('p3')
        p4 = ca.MX.sym('p4')
        x = ca.MX.sym('x')
        der_x = ca.MX.sym('der(x)')
        alias = ca.MX.sym('alias')
        y = ca.MX.sym('y')
        _tmp = ca.MX.sym('_tmp')
        cst = ca.MX.sym('cst')

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].min = 0
        ref_model.states[0].max = 3
        ref_model.states[0].nominal = 10
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [alias, y, _tmp, cst]))
        ref_model.alg_states[0].min = 1
        ref_model.alg_states[0].max = 2
        ref_model.alg_states[0].nominal = 1
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.constants = list(map(Variable, [c]))
        constant_values = [3]
        for _cst, v in zip(ref_model.constants, constant_values):
            _cst.value = v
        ref_model.parameters = list(map(Variable, [p1, p2, p3, p4]))
        parameter_values = [2.0, 2 * p1, np.nan, 2 * p3]
        for par, v in zip(ref_model.parameters, parameter_values):
            par.value = v

        A = ca.MX(5, 6)
        A[0, 0] = -1.0
        A[0, 1] = 1.0
        A[1, 2] = 1.0
        A[1, 0] = -1.0
        A[2, 0] = -1.0
        A[2, 3] = 1.0
        A[2, 4] = -1.0
        A[2, 5] = -1.0
        A[3, 0] = -0.1
        A[3, 4] = 1.0
        A[4, 5] = 1.0
        b = ca.MX(5, 1)
        b[0] = -p1 - p2 - p3 - p4
        b[2] = -c
        b[4] = -4
        x = ca.vertcat(x, der_x, alias, y, _tmp, cst)
        ref_model.equations = [ca.mtimes(A, x) + b]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)

    def test_simplify_all(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'expand_vectors': True,
             'replace_constant_values': True,
             'replace_constant_expressions': True,
             'replace_parameter_values': True,
             'replace_parameter_expressions': True,
             'eliminate_constant_assignments': True,
             'detect_aliases': True,
             'eliminable_variable_expression': r'_\w+',
             'reduce_affine_expression': True}

        casadi_model = transfer_model(MODEL_DIR, 'Simplify', compiler_options)

        ref_model = Model()

        p3 = ca.MX.sym('p3')
        x = ca.MX.sym('x')
        der_x = ca.MX.sym('der(x)')
        y = ca.MX.sym('y')

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].min = 1
        ref_model.states[0].max = 2
        ref_model.states[0].nominal = 10
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [y]))
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.constants = list(map(Variable, []))
        constant_values = []
        for _cst, v in zip(ref_model.constants, constant_values):
            _cst.value = v
        ref_model.parameters = list(map(Variable, [p3]))
        parameter_values = [np.nan]
        for par, v in zip(ref_model.parameters, parameter_values):
            par.value = v

        A = ca.MX(2, 3)
        A[0, 0] = -1.0
        A[0, 1] = 1.0
        A[1, 0] = -1.1
        A[1, 2] = 1.0
        b = ca.MX(2, 1)
        b[0] = -6 - 3 * p3
        b[1] = -7
        x = ca.vertcat(x, der_x, y)
        ref_model.equations = [ca.mtimes(A, x) + b]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)

    def test_simplify_expand_mx(self):
        # Create model, cache it, and load the cache
        compiler_options = \
            {'expand_mx': True}

        casadi_model = transfer_model(MODEL_DIR, 'Simplify', compiler_options)

        ref_model = Model()

        c = ca.MX.sym('c')
        p1 = ca.MX.sym('p1')
        p2 = ca.MX.sym('p2')
        p3 = ca.MX.sym('p3')
        p4 = ca.MX.sym('p4')
        x = ca.MX.sym('x')
        der_x = ca.MX.sym('der(x)')
        alias = ca.MX.sym('alias')
        y = ca.MX.sym('y')
        _tmp = ca.MX.sym('_tmp')
        cst = ca.MX.sym('cst')

        ref_model.states = list(map(Variable, [x]))
        ref_model.states[0].min = 0
        ref_model.states[0].max = 3
        ref_model.states[0].nominal = 10
        ref_model.der_states = list(map(Variable, [der_x]))
        ref_model.alg_states = list(map(Variable, [alias, y, _tmp, cst]))
        ref_model.alg_states[0].min = 1
        ref_model.alg_states[0].max = 2
        ref_model.alg_states[0].nominal = 1
        ref_model.inputs = list(map(Variable, []))
        ref_model.outputs = list(map(Variable, []))
        ref_model.constants = list(map(Variable, [c]))
        constant_values = [3]
        for _cst, v in zip(ref_model.constants, constant_values):
            _cst.value = v
        ref_model.parameters = list(map(Variable, [p1, p2, p3, p4]))
        parameter_values = [2.0, 2 * p1, np.nan, 2 * p3]
        for par, v in zip(ref_model.parameters, parameter_values):
            par.value = v
        ref_model.equations = [der_x - x - p1 - p2 - p3 - p4, alias - x, y - x - c - _tmp - cst, _tmp - 0.1 * x, cst - 4]

        # Compare
        self.assert_model_equivalent_numeric(casadi_model, ref_model)

    def test_state_annotator(self):
        with open(os.path.join(MODEL_DIR, 'StateAnnotator.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'StateAnnotator')
        print(casadi_model)
        ref_model = Model()

        x = ca.MX.sym('x')
        y = ca.MX.sym('y')
        z = ca.MX.sym('z')
        u = ca.MX.sym('u', 3)
        v = ca.MX.sym('v', 3)
        w = ca.MX.sym('w', 3)
        der_x = ca.MX.sym('der(x)')
        der_y = ca.MX.sym('der(y)')
        der_z = ca.MX.sym('der(z)')
        der_u = ca.MX.sym('der(u)', 3)
        der_v = ca.MX.sym('der(v)', 3)
        der_w = ca.MX.sym('der(w)', 3)

        ref_model.states = list(map(Variable, [x, y, z, u, v, w]))
        ref_model.der_states = list(map(Variable, [der_x, der_y, der_z, der_u, der_v, der_w]))
        ref_model.equations = [der_x + der_y - 1,
                               der_x * y + x * der_y - 2,
                               (der_x * y - x * der_y) / (y**2) - 3,
                               2 * x * der_x - 4,
                               der_z - 5,
                               der_x * z + x * der_z + der_y * z + y * der_z - 4,
                               0,
                               der_u - np.array([1, 2, 3]),
                               der_v[0] - 4,
                               der_v[1] - 5,
                               der_v[2] - 6,
                               der_w - np.array([7, 8, 9])]

        self.assert_model_equivalent_numeric(ref_model, casadi_model)

    def test_alias_relation(self):
        a = AliasRelation()
        self.assertEqual(a.canonical_signed('-a'), ('a', -1))
        a.add('a', '-b')
        a.add('b', 'c')
        a.add('d', '-b')
        self.assertEqual(list(a), [('d', ['a', '-b', '-c'])])

    def test_cat_params(self):
        casadi_model = transfer_model(MODEL_DIR, 'Concat', {'replace_constant_values': True})
        c = [0, 1, 2, 2, 2, 0, 1]
        for i, e in enumerate(c):
            self.assertEqual(casadi_model.parameters[1].value[i], e)

    def test_inline_input_assignment(self):
        casadi_model = transfer_model(MODEL_DIR, 'InlineAssignment')
        self.assertTrue(casadi_model.inputs[0].fixed)
        self.assertFalse(casadi_model.alg_states[0].fixed)
        casadi_model = transfer_model(MODEL_DIR, 'InlineAssignment', {'detect_aliases': True})
        self.assertTrue(casadi_model.inputs[0].fixed)

    def test_unspecified_dimensions(self):
        with open(os.path.join(MODEL_DIR, 'UnspecifiedDimensions.mo'), 'r') as f:
            txt = f.read()
        ast_tree = parser.parse(txt)
        casadi_model = gen_casadi.generate(ast_tree, 'B')

        a_x = casadi_model.parameters[0]
        a_y = casadi_model.parameters[1]

        self.assertTrue(a_x.symbol.name() == "a.x")
        self.assertEqual(a_x.value, [[ 88.3224,  281.642,  143.011],
                                     [ 58.8183, -24.9845,      0.0],
                                     [-1.45483,      0.0,      0.0]])

        self.assertTrue(a_y.symbol.name() == "a.y")
        self.assertEqual(a_y.value, [[1, 2],
                                     [3, 4],
                                     [5, 6]])

if __name__ == "__main__":
    unittest.main()


import numpy as np
import matplotlib.pyplot as plt
import math
from decimal import Decimal, getcontext
from matplotlib.animation import FuncAnimation, PillowWriter

N=91

def RK4(f, y0, t):
    n = len(t)
    # if y0 is a scalar:
    if np.isscalar(y0):
        y = np.zeros(n)
    else:
        y = np.zeros((n, len(y0)))
    y[0] = y0
    for i in range(n-1):
        h = t[i+1] - t[i]
        k1 = h*f(t[i], y[i])
        k2 = h*f(t[i] + h/2, y[i] + k1/2)
        k3 = h*f(t[i] + h/2, y[i] + k2/2)
        k4 = h*f(t[i] + h, y[i] + k3)
        y[i+1] = y[i] + (k1 + 2*k2 + 2*k3 + k4)/6
    return y

f4 = lambda t, y: y**2

C = N/100
h = 1e-6
t = np.linspace(0, 1.5, int(1.5/h))
y = RK4(f4, C, t)
plt.plot(t, y)
plt.xlabel('t')
plt.ylabel('y')
t_last = t[(np.where(np.isfinite(y)))][-1]
plt.title(f'RK4 y(0) = 0.91, end={t_last:.6f}')
plt.show()


def isSubsequence(s: str, t: str) -> bool:
    s_len, t_len = len(s), len(t)
    if s_len > t_len:
        return False
    elif s_len == 0:
        return True
    else:
        s_iterator, t_iterator = 0, 0
        while s_iterator < s_len and t_iterator < t_len:
            if s[s_iterator] == t[t_iterator]:
                s_iterator += 1
            t_iterator += 1
        return s_len == s_iterator

print(isSubsequence("abc", "abvc"))