# Path: sdopt/parsers/dag_parser.py
# def read_problem(filename, crosscheck_nl=True, show_sparsity=True):
#     with lines_of(filename) as lines:
#         problem = parse(lines)
#     setup(problem)
#     if crosscheck_nl:
#         nl_filename = filename[:-4]+'.nl' # filename.dag -> filename.nl
#         bsp = read_flattened_ampl(nl_filename, show_sparsity)
#         crosscheck_sparsity_pattern(problem, bsp.csr_mat)
#         crosscheck_names(problem, bsp.row_names, bsp.col_names)
#     return problem
# 
# Path: sdopt/datagen/paths.py
# DATADIR = join(_ROOT, 'data')
# 
# Path: sdopt/util/misc.py
# def import_code(code):
#     import imp
#     module = imp.new_module('someFakeName')
#     try:
#         exec_(code, module.__dict__)
#     except:
#         print(code)
#         raise
#     return module
# 
# def get_all_files(directory, extension):
#     files = sorted(f for f in os.listdir(directory) if f.endswith(extension))
#     return [ os.path.join(directory, filename) for filename in files ]
# 
# Path: sdopt/nodes/reverse_ad.py
# def prepare_evaluation_code(prob, tracepoint=[ ], only_forward=False):
#     with closing(stringIO()) as code: 
#         code.write(preamble)
#         write_constraint_evaluation_code(prob, code, only_forward)
#         code.write(postamble)
#         code.write( main_func.substitute(v=prob.refsols[0], tp=list(tracepoint), 
#                                          ncons =prob.ncons, nvars=prob.nvars, 
#                                          nzeros=prob.nzeros) )
#         return code.getvalue()


import unittest
import numpy as np
from sdopt.parsers.dag_parser import read_problem
from sdopt.datagen.paths import DATADIR
from sdopt.util.misc import import_code, get_all_files
from sdopt.nodes.reverse_ad import prepare_evaluation_code
from __future__ import print_function

class ResidualTest(unittest.TestCase):
    def test_files(self):
        check_residuals()

def check_residuals():
    for dag_file in get_all_files(DATADIR, '.dag'):
        problem = read_problem(dag_file, show_sparsity=False)
        residual_code = prepare_evaluation_code(problem, only_forward=True)
        f = import_code(residual_code)
        # ignore the returned Jacobian, which is still empty in forward mode
        residuals, _  = f.evaluate( problem.refsols[0], problem.ncons, 
                                    problem.nvars,      problem.nzeros )
        approx_zero = np.isclose(residuals, 0.0, atol=4.0e-6)
        # TODO If fails, give the violated constraint name
        assert np.all(approx_zero), 'Large constraint violation\n%s' % residuals

# Path: sdopt/parsers/dag_parser.py
# def read_problem(filename, crosscheck_nl=True, show_sparsity=True):
#     with lines_of(filename) as lines:
#         problem = parse(lines)
#     setup(problem)
#     if crosscheck_nl:
#         nl_filename = filename[:-4]+'.nl' # filename.dag -> filename.nl
#         bsp = read_flattened_ampl(nl_filename, show_sparsity)
#         crosscheck_sparsity_pattern(problem, bsp.csr_mat)
#         crosscheck_names(problem, bsp.row_names, bsp.col_names)
#     return problem
# 
# Path: sdopt/datagen/paths.py
# DATADIR = join(_ROOT, 'data')
# 
# Path: sdopt/util/misc.py
# def import_code(code):
#     import imp
#     module = imp.new_module('someFakeName')
#     try:
#         exec_(code, module.__dict__)
#     except:
#         print(code)
#         raise
#     return module
# 
# def get_all_files(directory, extension):
#     files = sorted(f for f in os.listdir(directory) if f.endswith(extension))
#     return [ os.path.join(directory, filename) for filename in files ]
# 
# Path: sdopt/nodes/reverse_ad.py
# def prepare_evaluation_code(prob, tracepoint=[ ], only_forward=False):
#     with closing(stringIO()) as code: 
#         code.write(preamble)
#         write_constraint_evaluation_code(prob, code, only_forward)
#         code.write(postamble)
#         code.write( main_func.substitute(v=prob.refsols[0], tp=list(tracepoint), 
#                                          ncons =prob.ncons, nvars=prob.nvars, 
#                                          nzeros=prob.nzeros) )
#         return code.getvalue()


# Path: sdopt/tests/ResidualTest.py
import unittest
import numpy as np
from sdopt.parsers.dag_parser import read_problem
from sdopt.datagen.paths import DATADIR
from sdopt.util.misc import import_code, get_all_files
from sdopt.nodes.reverse_ad import prepare_evaluation_code

from __future__ import print_function

class ResidualTest(unittest.TestCase):
    def test_files(self):
        check_residuals()

def check_residuals():
    for dag_file in get_all_files(DATADIR, '.dag'):
        problem = read_problem(dag_file, show_sparsity=False)
        residual_code = prepare_evaluation_code(problem, only_forward=True)
        f = import_code(residual_code)
        # ignore the returned Jacobian, which is still empty in forward mode
        residuals, _  = f.evaluate( problem.refsols[0], problem.ncons, 
                                    problem.nvars,      problem.nzeros )
        approx_zero = np.isclose(residuals, 0.0, atol=4.0e-6)
        # TODO If fails, give the violated constraint name
        assert np.all(approx_zero), 'Large constraint violation\n%s' % residuals

        print('PASSED:', dag_file)