from os import path
from hashlib import md5
from datetime import datetime

from django.http import HttpResponseRedirect
from django.conf.urls import url
from django_openapi import OpenAPI, Path, Body, Query, Form, UploadFile, Cookie, Header
from django_openapi.schema import (
    BaseModel,
    StringField,
    NumberField,
    BooleanField,
    ObjectField,
    ArrayField,
)

'''
A minimal working demo of Django App
'''

DEBUG = True
SECRET_KEY = 'canukeepasecret'
ROOT_URLCONF = __name__

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': path.join(path.dirname(__file__), 'db.sqlite3'),
    }
}

def redirect_to_doc(request):
    return HttpResponseRedirect(
        '/intro/_rapidoc#tag--1.-Setup-your-first-OpenAPI-endpoint'
    )

api = OpenAPI(
    title='OpenAPI Test', version='0.1', description='Just a Test', prefix_path='/intro'
)

urlpatterns = [url(r'^$', redirect_to_doc), api.as_django_url_pattern()]

class IntroResponse1(BaseModel):
    arg1 = StringField()
    arg2 = StringField()

class IntroResponse2(BaseModel):
    arg1 = StringField(min_length=3, max_length=10)
    arg2 = NumberField(gte=0, lte=10, multiple_of=1)
    arg3 = BooleanField(default_value=False)

@api.get(
    '/get_request',
    tags=['1. Setup your first OpenAPI endpoint'],
    summary='Get start & create a simple http GET route',
)
def get_request():
    '''
For start using django-openapi, in your Django project

* import OpenAPI from django_openapi
* create an OpenAPI object
* put it into your urlpatterns
* start define api endpoints using api OpenAPI object

```python
from django_openapi import OpenAPI

api = OpenAPI(
    title='OpenAPI Test',
    version='0.1',
    description='Just a Test',
    prefix_path='/intro'
)

urlpatterns = [
    api.as_django_url_pattern()
]

@api.get('/get_request')
def get_request():
    return {'hello': 'world'}
```
    '''
    return {'hello': 'world'}

@api.get(
    '/get_request_with_path_args/{arg1}/{arg2}',
    tags=['1. Basic HTTP requests'],
    summary='Define path parameters',
    response_model=IntroResponse1,
)
def get_request_with_path_args(arg1=Path(), arg2=Path()):
    '''
Use `Path()` to tell API to parse parameter from url path

```python
from django_openapi import Path

@api.get('/get_request_with_path_args/{arg1}/{arg2}')
def get_request_with_path_args(arg1=Path(), arg2=Path()):
    return dict(arg1=arg1, arg2=arg2)
```
    '''
    return dict(arg1=arg1, arg2=arg2)

@api.get(
    '/get_request_with_query_args',
    tags=['1. Basic HTTP requests'],
    summary='Define query string parameters',
    response_model=IntroResponse1,
)
def get_request_with_query_args(arg1=Query(), arg2=Query()):
    '''
Use `Query()` to tell API to parse parameters from query string

```python
from django_openapi import Query

@api.get('/get_request_with_query_args')
def get_request_with_query_args(arg1=Query(), arg2=Query()):
    return dict(arg1=arg1, arg2=arg2)
```

Query strings are something after the `?` mark of your url.

`https://localhost:9527/get_request_with_query_args?arg1=1&arg2=b`

`arg1` and `arg2` are so called query string
    '''
    return dict(arg1=arg1, arg2=arg2)

@api.get(
    '/get_request_with_json_schema_query_args',
    tags=['1. Basic HTTP requests'],
    summary='Auto parameter validation via JSON schema fields',
    response_model=IntroResponse2,
)
def get_request_with_json_schema_query_args(
    arg1=Query(StringField(min_length=3, max_length=10)),
    arg2=Query(NumberField(gte=0, lte=10, multiple_of=1)),
    arg3=Query(BooleanField(default_value=False)),
):
    '''
Currently, we have 5 basic JSON schema fields

* StringField
* NumberField
* BooleanField
* ObjectField
* ArrayField

Below we'll first demo how to use StringField, NumberField & BooleanField

```python
from django_openapi import Query
from django_openapi.schema import StringField, NumberField, BooleanField

@api.get('/get_request_with_json_schema_query_args')
def get_request_with_json_schema_query_args(
    arg1=Query(StringField(min_length=3, max_length=10)),
    arg2=Query(NumberField(gte=0, lte=10, multiple_of=1)),
    arg3=Query(BooleanField(default_value=False)),
):
    return dict(arg1=arg1, arg2=arg2, arg3=arg3)
```
    '''
    return dict(arg1=arg1, arg2=arg2, arg3=arg3)

@api.post(
    '/post_request_with_json_schema_form_args',
    tags=['1. Basic HTTP requests'],
    summary='Define Form parameters',
    response_model=IntroResponse2,
)
def post_request_with_json_schema_form_args(
    arg1=Form(StringField(min_length=3, max_length=10)),
    arg2=Form(NumberField(gte=0, lte=10, multiple_of=1)),
    arg3=Form(BooleanField(default_value=False)),
):
    '''
Now we use the same JSON schema field definitions, but in Form() format.

```python
from django_openapi import Form
from django_openapi.schema import StringField, NumberField, BooleanField

@api.post('/post_request_with_json_schema_form_args')
def post_request_with_json_schema_form_args(
    arg1=Form(StringField(min_length=3, max_length=10)),
    arg2=Form(NumberField(gte=0, lte=10, multiple_of=1)),
    arg3=Form(BooleanField(default_value=False)),
):
    return dict(arg1=arg1, arg2=arg2, arg3=arg3)
```
    '''
    return dict(arg1=arg1, arg2=arg2, arg3=arg3)

@api.post(
    '/post_request_file_upload',
    tags=['1. Basic HTTP requests'],
    summary='Define File Upload',
)
def post_request_file_upload(
    upload_file=UploadFile(),
    md5_hash=Form(StringField(required=False, description='md5 of uploaded file')),
):
    '''
Now let's try building an endpoint for user file upload.

```python
from hashlib import md5
from django_openapi import UploadFile, Form
from django_openapi.schema import StringField, NumberField, BooleanField

@api.post('/post_request_file_upload')
def post_request_file_upload(
    upload_file = UploadFile(),
    md5_hash = Form(StringField(required=False, description='md5 of uploaded file'))
):
    return {
        'submitted_md5': md5_hash,
        'file': {
            'name': upload_file.name,
            'size': upload_file.size,
            'md5': md5(upload_file.read()).hexdigest,
        },
    }
```
    '''
    return {
        'submitted_md5': md5_hash,
        'file': {
            'name': upload_file.name,
            'size': upload_file.size,
            'md5': md5(upload_file.read()).hexdigest(),
        },
    }

class SamplePayload(BaseModel):
    arg1 = StringField(min_length=3, max_length=10)
    arg2 = NumberField(gte=0, lte=10, multiple_of=1)
    arg3 = BooleanField(default_value=False)

class SampleResponse(BaseModel):
    obj = ObjectField(SamplePayload)
    ary = ArrayField(ObjectField(SamplePayload))

@api.post(
    '/post_request_with_json_schema_body',
    tags=['1. Basic HTTP requests'],
    summary='Define body parameters via JSON schema model',
    response_model=SampleResponse,
)
def post_request_with_json_schema_body(payload=Body(SamplePayload)):
    '''
The JSON schema fields could also be used for describing JSON body format,
all you need is declearing a class inherited from BaseModel class.

```python
from django_openapi import Body
from django_openapi.schema import BaseModel, StringField, NumberField, BooleanField

class SamplePayload(BaseModel):
    arg1 = StringField(min_length=3, max_length=10)
    arg2 = NumberField(gte=0, lte=10, multiple_of=1)
    arg3 = BooleanField(default_value=False)

class SampleResponse(BaseModel):
    obj = ObjectField(SamplePayload)  # Object (dict in JSON) type field
    ary = ArrayField(ObjectField(SamplePayload))  # Array type field

@api.post(
    '/post_request_with_json_schema_body',
    response_model=SampleResponse,  # you can also put json schema model here for declearing response model
)
def post_request_with_json_schema_body(
    payload=Body(SamplePayload),
):
    return payload
```
    '''
    return {'obj': payload, 'ary': [payload, payload]}

@api.post(
    '/some_special_variables_by_name',
    tags=['1. Basic HTTP requests'],
    summary='Some special variables',
)
def some_special_variables_by_name(request, session, cookie_jar):
    '''
You could access some special variables via your function parameter name.

* `request`

  * the django `HttpRequest` object

* `session`

  * the session object binded on request

* `cookie_jar`

  * if you want to set/del cookies on the response object, you must use cookie_jar
  * cookie_jar is a proxy object to real HttpResponse object. The `set_cookie()`, `delete_cookie()` functions on it have the same signatures of HttpResonse.

```python
@api.get(
    '/some_special_variables_by_name',
)
def some_special_variables_by_name(request, session, cookie_jar):

    # this has the same signature as django HTTPResponse.set_cookie() function
    cookie_jar.set_cookie('test_cookie', str(datetime.now()))

    return {
        'request': request,
        'session': session,
    }
```
    '''

    # this has the same signature as django HTTPResponse.set_cookie() function
    cookie_jar.set_cookie('test_cookie', str(datetime.now()))

    return {
        'request': repr(request),
        'session': session,
    }

@api.post(
    '/other_argument_data_sources',
    tags=['1. Basic HTTP requests'],
    summary='Other argument data sources',
)
def other_argument_data_sources(
    test_cookie=Cookie(), content_type=Header(), http_referer=Header()
):
    '''
You can also get your request arguments from other data sources.

Like: `Header()`, `Cookie()`

* *Note: While accessing via `Header()`, all variable name will converted to uppercase as http header key name*
* *e.g.: `content_type` -> `CONTENT_TYPE`

```python
@api.post(
    '/other_argument_data_sources',
)
def other_argument_data_sources(
    test_cookie=Cookie(), content_type=Header(), http_referer=Header()
):
    return {
        'test_cookie': test_cookie,
        'content_type': content_type,
        'referrer': http_referer,
    }
```
    '''
    return {
        'test_cookie': test_cookie,
        'content_type': content_type,
        'referrer': http_referer,
    }


import logging

import falcon

from freezer_api.common._i18n import _

class FreezerAPIException(falcon.HTTPError):
    """
    Base Freezer API Exception
    """
    message = "unknown error"

    def __init__(self, message=''):
        if message:
            self.message = _(str(message))  # noqa
        logging.error(message)
        Exception.__init__(self, message)

    @staticmethod
    def handle(ex, req, resp, params):
        raise falcon.HTTPError(_('500 unknown server error'),
                               title=_("Internal Server Error"),
                               description=FreezerAPIException.message)

class BadDataFormat(FreezerAPIException):
    @staticmethod
    def handle(ex, req, resp, params):
        raise falcon.HTTPBadRequest(
            title=_("Bad request format"),
            description=ex.message)

class DocumentExists(FreezerAPIException):
    @staticmethod
    def handle(ex, req, resp, params):
        raise falcon.HTTPConflict(
            title=_("Document already existing"),
            description=ex.message)

class StorageEngineError(FreezerAPIException):
    @staticmethod
    def handle(ex, req, resp, params):
        raise falcon.HTTPInternalServerError(
            title=_("Internal Storage Error"),
            description=ex.message)

class DocumentNotFound(FreezerAPIException):
    @staticmethod
    def handle(ex, req, resp, params):
        raise falcon.HTTPError(
            status=falcon.HTTP_404,
            title=_("Not Found"),
            description=ex.message)

class AccessForbidden(FreezerAPIException):
    @staticmethod
    def handle(ex, req, resp, params):
        raise falcon.HTTPForbidden(
            title=_("Access Forbidden"),
            description="You are not allowed to access this resource")

class MethodNotImplemented(FreezerAPIException):
    @staticmethod
    def handle(ex, req, resp, params):
        raise falcon.HTTPMethodNotAllowed(
            title=_("Bad Method"),
            description=ex.message,
            allowed_methods=['GET', 'POST', 'HEAD', 'PATCH', 'DELETE'])

exception_handlers_catalog = [
    BadDataFormat,
    DocumentExists,
    StorageEngineError,
    DocumentNotFound,
    AccessForbidden,
    MethodNotImplemented
]


import numpy as np
A = [[-0.2,-1,0.6],[5.0,1.0,-0.7],[1.0,0,-3.0]]
B = [[1],[0],[0]]; C = [0.5,0.5,0.5]; D = [0]
print(np.linalg.eig(A)[0])

from scipy import signal
sys1 = signal.StateSpace(A,B,C,D)
t1,y1 = signal.step(sys1)

import matplotlib.pyplot as plt
plt.figure(1)
plt.plot(t1,y1,'r-',label='y')
plt.legend()
plt.xlabel('Time')
plt.show()


from question_model import Question
from data import question_data
from quiz_brain import QuizBrain

question_bank = [
    Question(question["text"], question["answer"]) for question in question_data
]

quiz_brain = QuizBrain(question_bank)

while quiz_brain.still_has_questions():
    answer = quiz_brain.next_question()

print(f"You Scored {quiz_brain.user_score} points out of {quiz_brain.quiz_length} possible")


import json
import time
from Data.DataProvider import DataProvider
from Models.Optional import ACC
from Models.Variant import Variant

# timer
start_time = time.time()

data_provider = DataProvider()
agr = data_provider.baumuster
basic_qvv = agr.basic_variant()

inconsistent_codes = []
acc_fixed = []
acc_optionals = []

for code in basic_qvv.codes:
    acc = data_provider.acc_list.find_acc(code)
    if acc is None:
        inconsistent_codes.append(code)
    elif not acc.optionals:
        acc_fixed.append(acc)
    else:
        cu = []
        for opt in acc.optionals:
            if agr.contains_code(opt):
                cu.append(opt)

        new_acc = ACC(code, cu)
        if not new_acc.optionals:
            acc_fixed.append(new_acc)
        else:
            acc_optionals.append(new_acc)

basic_combination = []
for acc in acc_fixed:
    basic_combination.append(acc.id)

combinations = [basic_combination]

for acc in acc_optionals:
    swap_list = [acc.id]
    for id in acc.optionals:
        swap_list.append(id)

    new_combinations = []
    for combination in combinations:
        for code in swap_list:
            new_combination = combination.copy()
            new_combination.append(code)
            new_combinations.append(new_combination)

    combinations = new_combinations

qvv_list = []
for index, combination in enumerate(combinations):
    name = 'QVV'+str(index+1)
    qvv = Variant(name, combination)
    qvv_list.append(qvv)

j = json.dumps([qvv.__dict__ for qvv in iter(qvv_list)])
with open('output.json', 'w') as file:
    file.write(j)

print('\n--------- ERROS ----------')
for code in inconsistent_codes:
    print('{} - Não disponível nos ACCs'.format(code))

print('\n--------- FIXO ----------')
print([acc.id for acc in iter(acc_fixed)])

print('\n--------- OPCIONAIS ----------')
for acc in acc_optionals:
    print('{} - {}'.format(acc.id, str(acc.optionals)))

print('\n--------- TEMPO DE EXECUCAO ----------')
print("%s segundos" % (time.time() - start_time))


from flask import request, jsonify
from datetime import datetime

from flask_restful import Resource
from schema.feedback import feedback_schema, feedbacks_schema
from models.feedback import FeedbackModel
from models.user import UsersModel
from db import db
from flask_jwt_extended import jwt_required, get_jwt_identity
from schema.user import users_schema

class FeedbacksResource(Resource):
    @jwt_required
    def get(self, feedback_id):
        id = feedback_id
        feedback = FeedbackModel.query.get(id)
        if not feedback:
            return {"message": "Not found User"}, 404
        result = feedback_schema.dump(feedback)
        return jsonify(result)

    @jwt_required
    def put(self, feedback_id):
        id = feedback_id
        user_from_token = get_jwt_identity()
        current_user = UsersModel.query.filter_by(
            email=user_from_token).first()
        feed_back = FeedbackModel.query.get(id)
        if not feed_back:
            return {"message": "Not found Feeback"}, 404
        if current_user.id == feed_back.owner_id:
            comment = request.json['comment']
            rating = request.json['rating']
            feed_back.comment = comment
            feed_back.rating = rating
            db.session.commit()
            result = feedback_schema.dump(feed_back)
            return jsonify(result)

        return {"error": " You Dont have previlege to update other users feedback"}, 403

    @jwt_required
    def delete(self, feedback_id):
        id = feedback_id
        user_from_token = get_jwt_identity()
        current_user = UsersModel.query.filter_by(
            email=user_from_token).first()
        feed_back = FeedbackModel.query.get(id)
        if not feed_back:
            return {"message": "Not found Feeback"}, 404
        if current_user.id == feed_back.owner_id:

            db.session.delete(feed_back)
            db.session.commit()
            return{"message": " Successfully deleted."}, 200

        return {"error": " You Dont have previlege to delete other users feedback"}, 403

class FeedbacksList(Resource):
    @jwt_required
    def get(self):
        feedback = FeedbackModel.query.all()
        result = feedbacks_schema.dump(feedback)
        return {"data": result}

class Feedbacks(Resource):
    @jwt_required
    def post(self, id):
        user_from_token = get_jwt_identity()
        ticket_id = id
        user = UsersModel.query.filter_by(email=user_from_token).first()
        ticket = UsersModel.query.filter_by(id=ticket_id).first()
        if not ticket:
            return {'error': 'Not found ticket '}, 404

        comment = request.json['comment']
        rating = request.json['rating']
        user_id = user.id
        created_at = str(datetime.now())
        new_feedback = FeedbackModel(
            comment=comment, rating=rating, created_at=created_at, owner_id=user_id, ticket_id=ticket_id)
        db.session.add(new_feedback)
        db.session.commit()
        return {"message": "Thank You Saved !"}

class SingleUserFeedback(Resource):
    @jwt_required
    def get(self):
        user_from_token = get_jwt_identity()
        current_user = UsersModel.query.filter_by(
            email=user_from_token).first()
        user_id = current_user.id
        payment = FeedbackModel.query.filter_by(owner_id=user_id).all()
        result = feedbacks_schema.dump(payment)
        return jsonify(result=result)


__author__ = 'Kazem'
import csv
import os
import glob
from os.path import isfile, join
import sys
import getopt
import collections
import matplotlib.pyplot as plt
import numpy as np
import fnmatch
import pandas as pd
from enum import Enum
from matplotlib.font_manager import FontProperties
from matplotlib import colors as mcolors
from os.path import basename
from operator import itemgetter, attrgetter, methodcaller
from osqp_utils import compute_failure_rates,compute_performance_profiles,plot_performance_profiles,\
    exclude_items,compute_speedup,exclude_items_general

INV='N/A'

def dir_contents(path, type):
    matches = []
    for root, dirnames, filenames in os.walk(path):
        for filename in fnmatch.filter(filenames, '*.'+ type):
            matches.append(os.path.join(root, filename))
    return matches

class solver_time:
    def __init__(self):
        self.fact_time = np.array([])
        self.analysis_time = np.array([])
        self.ordering_time = np.array([])
        self.solve_time = np.array([])
        self.refine_time = np.array([])

class MatrixRecord:
    def __init__(self, matrix_name='', nnz=0, dim1=0, dim2=0,
                 nnz_l=0, ordering_method='',
                 tree_height=0, norm2=0.0, residual=0.0, bwd_error=0.0, fwd_error=0.0):
        self.matrix_name = matrix_name
        self.nnz = nnz
        self.dim1 = dim1
        self.dim2 = dim2
        self.nnz_l = nnz_l
        self.ordering_method = ordering_method
        self.parallel_time = solver_time()
        self.serial_time = solver_time()
        self.tree_height = tree_height
        self.norm2 = norm2
        self.residual = residual
        self.bwd_error = bwd_error
        self.fwd_error = fwd_error

class RunRecord:
    def __init__(self, tool_name='', target_name='', num_thread=0):
        self.tool_name = tool_name
        self.num_thread = num_thread
        self.target_name = target_name
        self.mat_rec_list = []

OPTIMAL = 'optimal'
MAX_VAL = 1600
class Visualizer:

    def __init__(self, path):
        self.path = path
        self.run_rec_list = []
        self.headerList = []
        self.empty_dic = []
        self.font0 = FontProperties()
        self.qp2size = {}
        self.sympiler_header = ['Matrix Name', 'Row', 'Col', 'Nonzero', 'Factor Nonzero',
                                'Ordering Time (sec)', 'Analysis Time (sec)',
                                'Factorization Time (sec)', 'Solve Time (sec)',
                                'Iterative Refinement Time (sec)',
                                'Error Norm2-Before', 'Rel Error Norm2-Before',
                                'Infinity Norm-Before', 'BWD Error-Before', 'Residual-Before',
                                'Number of Threads',
                                'Target Name', 'Total Time (sec)', 'Tool Name',
                                'Iterative Refinement Method', 'Chunk Size',
                                'Error Norm2-After', 'Rel Error Norm2-After',
                                'Infinity Norm-After', 'BWD Error-After', 'Residual-After',
                                'Number of W-partition', 'Initial Cut', 'BLAS Threads',
                                'Final Cuts', 'Height', 'Number of Supernodes', 'Number of Pivots',
                                'Precision-Before', 'Precision-After', 'Number of Refinement Iterations',
                                'Factorization (GFLOPS)'
                                ]
        self.qp_header = ['Tool Name',
                           'Problem Name', 'Time (s)', 'Residual Lagrangian inf',
                          'Constraint Satisfaction Inf',
                          'Status', 'Problem Size', 'Hessian NNZ', 'Eq Constraint NNZ',
                          'Ineq Constraint NNZ', 'Outer GMRES Iter', 'GMRES Tol', 'Diagonal Pert', 'eps_abs',
                          'Inner GMRES Iter', 'Hessian dim','Non-negativity Inf','Complementarity Inf',
                          'Problem Type', 'Hessian dim', '# of Ineq Const', '# of Eq Constraints'
                                ]
    class LogHeader(Enum):
        MATN = 0
        ROW = 1
        COL = 2
        NNZ = 3
        NNZL = 4
        ORDT = 5
        ANAT = 6
        FACT = 7
        SOLT = 8
        ITERT = 9
        NRM1 = 10
        NRM2 = 11
        NRMI = 12
        BWDE = 13
        RESD = 14
        THRN = 15
        TRGT = 16
        TOTT = 17
        TOOL = 18
        IREF = 19
        CHNK = 20
        NR1A = 21
        NR2A = 22
        NRIA = 23
        BWEA = 24
        REDA = 25
        WPAR = 26
        ICUT = 27
        BLAS = 28
        FCUT = 29
        HGHT = 30
        SUPN = 31
        NPIV = 32
        PREC = 33
        PREA = 34
        NREF = 35
        FLPS = 36

    class qp_log_header(Enum):
        TOOLN = 0
        PROBN = 1
        STIME = 2
        LRNRM = 3
        CSNRM = 4
        STATS = 5
        PROBS = 6
        HSSNZ = 7
        CNSNZ = 8
        INQNZ = 9
        INIR = 10
        TOLIR = 11
        PERTB = 12
        EPSAB = 13
        OUTIR = 14
        HSSDM = 15
        NGINF = 16
        CMINF = 17
        CLSTY = 18
        PROBD = 19
        CNSID = 20
        CNSED = 21
        INVAL = 100

    def read_csv(self, report_path):
        #report = RunRecord()
        report = []
        with open(report_path) as csvFile:
            reader = csv.DictReader(csvFile)
            # cur_row = MatrixRecord()
            self.headerList = reader.fieldnames
            for row in reader:
                report.append(row)
        if len(report) > 0:
            self.empty_dic = report[0].copy()
            for key, value in self.empty_dic.items():
                self.empty_dic[key] = ''
        return report

    def fact_time_sympiler(self, sym_report_path, cmp_idx=LogHeader.FACT.value):
        mat_list = []
        sym_report = self.read_csv(sym_report_path)
        i1 = 0
        sw = True
        nxt_mat = ''
        while i1 < len(sym_report):
            sr = sym_report[i1]
            cur_mat = sr[self.sympiler_header[self.LogHeader.MATN.value]]  # matrix name
            i2 = 0
            if i1 + 1 < len(sym_report):
                nxt_mat = sym_report[i1 + 1][self.sympiler_header[self.LogHeader.MATN.value]]
            else:
                sw = False
            min_time = sys.maxsize
            min_idx = 0
            while cur_mat == nxt_mat and sw:
                cur_time = float(nxt_mat[self.sympiler_header[cmp_idx]])
                if min_time > cur_time:
                    min_time = cur_time
                    min_idx = i2
                i2 += 1
            mat_list.append(sym_report[i1 + min_idx])
            i1 += (i2 + 1)
        return mat_list

    def fact_time_mkl(self, mkl_report_path):
        mat_list = []
        new_dic = []
        file_token = 'Matrix Name***'
        time_afs = 'Total time spent'
        time_solve = 'Time spent in direct solver at solve step (solve)'
        extra_info_s = '+++extrainfo:'
        sup_node = 'number of supernodes:'
        iter_refine = 'Time spent in additional calculations'
        file_found = False
        analysis_time = False
        fact_time = False
        solve_time = False
        iter_ref_Time = False
        super_node = False
        extra_info = False
        #log = os.popen(mkl_report_path)
        f = open(mkl_report_path, "r")
        log = f.read()
        totoal_time = 0
        for line in log.splitlines(True):
            if not file_found:
                idx_f = line.find(file_token)
                if idx_f >= 0:
                    file_found = True
                    totoal_time = 0
                    new_dic = self.empty_dic.copy()
                    new_dic[self.sympiler_header[self.LogHeader.TOOL.value]] = 'MKL Pardiso'
                    mat_full_name = line.split()[2].split('/')
                    mat_name = mat_full_name[len(mat_full_name)-1].split('.')[0]
                    new_dic[self.sympiler_header[self.LogHeader.MATN.value]] = mat_name
                    continue
            if file_found and not analysis_time:
                idx_f = line.find(time_afs)
                if idx_f >= 0:
                    analysis_time = True
                    a_time = line.split()[4]
                    totoal_time += float(a_time)
                    new_dic[self.sympiler_header[self.LogHeader.ANAT.value]] = a_time
                    continue
            if analysis_time and not fact_time:
                idx_f = line.find(time_afs)
                if idx_f >= 0:
                    fact_time = True
                    a_time = line.split()[4]
                    totoal_time += float(a_time)
                    new_dic[self.sympiler_header[self.LogHeader.FACT.value]] = a_time
                    continue
            if fact_time and not solve_time:
                idx_f = line.find(time_solve)
                if idx_f >= 0:
                    solve_time = True
                    a_time = line.split()[10]
                    totoal_time += float(a_time)
                    new_dic[self.sympiler_header[self.LogHeader.SOLT.value]] = a_time
                    continue
            if solve_time and not iter_ref_Time:
                idx_f = line.find(iter_refine)
                if idx_f >= 0:
                    iter_ref_Time = True
                    a_time = line.split()[6]
                    totoal_time += float(a_time)
                    new_dic[self.sympiler_header[self.LogHeader.ITERT.value]] = a_time
                    continue
            if iter_ref_Time and not super_node:
                idx_f = line.find(sup_node)
                if idx_f >= 0:
                    super_node = True
                    tmp_buf = line.split()[3]
                    new_dic[self.sympiler_header[self.LogHeader.SUPN.value]] = tmp_buf
                    continue
            if super_node and not extra_info:
                idx_f = line.find(extra_info_s)
                if idx_f >= 0:
                    file_found = False
                    analysis_time = False
                    fact_time = False
                    solve_time = False
                    super_node = False
                    iter_ref_Time = False
                    super_node = False
                    tmp_buf = line.split(':')[1].split(',')
                    totoal_time += float(tmp_buf[0])
                    new_dic[self.sympiler_header[self.LogHeader.TOTT.value]] = str(totoal_time)
                    new_dic[self.sympiler_header[self.LogHeader.ORDT.value]] = tmp_buf[0]
                    new_dic[self.sympiler_header[self.LogHeader.NNZL.value]] = tmp_buf[1]
                    new_dic[self.sympiler_header[self.LogHeader.FLPS.value]] = tmp_buf[2]
                    new_dic[self.sympiler_header[self.LogHeader.ROW.value]] = tmp_buf[3]
                    new_dic[self.sympiler_header[self.LogHeader.NREF.value]] = tmp_buf[4]
                    new_dic[self.sympiler_header[self.LogHeader.NNZ.value]] = tmp_buf[5]
                    new_dic[self.sympiler_header[self.LogHeader.THRN.value]] = tmp_buf[6]
                    new_dic[self.sympiler_header[self.LogHeader.NRM1.value]] = tmp_buf[7]
                    new_dic[self.sympiler_header[self.LogHeader.NRM2.value]] = tmp_buf[8]
                    new_dic[self.sympiler_header[self.LogHeader.NRMI.value]] = tmp_buf[9]
                    new_dic[self.sympiler_header[self.LogHeader.NR1A.value]] = tmp_buf[7]
                    new_dic[self.sympiler_header[self.LogHeader.NR2A.value]] = tmp_buf[8]
                    new_dic[self.sympiler_header[self.LogHeader.NRIA.value]] = tmp_buf[9]
                    new_dic[self.sympiler_header[self.LogHeader.TRGT.value]] = tmp_buf[10]
                    #updating analysis time
                    anal_time = float(new_dic[self.sympiler_header[self.LogHeader.ANAT.value]])
                    ord_time = float(new_dic[self.sympiler_header[self.LogHeader.ORDT.value]])
                    total_anal_time = anal_time + ord_time
                    new_dic[self.sympiler_header[self.LogHeader.ANAT.value]] = str(total_anal_time)
                    mat_list.append(new_dic)
        mat_list_sorte = sorted(mat_list,
                                key=itemgetter(self.sympiler_header[Visualizer.LogHeader.MATN.value]))

        return mat_list_sorte

    def read_sympiler_log(self, report_path, idx_eq, idx_sort, f_sort):
        sym_log = self.read_csv(report_path)
        red_log = self.list_reduction(sym_log, idx_eq, idx_sort, f_sort)
        # extracting matrix name from the path
        for i in range(len(red_log)):
            full_name = red_log[i][self.sympiler_header[self.LogHeader.MATN.value]]
            mat_full_name = full_name.split('/')
            mat_name = mat_full_name[len(mat_full_name) - 1].split('.')[0]
            red_log[i][self.sympiler_header[self.LogHeader.MATN.value]] = mat_name
        red_sort_log = sorted(red_log, key=itemgetter(self.sympiler_header[idx_eq]))

        return red_sort_log

    def read_qp_log(self, report_path, idx_eq, idx_min=qp_log_header.INVAL, tol=1e-12):
        sym_log = self.read_csv(report_path)
        red_log = self.qp_lib_list_reduction(sym_log,idx_eq,idx_min,tol)
        #eee_tmp = self.qp_lib_list_reduction_2(sym_log,idx_eq,idx_min,tol)
        #return eee_tmp
        # extracting matrix name from the path
        for i in range(len(red_log)):
            full_name = red_log[i][self.qp_header[self.qp_log_header.PROBN.value]]
            mat_full_name = full_name.split('/')
            mat_name = mat_full_name[len(mat_full_name) - 1].split('.')[0]
            #mat_name = mat_name.split('_')
            us_pos = mat_name.rfind('_')
            if us_pos>0:
                mat_name = mat_name[0:us_pos]
            red_log[i][self.qp_header[self.qp_log_header.PROBN.value]] = mat_name
            psize = 0
            if not red_log[i][self.qp_header[self.qp_log_header.HSSNZ.value]] == INV:
                psize = int(red_log[i][self.qp_header[self.qp_log_header.HSSNZ.value]])
                #FIXME: remove this after the logs are fixed
                if "NASOQ" in red_log[i][self.qp_header[self.qp_log_header.TOOLN.value]]:
                    dim = int(red_log[i][self.qp_header[self.qp_log_header.HSSDM.value]])
                    psize = 2*psize - dim
            if not red_log[i][self.qp_header[self.qp_log_header.CNSNZ.value]] == INV:
                psize += int(red_log[i][self.qp_header[self.qp_log_header.CNSNZ.value]])
            if not red_log[i][self.qp_header[self.qp_log_header.INQNZ.value]] == INV:
                psize += int(red_log[i][self.qp_header[self.qp_log_header.INQNZ.value]])
            red_log[i][self.qp_header[self.qp_log_header.PROBS.value]] = psize

        red_sort_log = sorted(red_log, key=itemgetter(self.qp_header[idx_eq.value]))
        return red_sort_log

    def qp_lib_list_reduction(self,list_log, idx_eq,idx_min, tol):
        min_time = 1e8
        red_sort_log = sorted(list_log, key=itemgetter(self.qp_header[idx_eq.value]))
        reduced_list = []
        if len(list_log) <= 1:
            return list_log
        tmp_list = []
        tmp_sort = np.array([])
        i = 0
        r_i = 0 # num of reduced elements
        while i < len(red_sort_log):
            num_rep = 0
            cur_prob = red_sort_log[i][self.qp_header[idx_eq.value]]
            sat_norm = float(red_sort_log[i][self.qp_header[self.qp_log_header.CSNRM.value]])
            lag_norm = float(red_sort_log[i][self.qp_header[self.qp_log_header.LRNRM.value]])
            comp_norm = float(red_sort_log[i][self.qp_header[self.qp_log_header.CMINF.value]])
            nng_norm = float(red_sort_log[i][self.qp_header[self.qp_log_header.NGINF.value]])
            min_time = float(red_sort_log[i][self.qp_header[idx_min.value]])
            status = red_sort_log[i][self.qp_header[self.qp_log_header.STATS.value]]
            if sat_norm < tol and lag_norm < tol and min_time < MAX_VAL and nng_norm < tol  \
                    and (status == 'solved' or status == '1' or status == 'The optimality conditions are satisfied'):
                red_sort_log[i][self.qp_header[self.qp_log_header.STATS.value]] = OPTIMAL
            else:
                min_time = 1e8
                red_sort_log[i][self.qp_header[self.qp_log_header.STATS.value]] = 'Not converged'
            tmp_list.append(red_sort_log[i])
            if i+1 < len(red_sort_log):
                nxt_prob = red_sort_log[i+1][self.qp_header[idx_eq.value]]
            else:
                break;
            i = i+1
            while cur_prob == nxt_prob:
                nxt_time = float(red_sort_log[i][self.qp_header[idx_min.value]])
                nxt_sat_norm = float(red_sort_log[i][self.qp_header[self.qp_log_header.CSNRM.value]])
                nxt_lag_norm = float(red_sort_log[i][self.qp_header[self.qp_log_header.LRNRM.value]])
                if sat_norm < tol and lag_norm < tol and min_time < MAX_VAL and nng_norm < tol  \
                    and (status == 'solved' or status == '1'):
                    min_time = nxt_time
                    red_sort_log[i][self.qp_header[self.qp_log_header.STATS.value]] = OPTIMAL
                    tmp_list[r_i] = red_sort_log[i]
                i = i+1
                if i < len(red_sort_log):
                    nxt_prob = red_sort_log[i][self.qp_header[idx_eq.value]]
                else:
                    break
            r_i = r_i + 1
        return tmp_list

    def compute_qp_size(self, red_log):
        psize = 0
        if not red_log[self.qp_header[self.qp_log_header.HSSNZ.value]] == INV:
            psize = int(red_log[self.qp_header[self.qp_log_header.HSSNZ.value]])
        if not red_log[self.qp_header[self.qp_log_header.CNSNZ.value]] == INV:
            psize += int(red_log[self.qp_header[self.qp_log_header.CNSNZ.value]])
        if not red_log[self.qp_header[self.qp_log_header.INQNZ.value]] == INV:
            psize += int(red_log[self.qp_header[self.qp_log_header.INQNZ.value]])
        red_log[self.qp_header[self.qp_log_header.PROBS.value]] = psize
        return psize

    def find_problem_size(self, report_path, idx_eq, idx_min=qp_log_header.INVAL,
                          tol=1e-6, tol_str='1e-06', class_type=["All"]):
        prt_str = self.qp_header[self.qp_log_header.PERTB.value]
        ir_in = self.qp_header[self.qp_log_header.INIR.value]
        ir_out = self.qp_header[self.qp_log_header.OUTIR.value]
        ir_tol = self.qp_header[self.qp_log_header.TOLIR.value]

        sym_log = self.read_csv(report_path)
        #        tn = sym_log['Tool Name']
        splited_log = []
        if len(class_type) == 1:
            if class_type[0] == "" or class_type[0] == "All":
                splited_log = self.qp_lib_list_split_byname(sym_log)
            else:
                splited_log = self.qp_lib_list_split_bycat(sym_log, class_type)
        else:
            splited_log = self.qp_lib_list_split_bycat(sym_log, class_type)
        #        if tn == 'NASOQ-auto':
        #            splited_log = sym_log
        red_tol_log = []
        for lst in splited_log:
            tt = lst[0][self.qp_header[self.qp_log_header.TOOLN.value]]
            if (lst[0]['eps_abs'] == tol_str and not tt == 'QL') or (lst[0]['eps_abs'] == tol_str and tt == 'QL'):
                lst1 = self.qp_lib_list_reduction(lst, idx_eq, idx_min, tol)
                for l in lst1:
                    tool_name = l[self.qp_header[self.qp_log_header.TOOLN.value]]
                    prt_str_val = l[prt_str]
                    ir_in_val = l[ir_in]
                    ir_out_val = l[ir_out]
                    ir_tol_val = l[ir_tol]
                    # tn = tool_name + '_' + prt_str_val + '_' + ir_out_val + '_' + ir_in_val + '_' + ir_tol_val
                    # tn = tn.split('/')[0]
                    tn = tool_name
                    l[self.qp_header[self.qp_log_header.TOOLN.value]] = tn
                red_tol_log.append(lst1)

        for red_log in red_tol_log:
            if len(red_log) > 0:
                if "OSQP-polished" not in red_log[0][self.qp_header[self.qp_log_header.TOOLN.value]]:
                    continue
            for i in range(len(red_log)):
                if "OSQP-polished" in red_log[i][self.qp_header[self.qp_log_header.TOOLN.value]]:
                    full_name = red_log[i][self.qp_header[self.qp_log_header.PROBN.value]]
                    mat_full_name = full_name.split('/')
                    mat_name = mat_full_name[len(mat_full_name) - 1].split('.')[0]
                    # mat_name = mat_name.split('_')
                    us_pos = mat_name.rfind('_')
                    if us_pos > 0:
                        mat_name = mat_name[0:us_pos]
                    self.qp2size[mat_name] = self.compute_qp_size(red_log[i])

    def read_qp_log_split(self, report_path, idx_eq, idx_min=qp_log_header.INVAL,
                          tol=1e-6, tol_str='1e-06', class_type=["All"]):
        prt_str = self.qp_header[self.qp_log_header.PERTB.value]
        ir_in = self.qp_header[self.qp_log_header.INIR.value]
        ir_out = self.qp_header[self.qp_log_header.OUTIR.value]
        ir_tol = self.qp_header[self.qp_log_header.TOLIR.value]

        sym_log = self.read_csv(report_path)
#        tn = sym_log['Tool Name']
        splited_log = []
        if len(class_type)==1:
            if class_type[0] == "" or class_type[0] == "All":
                splited_log = self.qp_lib_list_split_byname(sym_log)
            else:
                splited_log = self.qp_lib_list_split_bycat(sym_log, class_type)
        else:
            splited_log = self.qp_lib_list_split_bycat(sym_log,class_type)
#        if tn == 'NASOQ-auto':
#            splited_log = sym_log
        red_tol_log = []
        for lst in splited_log:
            tt = lst[0][self.qp_header[self.qp_log_header.TOOLN.value]]
            if (lst[0]['eps_abs'] == tol_str and not tt == 'QL') or (lst[0]['eps_abs'] == tol_str and tt == 'QL'):
                lst1 = self.qp_lib_list_reduction(lst, idx_eq, idx_min, tol)
                for l in lst1:
                    tool_name = l[self.qp_header[self.qp_log_header.TOOLN.value]]
                    prt_str_val = l[prt_str]
                    ir_in_val = l[ir_in]
                    ir_out_val = l[ir_out]
                    ir_tol_val = l[ir_tol]
                    #tn = tool_name + '_' + prt_str_val + '_' + ir_out_val + '_' + ir_in_val + '_' + ir_tol_val
                    #tn = tn.split('/')[0]
                    tn = tool_name
                    l[self.qp_header[self.qp_log_header.TOOLN.value]] = tn
                red_tol_log.append(lst1)

        # extracting matrix name from the path and seting size

        lst_i = 0
        for red_log in red_tol_log:
            for i in range(len(red_log)):
                full_name = red_log[i][self.qp_header[self.qp_log_header.PROBN.value]]
                mat_full_name = full_name.split('/')
                mat_name = mat_full_name[len(mat_full_name) - 1].split('.')[0]
                #mat_name = mat_name.split('_')
                us_pos = mat_name.rfind('_')
                if us_pos>0:
                    mat_name = mat_name[0:us_pos]
                red_log[i][self.qp_header[self.qp_log_header.PROBN.value]] = mat_name
                psize = self.qp2size[mat_name]
                red_log[i][self.qp_header[self.qp_log_header.PROBS.value]] = psize
                # if not red_log[i][self.qp_header[self.qp_log_header.HSSNZ.value]] == INV:
                #     psize = int(red_log[i][self.qp_header[self.qp_log_header.HSSNZ.value]])
                #     # FIXME: remove this after the logs are fixed
                #     if "NASOQ" in red_log[i][self.qp_header[self.qp_log_header.TOOLN.value]] or \
                #             "MOSEK" in red_log[i][self.qp_header[self.qp_log_header.TOOLN.value]] or \
                #             "OSQP" in red_log[i][self.qp_header[self.qp_log_header.TOOLN.value]] or \
                #             "QL" in red_log[i][self.qp_header[self.qp_log_header.TOOLN.value]]:
                #         dim = int(red_log[i][self.qp_header[self.qp_log_header.HSSDM.value]])
                #         psize = 2 * psize - dim
                # if not red_log[i][self.qp_header[self.qp_log_header.CNSNZ.value]] == INV:
                #     psize += int(red_log[i][self.qp_header[self.qp_log_header.CNSNZ.value]])
                # if not red_log[i][self.qp_header[self.qp_log_header.INQNZ.value]] == INV:
                #     psize += int(red_log[i][self.qp_header[self.qp_log_header.INQNZ.value]])
                # red_log[i][self.qp_header[self.qp_log_header.PROBS.value]] = psize

            red_tol_log[lst_i] = sorted(red_log, key=itemgetter(self.qp_header[idx_eq.value]))
            lst_i = lst_i+1
        return red_tol_log

    def qp_lib_list_split(self, list_log):
        splitted = []
        prt_str = self.qp_header[self.qp_log_header.PERTB.value]
        eps = self.qp_header[self.qp_log_header.EPSAB.value]
        ir_in = self.qp_header[self.qp_log_header.INIR.value]
        ir_out = self.qp_header[self.qp_log_header.OUTIR.value]
        ir_tol = self.qp_header[self.qp_log_header.TOLIR.value]
        df = pd.DataFrame(list_log)
        gb = df.groupby([eps, prt_str, ir_in, ir_out, ir_tol])
        gbg = [gb.get_group(x) for x in gb.groups]
        for g in gbg:
            tmp = []
            for idx in g.index:
                tmp.append(list_log[idx])
            splitted.append(tmp)
        return splitted

    def qp_lib_list_split_byname(self, list_log):
        splitted = []
        eps = self.qp_header[self.qp_log_header.EPSAB.value]
        tool_str = self.qp_header[self.qp_log_header.TOOLN.value]
        df = pd.DataFrame(list_log)
        gb = df.groupby([eps, tool_str])
        gbg = [gb.get_group(x) for x in gb.groups]
        for g in gbg:
            tmp = []
            for idx in g.index:
                tmp.append(list_log[idx])
            splitted.append(tmp)
        return splitted

    def qp_lib_list_split_bycat(self, list_log, class_type):
        splitted = []
        reduced_logs = []
        eps = self.qp_header[self.qp_log_header.EPSAB.value]
        tool_str = self.qp_header[self.qp_log_header.TOOLN.value]
        prob_type = self.qp_header[self.qp_log_header.CLSTY.value]

        for s in list_log:
            tmp = s[prob_type]
            for ct in class_type:
                if tmp == ct:
                    reduced_logs.append(s)

        df = pd.DataFrame(reduced_logs)
        gb = df.groupby([eps, tool_str])
        gbg = [gb.get_group(x) for x in gb.groups]
        for g in gbg:
            tmp = []
            for idx in g.index:
                tmp.append(reduced_logs[idx])
            splitted.append(tmp)
        return splitted

    def qp_lib_list_reduction_2(self,list_log, idx_eq,idx_min, tol):
        min_time = 1e8
        red_sort_log = sorted(list_log, key=itemgetter(self.qp_header[idx_eq.value]))
        reduced_list = []
        if len(list_log) <= 1:
            return list_log
        tmp_list = []
        tmp_sort = np.array([])
        i = 0
        r_i = 0 # num of reduced elements
        while i < len(red_sort_log):
            num_rep = 0
            cur_prob = red_sort_log[i][self.qp_header[idx_eq.value]]
            sat_norm = float(red_sort_log[i][self.qp_header[self.qp_log_header.CSNRM.value]])
            lag_norm = float(red_sort_log[i][self.qp_header[self.qp_log_header.LRNRM.value]])
            min_time = float(red_sort_log[i][self.qp_header[idx_min.value]])
            psize = int(red_sort_log[i][self.qp_header[self.qp_log_header.HSSNZ.value]])
            psize = psize + int(red_sort_log[i][self.qp_header[self.qp_log_header.INQNZ.value]])
            psize = psize + int(red_sort_log[i][self.qp_header[self.qp_log_header.CNSNZ.value]])

            if sat_norm < tol and lag_norm < tol and min_time < 1e3:
                red_sort_log[i][self.qp_header[self.qp_log_header.STATS.value]] = 'optimal'
            else:
                min_time = 1e8
                red_sort_log[i][self.qp_header[self.qp_log_header.STATS.value]] = 'Not converged'
            tmp_list.append(red_sort_log[i])
            if i+1 < len(red_sort_log):
                nxt_prob = red_sort_log[i+1][self.qp_header[idx_eq.value]]
            else:
                break;
            i = i+1
            while cur_prob == nxt_prob:
                nxt_time = float(red_sort_log[i][self.qp_header[idx_min.value]])
                nxt_sat_norm = float(red_sort_log[i][self.qp_header[self.qp_log_header.CSNRM.value]])
                nxt_lag_norm = float(red_sort_log[i][self.qp_header[self.qp_log_header.LRNRM.value]])
                psize = int(red_sort_log[i][self.qp_header[self.qp_log_header.HSSNZ.value]])
                psize = psize + int(red_sort_log[i][self.qp_header[self.qp_log_header.INQNZ.value]])
                psize = psize + int(red_sort_log[i][self.qp_header[self.qp_log_header.CNSNZ.value]])
                #if nxt_sat_norm < tol and nxt_lag_norm < tol and nxt_time < 1000:
                if nxt_sat_norm < tol and nxt_lag_norm < tol and nxt_time < MAX_VAL :
                    min_time = nxt_time
                    red_sort_log[i][self.qp_header[self.qp_log_header.STATS.value]] = 'optimal'
                    tmp_list[r_i] = red_sort_log[i]
                i = i+1
                if i < len(red_sort_log):
                    nxt_prob = red_sort_log[i][self.qp_header[idx_eq.value]]
                else:
                    break
            r_i = r_i + 1
        rep = np.zeros((100, 17, 13))
        for irn in {0,1,2,3,4,5,6,7,8,9, 99}:
            for tol in range(15, 16):
                for pert in range(10, 11):
                    cur_tol = pow(10, -tol)
                    cur_pert = pow(10, -pert)
                    for i in range(len(red_sort_log)):
                        iter_noi = int(red_sort_log[i][self.qp_header[self.qp_log_header.INIR.value]])
                        diag_perti = float(red_sort_log[i][self.qp_header[self.qp_log_header.PERTB.value]])
                        toli = float(red_sort_log[i][self.qp_header[self.qp_log_header.TOLIR.value]])
                        statui = red_sort_log[i][self.qp_header[self.qp_log_header.STATS.value]]
                        if statui == "optimal" and iter_noi == irn and diag_perti == cur_pert and toli == cur_tol:
                            rep[irn, tol, pert] = rep[irn, tol, pert] + 1

        # for irn in {0,1,2,3,4,5,6,7,8,9, 99}:
        #     for tol in range(15, 16):
        #         for pert in range(7, 12):
        #             print(irn , ", ", tol, ", ", pert, ", ", rep[irn, tol, pert])

        rep2 = np.zeros(13)
        for pert in range(1, 12):
            cur_pert = pow(10, -pert)
            for i in range(len(red_sort_log)):
                diag_perti = float(red_sort_log[i][self.qp_header[self.qp_log_header.PERTB.value]])
                statui = red_sort_log[i][self.qp_header[self.qp_log_header.STATS.value]]
                if statui == "optimal"  and diag_perti == cur_pert:
                    rep2[ pert] = rep2[pert] + 1
        for pert in range(7, 12):
            print( pert, ", ", rep2[ pert])
        return red_sort_log

    def qp_log_export(self, log_list, problems_type):
        num_converged = 0
        avg_solve = 0
        perf_profile = []
        tool_name = log_list[0][self.qp_header[self.qp_log_header.TOOLN.value]]
        # file_name = os.path.join(".", "results", problems_type,tool_name,
        #                             "statistics.txt")
        file_name = "results_" + problems_type +"_" + tool_name + "_statistics.txt"
        f = open(file_name, "w")
        f.write(self.qp_header[self.qp_log_header.PROBN.value])
        f.write(",")
        f.write(self.qp_header[self.qp_log_header.TOOLN.value])
        f.write(",run_time")
        #f.write(self.qp_header[self.qp_log_header.STIME.value])
        f.write(",status")
        #f.write(self.qp_header[self.qp_log_header.STATS.value])
        f.write("\n")
        for el in log_list:
            f.write(el[self.qp_header[self.qp_log_header.PROBN.value]])
            f.write(",")
            f.write(el[self.qp_header[self.qp_log_header.TOOLN.value]])
            f.write(",")
            f.write(el[self.qp_header[self.qp_log_header.STIME.value]])
            f.write(",")
            f.write(el[self.qp_header[self.qp_log_header.STATS.value]])
            f.write("\n")
        f.close()
        return num_converged, avg_solve, perf_profile

    def qp_comp_export(self, log_list, problems_type):
        num_converged = 0
        avg_solve = 0
        perf_profile = []
        tool_name = log_list[0][self.qp_header[self.qp_log_header.TOOLN.value]]
        # file_name = os.path.join(".", "results", problems_type,tool_name,
        #                             "statistics.txt")
        file_name = "comp_" + problems_type +"_" + tool_name + "_statistics.txt"
        f = open(file_name, "w")
        f.write(self.qp_header[self.qp_log_header.PROBN.value])
        f.write(",")
        f.write(self.qp_header[self.qp_log_header.TOOLN.value])
        f.write(",Complementarity Inf")
        #f.write(self.qp_header[self.qp_log_header.STIME.value])
        #f.write(",status")
        #f.write(self.qp_header[self.qp_log_header.STATS.value])
        f.write("\n")
        for el in log_list:
            f.write(el[self.qp_header[self.qp_log_header.PROBN.value]])
            f.write(",")
            f.write(el[self.qp_header[self.qp_log_header.TOOLN.value]])
            f.write(",")
            f.write(el[self.qp_header[self.qp_log_header.CMINF.value]])
            f.write("\n")
        f.close()
        return num_converged, avg_solve, perf_profile

    def list_reduction(self, list_log, idx_eq, idx_sort, f_sort):
        '''
        :param list_log: The list of reports as a set of dictionaries
        :param idx_eq:
        :param idx_sort: The ind
        :param f_sort:
        :return: Remove duplicates that has the same idx_eq and take the one
        with best f_sort<idx_sort>()
        '''
        reduced_list = []
        if len(list_log) <= 1:
            return list_log
        tmp_list = []
        tmp_sort = np.array([])
        i = 0
        while i < len(list_log):
            num_rep = 0
            tmp_list.append(list_log[i])
            tmp_sort = np.concatenate((tmp_sort, [float(list_log[i][self.sympiler_header[idx_sort]])]))
            cur_mat_name = list_log[i][self.sympiler_header[idx_eq]]
            for j in range(i+1, len(list_log)):
                if cur_mat_name == list_log[j][self.sympiler_header[idx_eq]]:
                    # tmp_sort = np.concatenate((tmp_sort, list_log[j][self.sympiler_header[idx_sort]]))
                    tmp_sort = np.concatenate((tmp_sort, [float(list_log[j][self.sympiler_header[idx_sort]])]))
                    tmp_list.append(list_log[j])
                    num_rep += 1
                else:
                    break
            idx_fav = f_sort(tmp_sort)
            reduced_list.append(list_log[i + idx_fav])
            tmp_list.clear()
            tmp_sort = np.array([])
            i = i + num_rep + 1
        return reduced_list

    def compute_scattered(self, *list_args, idx_x, idx_y, idx_y2, y_label='',
                       file_name='', y_scale="linear"):
        if len(list_args) <= 0:
            print("Wrong lists to visualize.")
            return -1
        n_groups = len(list_args[0])
        tool_name = []

        for lst in list_args:
            if len(lst) != n_groups:
                print("Wrong lists to visualize.")
                return -1
            tool_name.append(lst[0][self.qp_header[self.qp_log_header.TOOLN.value]])
        num_tool = len(list_args)
        all_data = np.zeros((num_tool,n_groups))
        all_data_rel = np.zeros((num_tool, n_groups))
        mat_list = []
        lst_no = 0
        for lst in list_args:
            for d in range(len(lst)):
                if (lst[d][self.qp_header[idx_y2.value]]) == OPTIMAL:
                    all_data[lst_no, d] = lst[d][self.qp_header[idx_y.value]]
                else:
                    all_data[lst_no, d] = MAX_VAL
                if lst_no == 0:
                    mat_list.append(lst[d][self.qp_header[idx_x.value]])
            lst_no += 1

        #all_data_rel = f_val(all_data)
        # for dim in range(num_tool):
        #     all_data_rel[dim, :] = all_data[dim, :]/all_data[0, :]
        # for v in range(n_groups):
        #     print(mat_list[v],',',all_data[0,v],',',all_data[1,v])

        ## Preparing the graph info
        # Other colors: https://matplotlib.org/gallery/color/named_colors.html
        colors = ('red', 'skyblue', 'indigo', 'olive', 'slateblue', 'magenta',
                  'slategray', 'limegreen', 'maroon', 'teal', 'khaki', 'purple',
                  'r', 'c', 'm', 'y', 'k')
        markers = ('s', 'o', '+', "."	,"," ,"v"	,"^"	,"<"	,">"	,
                   "1","2"	,"3"	,"4"	,"8"	,"s"	,"p"	,"P"	)

        x_label = np.arange(1, len(mat_list) + 1)
        font_axis = self.font0.copy()
        fig = plt.figure(figsize=(20, 5))
        ax1 = fig.add_subplot(111)
        ax1.set_yscale('log')
        for i in range(num_tool):
            ax1.scatter(x_label, all_data[i, :], s=10, c=colors[i],
                        marker=markers[i], label=tool_name[i])
            #ax1.scatter(mat_list[:], all_data[1, :], s=10, c='r', marker="o", label=tool_name[1])
        font_axis.set_weight('black')  # ['light', 'normal', 'medium', 'semibold', 'bold', 'heavy', 'black']
        ax1.set_ylabel(y_label, fontsize=12, fontproperties=font_axis)
        #ax1.set_xticks(x_label,minor=True)
        #ax1.set_xticklabels(x_label, fontsize=12)
        plt.xticks(x_label,rotation=55)
        plt.legend(loc='upper right');
        plt.show()

    def compute_bar(self, *list_args, idx_x, idx_y, idx_y2, y_label='',
                       file_name='', y_scale="linear"):
        if len(list_args) <= 0:
            print("Wrong lists to visualize.")
            return -1
        n_groups = len(list_args[0])
        tool_name = []
        for lst in list_args:
            if len(lst) != n_groups:
                print("Wrong lists to visualize.")
                return -1
            tool_name.append(lst[0][self.qp_header[self.qp_log_header.TOOLN.value]])
        num_tool = len(list_args)
        all_data = np.zeros((num_tool,n_groups))
        all_data_rel = np.zeros((num_tool, n_groups))
        mat_list = []
        lst_no = 0
        for lst in list_args:
            for d in range(len(lst)):
                if (lst[d][self.qp_header[idx_y2.value]]) == OPTIMAL:
                    all_data[lst_no, d] = lst[d][self.qp_header[idx_y.value]]
                else:
                    all_data[lst_no, d] = MAX_VAL
                if lst_no == 0:
                    mat_list.append(lst[d][self.qp_header[idx_x.value]])
            lst_no += 1

        #all_data_rel = f_val(all_data)
        # for dim in range(num_tool):
        #     all_data_rel[dim, :] = all_data[dim, :]/all_data[0, :]
        # for v in range(n_groups):
        #     print(mat_list[v],',',all_data[0,v],',',all_data[1,v])

        ## Preparing the graph info
        # Other colors: https://matplotlib.org/gallery/color/named_colors.html
        colors = ('red', 'skyblue', 'indigo', 'olive', 'slateblue', 'magenta',
                  'slategray', 'limegreen', 'maroon', 'teal', 'khaki', 'purple',
                  'r', 'c', 'm', 'y', 'k')
        markers = ('s', 'o', '+', "."	,"," ,"v"	,"^"	,"<"	,">"	,
                   "1","2"	,"3"	,"4"	,"8"	,"s"	,"p"	,"P"	)
        width = 0.7
        ind = (num_tool + 1) * width * np.arange(len(mat_list))
        x_label = np.arange(1,len(mat_list)+1)
        font_axis = self.font0.copy()
        metric_label = 'solve time(sec)'
        fig = plt.figure(figsize=(30,5))
        ax1 = fig.add_subplot(111)
        ax1.set_yscale('log')
        for i in range(num_tool):
            #ax1.scatter(mat_list[:], all_data[i, :], s=10, c=colors[i],
            #            marker=markers[i], label=tool_name[i])
            ax1.bar(ind + i*width, all_data[i, :], width,
                   label=tool_name[i] + ' ' + metric_label, color=colors[i],
                   align='edge')
            #ax1.scatter(mat_list[:], all_data[1, :], s=10, c='r', marker="o", label=tool_name[1])

        #ax1.set_ylabel(mat_list[:], fontsize=12, fontproperties=font_axis)
        font_axis.set_weight('black')  # ['light', 'normal', 'medium', 'semibold', 'bold', 'heavy', 'black']
        ax1.set_ylabel(y_label, fontsize=12, fontproperties=font_axis)
        ax1.set_xticks(ind)
        ax1.set_xticklabels(x_label, fontsize=12)
        plt.xticks(rotation=55)
        plt.legend(loc='upper right')
        plt.show()

    def plot_bar_chart(self, list_logs, idx_x, idx_y, idx_y2, y_label='',
                       file_name='', y_scale="linear"):
        if len(list_logs) <= 0:
            print("Wrong lists to visualize.")
            return -1
        n_groups = len(list_logs[0])
        tool_name = []
        for lst in list_logs:
            if len(lst) != n_groups:
                print("Wrong lists to visualize.")
                return -1
            tool_name.append(lst[0][self.qp_header[self.qp_log_header.TOOLN.value]])
        num_tool = len(list_logs)
        all_data = np.zeros((num_tool,n_groups))
        all_data_rel = np.zeros((num_tool, n_groups))
        mat_list = []
        lst_no = 0
        for lst in list_logs:
            for d in range(len(lst)):
                if (lst[d][self.qp_header[idx_y2.value]]) == OPTIMAL:
                    all_data[lst_no, d] = lst[d][self.qp_header[idx_y.value]]
                else:
                    all_data[lst_no, d] = MAX_VAL
                if lst_no == 0:
                    mat_list.append(lst[d][self.qp_header[idx_x.value]])
            lst_no += 1

        #all_data_rel = f_val(all_data)
        # for dim in range(num_tool):
        #     all_data_rel[dim, :] = all_data[dim, :]/all_data[0, :]
        # for v in range(n_groups):
        #     print(mat_list[v],',',all_data[0,v],',',all_data[1,v])

        ## Preparing the graph info
        # Other colors: https://matplotlib.org/gallery/color/named_colors.html
        colors = ('red', 'skyblue', 'indigo', 'olive', 'slateblue', 'magenta',
                  'slategray', 'limegreen', 'maroon', 'teal', 'khaki', 'purple',
                  'r', 'c', 'm', 'y', 'k')
        markers = ('s', 'o', '+', "."	,"," ,"v"	,"^"	,"<"	,">"	,
                   "1","2"	,"3"	,"4"	,"8"	,"s"	,"p"	,"P"	)
        width = 0.8
        ind = (num_tool + 1) * width * np.arange(len(mat_list))
        x_label = np.arange(1,len(mat_list)+1)
        font_axis = self.font0.copy()
        metric_label = 'solve time(sec)'
        fig = plt.figure(figsize=(100,5))
        ax1 = fig.add_subplot(111)
        ax1.set_yscale('log')
        for i in range(num_tool):
            #ax1.scatter(mat_list[:], all_data[i, :], s=10, c=colors[i],
            #            marker=markers[i], label=tool_name[i])
            ax1.bar(ind + i*width, all_data[i, :], width,
                   label=tool_name[i] + ' ' + metric_label, color=colors[i],
                   align='edge')
            #ax1.scatter(mat_list[:], all_data[1, :], s=10, c='r', marker="o", label=tool_name[1])

        #ax1.set_ylabel(mat_list[:], fontsize=12, fontproperties=font_axis)
        font_axis.set_weight('black')  # ['light', 'normal', 'medium', 'semibold', 'bold', 'heavy', 'black']
        ax1.set_ylabel(y_label, fontsize=12, fontproperties=font_axis)
        ax1.set_xticks(ind)
        ax1.set_xticklabels(x_label, fontsize=5)
        #ax1.tick_params(axis='x', which='minor', direction='out', bottom=True)
        plt.xticks(rotation=55)
        plt.legend(loc='upper right')
        results_file = file_name
        print("Saving plots to %s" % results_file)
        plt.savefig(results_file, dpi=100)
        plt.show()

    def visualize_list(self, *list_args, idx_x, idx_y, y_label='',
                       file_name='', f_val, y_scale="linear"):
        """

        :param list_args: The list of reports as a set of dics
        :param idx_x: The index ID for x axis
        :param idx_y: Array of y-axis. It is a bar chart if
        len(idx_y) == 1 otherwise, that is a stacked bar chart.
        :param y_label: The label for y-axis, if it is not given,
        the label from the header array will be used.
        :param file_name: The file name to store the graph
        :param f_val: Doing an operation on the data, e.g., normalizing
        the data on one of the dimensions.
        :param y_scale: The scale of Y-axis e.g., log-scale, linear, ...
        :return: returns the raw plotted data.
        """

        if len(list_args) <= 0:
            print("Wrong lists to visualize.")
            return -1
        n_groups = len(list_args[0])
        tool_name = []
        for lst in list_args:
            if len(lst) != n_groups:
                print("Wrong lists to visualize.")
                return -1
            tool_name.append(lst[0][self.sympiler_header[self.LogHeader.TOOL.value]])
        num_tool = len(list_args)
        num_stacks = len(idx_y)
        all_data = np.zeros((num_tool,n_groups,num_stacks))
        all_data_rel = np.zeros((num_tool, n_groups))
        mat_list = []
        lst_no = 0
        for lst in list_args:
            for d in range(len(lst)):
                st_no = 0
                for st in idx_y:
                    all_data[lst_no, d, st_no] = lst[d][self.sympiler_header[st]]
                    st_no += 1
                if lst_no == 0:
                    mat_list.append(lst[d][self.sympiler_header[idx_x]])
            lst_no += 1

        all_data_rel = f_val(all_data)
        # for dim in range(num_tool):
        #     all_data_rel[dim, :] = all_data[dim, :]/all_data[0, :]
        # for v in range(n_groups):
        #     print(mat_list[v],',',all_data[0,v],',',all_data[1,v])

        ## Preparing the graph info
        # Other colors: https://matplotlib.org/gallery/color/named_colors.html
        colors = ('red', 'skyblue', 'indigo', 'olive', 'slateblue', 'magenta',
                  'slategray', 'limegreen', 'maroon', 'teal', 'khaki', 'purple',
                  'r', 'c', 'm', 'y', 'k')
        font_axis = self.font0.copy()
        fig, ax = plt.subplots(figsize=(12, 6))  # size=fig(10,20)
        width = 0.8
        ind = (num_tool + 1) * width * np.arange(n_groups)
        if y_label == '' and num_stacks == 1:
            y_label = self.sympiler_header[idx_y[0]]
        if file_name == '':
            file_name = self.sympiler_header[idx_y[0]]
        i = 0
        c = 0
        st = 0
        for linePlt in all_data_rel:
            st = 0
            bot_stacks = np.zeros(n_groups)
            for st_val in range(num_stacks):
                metric_label = self.sympiler_header[idx_y[st]]
                st_val_array = linePlt[:, st_val]
                ax.bar(ind + i*width,  st_val_array, width,
                       label=tool_name[i]+' '+metric_label, color=colors[c],
                       align='edge', bottom=bot_stacks)
                bot_stacks += st_val_array
                c += 1
                st += 1
            i += 1
        ax.legend(frameon=False)
        # ax.grid()
        font_axis.set_weight('black') # ['light', 'normal', 'medium', 'semibold', 'bold', 'heavy', 'black']
        ax.set_ylabel(y_label,  fontsize=12, fontproperties=font_axis)
        ax.set_xticks(ind-6*width)
        ax.set_xticklabels(mat_list, fontsize=12)

        ax.tick_params(color='black', labelcolor='black')
        plt.yscale(y_scale)
        plt.xticks(rotation=55)
        # plt.set_title('Quality Progress for file:' + fileName)
        ax.tick_params(top=False, bottom=False, left=True, right=False,
                       labelleft=True, labelbottom=True, labeltop=False, labelright=False)
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        plt.show()
        if self.path != '' and os.path.exists(self.path):
            fig.savefig(join(self.path, file_name+".pdf"))
        else:
            print("Output path is not valid, saving current!")
            fig.savefig(file_name+".pdf", bbox_inches='tight')

        return all_data_rel

    def write_to_csv(self, report, csv_file):
        csv_columns = []
        if len(report) > 0:
            one_row = report[0]
        for key, value in one_row.items():
            csv_columns.append(key)
        def remove_key(d, key):
            r = dict(d)
            del r[key]
            return r
        try:
            with open(csv_file, 'w') as csvfile:
                writer = csv.DictWriter(csvfile, fieldnames=csv_columns)
                writer.writeheader()
                for data in report:
                    #data_p = remove_key(data, None)
                    writer.writerow(data)
        except IOError:
            print("I/O error")

def median_idx(tmp_sort):
    med_idx = np.argsort(tmp_sort)[len(tmp_sort) / 2]
    return med_idx

def min_idx(tmp_sort):
    min_idx = np.argsort(tmp_sort)[0]
    return min_idx

def scaling_array(in_list):
    scaled = np.zeros(in_list.shape)
    for l in range(len(in_list)):
        scaled[l, :] = in_list[l, :]/in_list[0, :]
    return scaled

def nop(in_list):
    return in_list

class reporting_type(Enum):
    LinSolve1 = 0
    LinSolve2 = 1
    SCATQP = 2
    BARQP = 3
    PerfProf = 4
    AllFile = 5

def main(argv):
    output_path = ''
    input_path1 = ''
    input_path2 = ''
    eps = -3
    input_path4 = ''
    report_type = 5
    try:
        opts , args = getopt.getopt(argv,"hi:f:s:w:d:o:t:",["help","inputPath=","outputPath=","fileName=","inputPath4=",
                                                            "directory=", "outputPath=", "reportType="])
    except getopt.GetoptError:
        print('visualize.py -i <sympiler report path> -s <second sym report> -f <mkl report path> -o <output Path for graphs> ')
        sys.exit(-1)
    for opt, arg in opts:
        if opt == '-h':
            print('visualize.py -i <sympiler report path> -f <mkl report path> -o <output Path for graphs> ')
        elif opt in ("-i", "--inputPath"):
            input_path1 = arg
        elif opt in ("-f", "--fileName"):
            input_path2 = arg.strip()
        elif opt in ("-s", "--sym2"):
            eps = int(arg.strip())
        elif opt in ("-w", "--inputPath4"):
            input_path4 = arg.strip()
        elif opt in ("-d", "--directory"):
            input_dir = arg.strip()
        elif opt in ("-o", "--outputPath"):
            output_path = arg
        elif opt in ("-t", "--reportType"):
            report_type = int(arg)

    graphGenerator = Visualizer(output_path)
    print('Reading CSV files from the input directory: ', input_path1)
    #report_type = 2
    if report_type == reporting_type.AllFile.value:
        if not os.path.isdir(input_dir):
            print('Please specify a path to the input directory.')
            print('visualize.py -i <sympiler report path> -f <mkl report path> -o <output Path for graphs> ')
            sys.exit(-1)

        def condition(dic_in):
            p_size = graphGenerator.qp_header[Visualizer.qp_log_header.PROBS.value]
            #if dic_in[p_size] <= 5000:
            #if dic_in[p_size] > 5000 and dic_in[p_size] <= 200000:
            #if dic_in[p_size] > 200000:

            if dic_in[p_size] <= 20000:
                return True
            else:
                return False

        def condition_ql(dic_in):
            p_size = graphGenerator.qp_header[Visualizer.qp_log_header.PROBD.value]
            psize = int(dic_in[p_size])
            if psize < 8000:
                # if dic_in[p_size] > 5000 and dic_in[p_size] <= 200000:
                # if dic_in[p_size] > 200000:
                return True
            else:
                return False

        def condition_ql(dic_in):
            p_size = graphGenerator.qp_header[Visualizer.qp_log_header.PROBD.value]
            psize = int(dic_in[p_size])
            if psize < 8000:
                # if dic_in[p_size] > 5000 and dic_in[p_size] <= 200000:
                # if dic_in[p_size] > 200000:
                return True
            else:
                return False

        def condition_large_var(dic_in):
            p_dim = graphGenerator.qp_header[Visualizer.qp_log_header.PROBD.value]
            p_ed = graphGenerator.qp_header[Visualizer.qp_log_header.CNSED.value]
            p_id = graphGenerator.qp_header[Visualizer.qp_log_header.CNSID.value]
            dim_val = float(dic_in[p_dim])
            ed_val = int(dic_in[p_ed])
            id_val = int(dic_in[p_id])

            if (ed_val+id_val / dim_val) >= 1.9:
                # if dic_in[p_size] > 5000 and dic_in[p_size] <= 200000:
                # if dic_in[p_size] > 200000:
                return True
            else:
                return False

        problem_group = ['All']
        #problem_group = ['contact simulation']
        #problem_group = ['maros-meszaros']
        #problem_group = ['model predictive control']
        #problem_group = ['cloth simulation', 'image deformation', 'model construction', 'distortion mapping']
        if len(problem_group) > 1:
            problem_type = "Mixed"
        else:
            problem_type = problem_group[0]
        tol = pow(10, eps)
        if eps == -3:
            tol_str = '0.001'
        elif eps == -6:
            tol_str = '1e-06'
        else:
            tol_str = '1e-09'

        sorting_idx = Visualizer.qp_log_header.PROBN
        sorting_idx2 = Visualizer.qp_log_header.PROBS
        key_item = graphGenerator.qp_header[Visualizer.qp_log_header.PROBN.value]
        ql_wanted = 0
        del_items = []

        files = [f for f in glob.glob(input_dir + "*.csv", recursive=False)]
        all_logs = []
        tool_names = []
        for f in files:
            if 'ql' in f:
                continue
            graphGenerator.find_problem_size(f, sorting_idx,
                                                    Visualizer.qp_log_header.STIME,
                                                        tol, tol_str, problem_group)
        for f in files:
            if 'ql' in f:
                continue
            logs_tmp = graphGenerator.read_qp_log_split(f, sorting_idx,
                                                    Visualizer.qp_log_header.STIME,
                                                        tol, tol_str, problem_group)

            for log_tmp in logs_tmp:
                tn = log_tmp[0][graphGenerator.qp_header[Visualizer.qp_log_header.TOOLN.value]]
                # if not "1e-09_1_1_1e-15" in tn and not "1e-09_2_2_1e-15" in tn and \
                #         not "1e-09_3_3_1e-15" in tn and not "OSQP" in tn:
                #     continue
                for del_item in del_items:
                    log_tmp = exclude_items(log_tmp, del_item, key_item)
                #if ql_wanted:

                #log_tmp = exclude_items_general(log_tmp, condition)
                #log_tmp = exclude_items_general(log_tmp, condition_ql)
                #log_tmp = exclude_items_general(log_tmp, condition_large_var)
                #log_tmp = sorted(log_tmp, key=itemgetter(graphGenerator.qp_header[sorting_idx2.value]))
                log_tmp = sorted(log_tmp, key=itemgetter(graphGenerator.qp_header[sorting_idx.value]))
                all_logs.append(log_tmp)
                tool_names.append(tn)
                graphGenerator.qp_log_export(log_tmp, problem_type)
                graphGenerator.qp_comp_export(log_tmp, problem_type)
        compute_performance_profiles(tool_names, problem_type,tol_str)
        su = compute_speedup(tool_names,"NASOQ-Fixed",problem_type,tol_str)
        fr = compute_failure_rates(tool_names,
                              problem_type, tol_str)
        plot_performance_profiles(problem_type,
                                  tool_names, tol_str)
        # min_fr = 100
        # min_log = []
        # all_reduced_logs = []
        # for l in all_logs:
        #     ln = l[0][graphGenerator.qp_header[Visualizer.qp_log_header.TOOLN.value]]
        #     if "NASOQ" in ln:
        #         cur_fr = fr[ln]
        #         if cur_fr < min_fr:
        #             min_fr = cur_fr
        #             min_log = l
        #     else:
        #         all_reduced_logs.append(l)
        #
        # all_reduced_logs.append(min_log)

        # graphGenerator.plot_bar_chart(all_reduced_logs, idx_x=Visualizer.qp_log_header.PROBN,
        #                            idx_y=Visualizer.qp_log_header.STIME,
        #                            idx_y2=Visualizer.qp_log_header.STATS,
        #                            y_label='Solve Time with tol = %s (Sec) ' % tol_str,
        #                               file_name='results_time_%s_%s.png' % (problem_type, tol_str) )
       # graphGenerator.write_to_csv(nasoq_log1, 'NASOQ.csv')

    else:
        if (not os.path.exists(input_path1) or not os.path.exists(input_path2)):
            print('Please specify a path and right command arguments. '
                  'You need to have correct input paths to see a graph')
            print('visualize.py -i <sympiler report path> -f <mkl report path> -o <output Path for graphs> ')
            sys.exit(-1)
        nasoqp_log2 = []
        nasoqp_log3 = []
        nasoqp_log4 = []
        problem_type = 'AllQPs'
        tol = 1e-9
        sorting_idx = Visualizer.qp_log_header.PROBN
        sorting_idx2 = Visualizer.qp_log_header.PROBS
        nasoq_log1 = graphGenerator.read_qp_log(input_path1, sorting_idx,
                                                    Visualizer.qp_log_header.STIME, tol)
        graphGenerator.write_to_csv(nasoq_log1, 'NASOQall.csv')

        nasoq_log1 = sorted(nasoq_log1, key=itemgetter(graphGenerator.qp_header[sorting_idx2.value]))
        graphGenerator.qp_log_export(nasoq_log1, problem_type)
        if input_path2 != '':
            nasoqp_log2 = graphGenerator.read_qp_log(input_path2, sorting_idx,
                                                    Visualizer.qp_log_header.STIME,tol)
            nasoqp_log2 = sorted(nasoqp_log2, key=itemgetter(graphGenerator.qp_header[sorting_idx2.value]))
            graphGenerator.qp_log_export(nasoqp_log2, problem_type)
        if input_path3 != '':
            nasoqp_log3 = graphGenerator.read_qp_log(input_path3, sorting_idx,
                                                    Visualizer.qp_log_header.STIME,tol)
            nasoqp_log3 = sorted(nasoqp_log3, key=itemgetter(graphGenerator.qp_header[sorting_idx2.value]))
            graphGenerator.qp_log_export(nasoqp_log3, problem_type)
        if input_path4 != '':
            nasoqp_log4 = graphGenerator.read_qp_log(input_path4, sorting_idx,
                                                    Visualizer.qp_log_header.STIME,tol)
            nasoqp_log4 = sorted(nasoqp_log4, key=itemgetter(graphGenerator.qp_header[sorting_idx2.value]))
            graphGenerator.qp_log_export(nasoqp_log4, problem_type)
        # Writing the CSV file if necessary
        #graphGenerator.write_to_csv(osqp_log, 'out_csv_mkl.csv')
        #graphGenerator.write_to_csv(nasoq_log1, 'out_csv_sym.csv')
        print('Drawing a graph')

    sys.exit(0)

if __name__ == "__main__":
   main(sys.argv[1:])


#!/bin/python/env python3
# -*- coding: UTF-8 -*-
"""

clidisplay : clidisplay contains the class CliDisplay .

Classes:
    CliDisplay : The CliDisplay  prints the game interface on the console.
Methods:
    print_interface(zones, macgyver_position, backpack, materials):
        Prints the game interface on the console.
    print_ending(cls, caption, ending, length=40):
        Print centered caption and ending text.
"""

import os

import config.const as const

class CliDisplay:
    """The CliDisplay prints the game interface on the console"""

    @staticmethod
    def _clear_console():
        '''Clears the console on any OS. '''
        if os.name in ("nt", "dos"):
            os.system("cls")
        elif os.name in ("linux", "osx", "posix"):
            os.system("clear")
        else:
            print("\n" * 120)

    @staticmethod
    def _print_separator(length=40):
        '''Prints a separator of the specified length.'''
        print("~" * length)

    @classmethod
    def print_interface(cls, zones, macgyver_position, backpack, materials):
        '''

        Prints the game interface on the command line interface.

        Clears the console and prints all the maze structures, the characters
        and the dropped items. Then prints justifyed carryed items name and
        quality followed by a separator.

            Args:
                zones (dict [tuples, str]):
                    Dictionnary of the zones in the labyrinth.
                macgyver_position (tuples):
                    MacGyver's position in the labyrinth.
                backpack (list [Item]):
                    List of items got by MacGyver.
                materials (list [Item]):
                    List of items dropped in the labyrinth.

        '''
        cls._clear_console()
        length = 40
        margin = 10
        # Draw maze
        for y_coordinate in range(const.MAZE_MIN_HEIGHT, const.MAZE_HEIGHT):
            line = ""
            for x_coordinate in range(const.MAZE_MIN_WIDTH, const.MAZE_WIDTH):
                # Structures
                if (zones[x_coordinate, y_coordinate] ==
                        const.MAZE_WALL):
                    char = const.STRUCTURES[const.MAZE_WALL]
                elif (zones[x_coordinate, y_coordinate] in
                      [const.MAZE_PATH, const.MAZE_START]):
                    char = const.STRUCTURES[const.MAZE_PATH]
                elif (zones[x_coordinate, y_coordinate] ==
                      const.MAZE_EXIT):
                    char = const.STRUCTURES[const.MAZE_EXIT]
                # Special locations
                if (x_coordinate, y_coordinate) == macgyver_position:
                    char = "@"
                else:
                    for item in materials:
                        if item.position == (x_coordinate, y_coordinate):
                            char = "$"
                line += char
            print(line.center(length))
        cls._print_separator(length)
        # Print items in backpack
        left_margin = " " * margin
        print("{}{}".format(left_margin, "Backpack :"))
        for item in backpack:
            left_column = "-{}".format(item.name.capitalize())
            right_column = "[{}]".format(item.quality).rjust(
                length - len(left_column) - margin * 2)
            print("{}{}{}".format(left_margin, left_column, right_column))
        cls._print_separator(length)

    @classmethod
    def print_ending(cls, caption, ending, length=40):
        '''

        Print centered caption and ending text.

            Args:
                caption (str): The text to be printed first.
                ending (str): The text to be printed after the caption.
                length (int, optional): The length is used to center the text
                    and print separators. By default, length is 40.
        '''
        cls._print_separator(length)
        print(caption.center(length))
        cls._print_separator(length)
        for line in ending.split("\n"):
            print(line.center(length))
        cls._print_separator(length)


import sqlite3
from Database import data_tables

# methods of operations on the database
# connecting to database
def connect_to_db():
        database = "database.db"
        print("connecting...")
        connection = sqlite3.connect(database)
        return connection

def create_table(sql):
    print("creating table...")
    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql)
    con.commit()
    cursor.close()

def create_tables():
    print("creating tables")
    create_table(data_tables.USERS_TABLE)
    create_table(data_tables.WEIGHTS_TABLE)
    create_table(data_tables.PRODUCTS_TABLE)
    create_table(data_tables.CONSUMED_PRODUCTS_TABLE)

# write data into database
def query(sql, data):
    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql, data)
    con.commit()
    cursor.close()

def insert_user(login, password, email, calories_intake):
    sql_cmd = """
            INSERT INTO Users (Login,Password,Email,CaloriesIntake)
            VALUES (?,?,?,?);
            """
    data = (login, password, email, calories_intake)
    query(sql_cmd, data)

def insert_weight(id_user, weight_value, weight_date):
    sql_cmd = """
            INSERT INTO Weights (IdUser,WeightValue,WeightDate)
            VALUES (?,?,?);
            """
    data = (id_user, weight_value, weight_date)
    query(sql_cmd, data)

def insert_product(id_user, product_name, calories):
    sql_cmd = """
            INSERT INTO Products (IdUser,Name,Calories)
            VALUES (?,?,?);
            """
    data = (id_user, product_name, calories)
    query(sql_cmd, data)

def insert_consumed_product(id_product, id_user, consumption_date, grammage):
    sql_cmd = """
          INSERT INTO ConsumedProducts (IdProduct,IdUser,ConsumptionDate,Grammage)
          VALUES (?,?,?,?);
          """
    data = (id_product, id_user, consumption_date, grammage)
    query(sql_cmd, data)

# get data from database
def get_user_by_login(login):
    sql_cmd = """
          SELECT * FROM Users WHERE Login=?;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (login,))

    row = cursor.fetchone()
    return row

def get_user_by_login_and_password(login, password):
    sql_cmd = """
          SELECT * FROM Users WHERE Login=? AND Password=?;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (login, password))

    row = cursor.fetchone()
    return row

def get_user_weight(user_id):
    sql_cmd = """
          SELECT * FROM Weights WHERE IdUser=? ORDER BY WeightDate DESC LIMIT 1;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (user_id,))

    row = cursor.fetchone()
    return row

def get_first_weight_before_date(user_id, current_date):
    sql_cmd = """
          SELECT * FROM Weights WHERE IdUser=? AND WeightDate<=? ORDER BY WeightDate DESC LIMIT 1;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (user_id, current_date))

    row = cursor.fetchone()
    return row

def get_first_after_before_date(user_id, current_date):
    sql_cmd = """
          SELECT * FROM Weights WHERE IdUser=? AND WeightDate>=? ORDER BY WeightDate ASC LIMIT 1;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (user_id, current_date))

    row = cursor.fetchone()
    return row

def get_user_weight_by_date(user_id, date):
    sql_cmd = """
          SELECT * FROM Weights WHERE IdUser=? AND WeightDate=? LIMIT 1;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (user_id, date))

    row = cursor.fetchone()
    return row

def get_user_products(user_id):
    sql_cmd = """
          SELECT * FROM Products WHERE IdUser=?;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (user_id,))

    rows = cursor.fetchall()
    return rows

def get_user_consumed_products_by_date(user_id, curr_date):
    sql_cmd = """
          SELECT cp.IdConsumedProduct, cp.IdProduct, cp.IdUser,
                cp.ConsumptionDate, cp.Grammage, p.Name, p.Calories
          FROM ConsumedProducts AS cp
          INNER JOIN Products AS p ON cp.IdProduct=p.IdProduct
          WHERE cp.IdUser=? AND cp.ConsumptionDate=?;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (user_id, curr_date))

    rows = cursor.fetchall()
    return rows

def get_user_calories_intake(user_id):
    sql_cmd = """
          SELECT CaloriesIntake FROM Users WHERE IdUser=?;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (user_id,))

    row = cursor.fetchone()
    return row

# update some basic data
def update_user_weight_date(user_id, weight, date):
    sql_cmd = """
            UPDATE Weights SET WeightValue=? WHERE IdUser=? AND WeightDate=?;
            """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (user_id, weight, date))
    con.commit()

def update_product(product_id, name, calories):
    sql_cmd = """
          UPDATE Products SET Name=?,Calories=? WHERE IdProduct=?;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (product_id, name, calories))
    con.commit()

def update_consumed_product(product_consumed_id, grammage):
    sql_cmd = """
          UPDATE ConsumedProducts SET Grammage=? WHERE IdConsumedProduct=?;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (product_consumed_id, grammage))
    con.commit()

def update_calories_intake(calories_intake, user_id):
    sql_cmd = """
          UPDATE Users SET CaloriesIntake=? WHERE IdUser=?;
          """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (calories_intake, user_id))
    con.commit()

# delete data from database
def delete_consumed_product_user_id(user_id, consumed_product_id):
    print(consumed_product_id)
    sql_cmd = """
            DELETE FROM ConsumedProducts WHERE IdConsumedProduct=? AND IdUser=?;
            """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (consumed_product_id, user_id))
    con.commit()

def delete_consumed_product_by_id(consumed_product_id):
    sql_cmd = """
            DELETE FROM ConsumedProducts WHERE IdProduct=?;
            """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (consumed_product_id,))
    con.commit()

def delete_product(product_id, user_id):
    sql_cmd = """
            DELETE FROM Products WHERE IdProduct=? AND IdUser=?;
            """

    con = connect_to_db()
    cursor = con.cursor()
    cursor.execute(sql_cmd, (product_id, user_id))
    con.commit()


import numpy as np
import collections
from .Binary_Heap import BinaryHeap

class ExperienceReplay_Options_Pseudo_Set:

    Experience = collections.namedtuple("Experience", "state action reward state_next steps terminal pseudo_reward density pseudo_reward_t trajectory_end")

    def __init__(self, N, pseudo_limit, exp_model, args, priority=False):
        self.N = N
        # self.Exps = [None for _ in range(N)]
        self.Exps = {}
        self.state_action_counts = {}
        self.pseudo_limit = pseudo_limit
        self.exp_model = exp_model
        self.T = 0
        self.storing_index = 0
        self.experiences_stored = 0
        self.args = args

        self.recent_exps = []

        self.priority = priority
        if self.priority:
            self.alpha = 0.7
            self.priorities = BinaryHeap(N)
            self.distrib = np.array([pow((1 / (i + 1)), self.alpha) for i in range(self.N)])
            self.full_distrib = self.distrib / np.sum(self.distrib)

    def Clear(self):
        self.Exps = [None for _ in range(self.N)]
        self.storing_index = 0
        self.experiences_stored = 0

    def state_to_tuple(self, state):
        return tuple(np.argwhere(state > 0.9)[0])
        return tuple([tuple([tuple(y) for y in x]) for x in state])

    def Add_Exp(self, state_now, action, reward, state_after, steps, terminal, pseudo_reward=0, density=1):
        # if len(self.Exps) >= self.N:
            # self.Exps.pop(0)
        # Make copies just in case
        new_exp = self.Experience(state=np.copy(state_now), action=action, reward=reward, state_next=np.copy(state_after), steps=steps, terminal=terminal, pseudo_reward=pseudo_reward, density=density, pseudo_reward_t=self.T, trajectory_end=terminal)
        self.recent_exps.append(new_exp)
        if len(self.recent_exps) < self.args.n_step:
            return
        n_step_reward = 0
        n_step_psuedo_reward = 0
        for i in range(self.args.n_step):
            n_step_reward += (self.args.gamma ** i) * self.recent_exps[i].reward
            n_step_psuedo_reward += (self.args.gamma ** i) * self.recent_exps[i].pseudo_reward
        n_step_state = np.copy(self.recent_exps[0].state)
        n_step_action = self.recent_exps[0].action
        n_step_terminal = self.recent_exps[-1].terminal
        n_step_traj_end = self.recent_exps[-1].trajectory_end
        n_step_next_state = np.copy(self.recent_exps[-1].state_next)
        n_step_density = self.recent_exps[0].density
        n_step_exp = self.Experience(state=n_step_state, action=n_step_action, reward=n_step_reward, state_next=n_step_next_state, steps=self.args.n_step, terminal=n_step_terminal, pseudo_reward=n_step_psuedo_reward, density=n_step_density, pseudo_reward_t=self.T, trajectory_end=n_step_traj_end)

        # self.Exps[self.storing_index] = n_step_exp
        n_step_state_tuple = self.state_to_tuple(n_step_state)
        # print(n_step_state_tuple)
        # print(n_step_state_tuple)
        sa_count = 0
        key = (n_step_state_tuple, n_step_action)
        if key in self.state_action_counts:
            sa_count = self.state_action_counts[key]
        self.Exps[(n_step_state_tuple, n_step_action, sa_count)] = n_step_exp
        sa_count += 1
        if sa_count >= self.args.set_replay_num:
            sa_count = 0
        self.state_action_counts[key] = sa_count
        # Remove the oldest entry
        self.recent_exps = self.recent_exps[1:]

        # print("{} items in replay".format(len(self.Exps)))

    def end_of_trajectory(self):
        while len(self.recent_exps) > 0:
            n_step_reward = 0
            n_step_psuedo_reward = 0
            for i in range(len(self.recent_exps)):
                n_step_reward += (self.args.gamma ** i) * self.recent_exps[i].reward
                n_step_psuedo_reward += (self.args.gamma ** i) * self.recent_exps[i].pseudo_reward
            n_step_state = np.copy(self.recent_exps[0].state)
            n_step_action = self.recent_exps[0].action
            n_step_terminal = self.recent_exps[-1].terminal
            # n_step_traj_end = self.recent_exps[-1].trajectory_end
            n_step_next_state = np.copy(self.recent_exps[-1].state_next)
            n_step_density = self.recent_exps[0].density
            n_step_exp = self.Experience(state=n_step_state, action=n_step_action, reward=n_step_reward, state_next=n_step_next_state, steps=len(self.recent_exps), terminal=n_step_terminal, pseudo_reward=n_step_psuedo_reward, density=n_step_density, pseudo_reward_t=self.T, trajectory_end=True)
            # n_step_exp = self.Experience(state=n_step_state, action=n_step_action, reward=n_step_reward, state_next=n_step_next_state, steps=len(self.recent_exps), terminal=n_step_terminal, pseudo_reward=n_step_psuedo_reward, pseudo_reward_t=self.T, trajectory_end=True)

            # n_step_state_tuple = tuple([tuple(x) for x in n_step_state])
            n_step_state_tuple = self.state_to_tuple(n_step_state)
            # self.Exps[(n_step_state_tuple, n_step_action)] = n_step_exp
            sa_count = 0
            key = (n_step_state_tuple, n_step_action)
            if key in self.state_action_counts:
                sa_count = self.state_action_counts[key]
            self.Exps[(n_step_state_tuple, n_step_action, sa_count)] = n_step_exp
            sa_count += 1
            if sa_count >= self.args.set_replay_num:
                sa_count = 0
            self.state_action_counts[key] = sa_count
            # self.Exps[(n_step_state, n_step_action)] = n_step_exp
            # Remove the oldest entry
            self.recent_exps = self.recent_exps[1:]

    def get_sampling_distribution(self):
        if self.experiences_stored < self.N:
            partial = self.distrib[:self.experiences_stored]
            return partial / np.sum(partial)
        else:
            return self.full_distrib

    def get_indices(self, size):
        if self.priority:
            distribution = self.get_sampling_distribution()
            sampled_indices = np.random.choice(np.arange(1, self.experiences_stored + 1), p=distribution, size=size)
            indices = self.priorities.priority_to_experience(sampled_indices)
        else:
            keys = list(self.Exps.keys())
            indices = np.random.randint(low=0, high=len(keys), size=size)
        return indices

    def Recompute_Pseudo_Counts(self, indices):
        return
        if self.exp_model is None or self.pseudo_limit >= self.N:
            # print("No exp model")
            return
        for i in indices:
            exp = self.Exps[i]
            if self.T - exp.pseudo_reward_t > self.pseudo_limit:
                # Recompute it
                if self.args.decay_count:
                    new_bonus = exp.pseudo_reward * self.args.decay_count_rate ** (self.T - exp.pseudo_reward_t)
                else:
                    new_bonus, _ = self.exp_model.bonus(exp.state, dont_remember=True)
                new_exp = self.Experience(state=exp.state, action=exp.action, reward=exp.reward, state_next=exp.state_next, steps=exp.steps, terminal=exp.terminal, pseudo_reward=new_bonus, pseudo_reward_t=self.T, trajectory_end=exp.trajectory_end)
                self.Exps[i] = new_exp

    def Update_Indices(self, indices, ps, no_pseudo_in_priority):
        return
        if self.priority:
            # print(ps)
            for index, priority in zip(indices, ps):
                # print(index, priority)
                self.priorities.update(priority[0] + 0.00001, index)

    def Sample_N(self, size, N, gamma):
        # assert(size <= self.N)
        self.T += 1
        # indices = np.random.randint(low=0, high=len(self.Exps) - 1, size=size)
        indices = self.get_indices(size)
        self.Recompute_Pseudo_Counts(indices)
        batch_to_return = []

        # exps_to_use = self.Exps[indices]
        keys = list(self.Exps.keys())
        keys_to_use = [keys[i] for i in indices]
        for exp in [self.Exps[k] for k in keys_to_use]:
            state_now = exp.state
            action_now = exp.action
            accum_reward = exp.reward + exp.pseudo_reward
            state_then = exp.state_next
            steps = exp.steps
            terminate = exp.terminal

        # state_now = exps_to_use[0].state
        # action_now = exps_to_use[0].action
        # state_then = exps_to_use[-1].state_next
        # terminate = exps_to_use[-1].terminal
        # steps = len(exps_to_use)
        # rewards_to_use = list(map(lambda x: x.reward + x.pseudo_reward, exps_to_use))
        # accum_reward = 0
        # for ri in reversed(rewards_to_use):
        #     accum_reward = ri + gamma * accum_reward
            new_exp = (state_now, action_now, accum_reward, state_then, steps, terminate)
            batch_to_return.append(new_exp)
        # [] for indices to match the prioritized replay
        return batch_to_return, indices, None


from pip._vendor import requests

class YaUploader:
    def __init__(self, token):
        self.token = token

    def get_headers(self):
        return {'Content-Type': 'application/json', 'Authorization': 'OAuth {}'.format(self.token)}

    def upload(self, file_path):
        url = 'https://cloud-api.yandex.net/v1/disk/resources/upload'
        params = {'path': file_path, 'overwrite': 'True'}
        headers = self.get_headers()
        link_dickt = requests.get(url, headers = headers, params = params).json()
        href = link_dickt.get('href', '')
        post_ = requests.put(href, data = open(file_path, 'rb'))
        return print(post_.status_code)

if __name__ == '__main__':
    path_to_file = 'Text.txt'
    token = ''
    uploader = YaUploader(token)
    result = uploader.upload(path_to_file)