SCIPDIR         =       $(SCIP_BUGFIX_PATH)

#-----------------------------------------------------------------------------
# include default project Makefile from SCIP (need to do this twice, once to
# find the correct binary, then, after getting the correct flags from the
# binary (which is necessary since the ZIMPL flags differ from the default
# if compiled with the SCIP Optsuite instead of SCIP), we need to set the
# compile flags, e.g., for the ZIMPL library, which is again done in make.project
#-----------------------------------------------------------------------------
include $(SCIPDIR)/make/make.project
SCIPVERSION		:=$(shell $(SCIPDIR)/bin/scip.$(BASE).$(LPS).$(TPI)$(EXEEXTENSION) -v | sed -e 's/$$/@/')
override ARCH		:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ARCH=\([^@]*\).*/\1/')
override EXPRINT	:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* EXPRINT=\([^@]*\).*/\1/')
override GAMS		:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* GAMS=\([^@]*\).*/\1/')
override GMP		:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* GMP=\([^@]*\).*/\1/')
override SYM		:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* SYM=\([^@]*\).*/\1/')
override IPOPT		:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* IPOPT=\([^@]*\).*/\1/')
override IPOPTOPT	:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* IPOPTOPT=\([^@]*\).*/\1/')
override LPSCHECK	:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* LPSCHECK=\([^@]*\).*/\1/')
override LPSOPT 	:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* LPSOPT=\([^@]*\).*/\1/')
override NOBLKBUFMEM	:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* NOBLKBUFMEM=\([^@]*\).*/\1/')
override NOBLKMEM	:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* NOBLKMEM=\([^@]*\).*/\1/')
override NOBUFMEM	:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* NOBUFMEM=\([^@]*\).*/\1/')
override PARASCIP	:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* PARASCIP=\([^@]*\).*/\1/')
override READLINE	:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* READLINE=\([^@]*\).*/\1/')
override SANITIZE	:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* SANITIZE=\([^@]*\).*/\1/')
override ZIMPL		:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ZIMPL=\([^@]*\).*/\1/')
override ZIMPLOPT	:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ZIMPLOPT=\([^@]*\).*/\1/')
override ZLIB		:=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ZLIB=\([^@]*\).*/\1/')
include $(SCIPDIR)/make/make.project

ifeq ($(DEBUGSOL),true)
FLAGS           +=      -DWITH_DEBUG_SOLUTION
endif

override SLURMACCOUNT="dopt"
EMPHBENCHMARK=true
CLOCKTYPE      	=	1

VERSION 	= 	1.0

#-----------------------------------------------------------------------------
# parameter settings for code
FW_SEPA         	=       false # Use a Frank-Wolfe idea for separation.
HYBRID_ORACLE 		= 	false # Use hybrid between brute-force CPU enumeration oracle and DP.
HYBRID_THRESHOLD	= 	8     # Threshold for switching between dynamic programming and enumeration oracle.
USE_AVX512 		= 	false # Use AVX512 instructions for enumeration oracle.
GANGSIZE		=	8

FLAGS           +=      -I../external
FLAGS		+=	-DGANGSIZE=${GANGSIZE}
ifeq ($(FW_SEPA),true)
FLAGS           +=      -DUSE_FW_SEPA
endif

ifeq ($(HYBRID_ORACLE), true)
FLAGS		+=	-DHYBRID_ORACLE
FLAGS		+=	-DORACLE_THRESHOLD=${HYBRID_THRESHOLD}

FLAGS           +=      -I$(OBJDIR) -fopenmp
LDFLAGS         +=      -lgomp -fopenmp
ISPC            =       ispc/bin/ispc
OBJSUBDIRS      =       $(OBJDIR)/oracle

# determine target architecture for ISPC
ifeq ($(USE_AVX512), true)
ISPC_TARGET 	=	avx512skx-i32x16
GANGSIZE 	=	16
else
ISPC_TARGET 	=	avx2-i32x8
GANGSIZE 	=	8
endif
endif

CXXFLAGS 	+=  	-std=gnu++14 -Wno-ctor-dtor-privacy

#-----------------------------------------------------------------------------
# Main Program
#-----------------------------------------------------------------------------

MAINNAME	=	knapsack

MAINISPCOBJ	=
MAINCPPOBJ	=
MAINCOBJ	=

ifeq ($(HYBRID_ORACLE), true)
MAINISPCOBJ	+=	oracle/enum_oracle.o
endif
MAINCOBJ	+=	cmain.o handle_localcuts.o sepa_localcuts.o
MAINCPPOBJ      +=      oracle/lmo_api.o oracle/lmo.o
ifeq ($(FW_SEPA),true)
MAINCPPOBJ      +=      lc_clock.o scalar-fw/fwknapcut.o
endif

MAINSRC		=	$(addprefix $(SRCDIR)/,$(MAINISPCOBJ:.o=.ispc))
MAINSRC		+=	$(addprefix $(SRCDIR)/,$(MAINCOBJ:.o=.c))
MAINSRC		+=	$(addprefix $(SRCDIR)/,$(MAINCPPOBJ:.o=.cpp))

MAIN		=	$(MAINNAME).$(BASE).$(LPS)$(EXEEXTENSION)
MAINFILE	=	$(BINDIR)/$(MAIN)
MAINSHORTLINK	=	$(BINDIR)/$(MAINNAME)

MAINOBJFILES	=	$(addprefix $(OBJDIR)/,$(MAINISPCOBJ))
MAINOBJFILES	+=	$(addprefix $(OBJDIR)/,$(MAINCOBJ))
MAINOBJFILES	+=	$(addprefix $(OBJDIR)/,$(MAINCPPOBJ))

OBJSUBDIRS	= 	$(OBJDIR)/scalar-fw $(OBJDIR)/oracle

#-----------------------------------------------------------------------------
# Rules
#-----------------------------------------------------------------------------

ifeq ($(VERBOSE),false)
.SILENT:	$(MAINFILE) $(MAINOBJFILES) $(MAINSHORTLINK)
endif

.PHONY: all
all:            $(SCIPDIR) $(MAINFILE) $(MAINSHORTLINK)

.PHONY: lint
lint:		$(MAINSRC)
		-rm -f lint.out
		$(SHELL) -ec 'for i in $^; \
			do \
			echo $$i; \
			$(LINT) -I$(SCIPDIR) lint/main-gcc.lnt +os\(lint.out\) -u -zero \
			$(FLAGS) -UNDEBUG -USCIP_WITH_READLINE -USCIP_ROUNDING_FE $$i; \
			done'

.PHONY: pclint
pclint:		$(MAINSRC)
		-rm -f pclint.out
		@$(SHELL) -ec 'if ! test -e $(SCIPDIR)/pclint/co-gcc.h ; \
			then \
				echo "Please run pclint on the SCIP repository"; \
				exit; \
			fi'
ifeq ($(FILES),)
		@$(SHELL) -ec 'echo "-> running pclint ..."; \
			for i in $^; \
			do \
				echo $$i; \
				$(PCLINT) -I$(SCIPDIR) -I$(SCIPDIR)/pclint pclint/main-gcc.lnt +os\(pclint.out\) -b -u -zero \
				$(USRFLAGS) $(FLAGS) -uNDEBUG -uSCIP_WITH_READLINE -uSCIP_ROUNDING_FE -D_BSD_SOURCE $$i; \
			done'
else
		@$(SHELL) -ec 'echo "-> running pclint ..."; \
			for i in $(FILES); \
			do \
				echo $$i; \
				$(PCLINT) -I$(SCIPDIR) -I$(SCIPDIR)/pclint pclint/main-gcc.lnt +os\(pclint.out\) -b -u -zero \
				$(USRFLAGS) $(FLAGS) -uNDEBUG -uSCIP_WITH_READLINE -uSCIP_ROUNDING_FE -D_BSD_SOURCE $$i; \
			done'
endif

.PHONY: scip
scip:
		@$(MAKE) -C $(SCIPDIR) libs $^

$(MAINSHORTLINK):	$(MAINFILE)
		@rm -f $@
		cd $(dir $@) && ln -s $(notdir $(MAINFILE)) $(notdir $@)

$(OBJDIR):
		@-mkdir -p $(OBJDIR)

$(OBJSUBDIRS):  | $(OBJDIR)
		@-mkdir -p $(OBJDIR)/scalar-fw
		@-mkdir -p $(OBJDIR)/oracle

$(BINDIR):
		@-mkdir -p $(BINDIR)

.PHONY: doc
doc:
		cd doc; doxygen knapsack.dxy

.PHONY: clean
clean:
ifneq ($(OBJDIR),)
		@-(rm -f $(OBJDIR)/*/*.o $(OBJDIR)/*/*.d $(OBJDIR)/*.o $(OBJDIR)/*.d $(OBJDIR)/*.h && rmdir $(OBJSUBDIRS) && rmdir $(OBJDIR));
		@echo "-> remove main objective files"
endif
		@-rm -f $(MAINFILE) $(MAINLINK) $(MAINSHORTLINK)
		@echo "-> remove binary"

.PHONY: test
test:           $(MAINFILE)
		@-(cd check && ln -fs $(SCIPDIR)/check/check.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/check_cluster.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/evalcheck.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/evalcheck_cluster.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/check.awk);
		@-(cd check && ln -fs $(SCIPDIR)/check/getlastprob.awk);
		@-(cd check && ln -fs $(SCIPDIR)/check/configuration_set.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/configuration_logfiles.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/configuration_tmpfile_setup_scip.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/run.sh);
		cd check; \
		$(SHELL) ./check.sh $(TEST) $(EXECUTABLE) $(SETTINGS) $(BINID) $(OUTPUTDIR) $(TIME) $(NODES) $(MEM) $(THREADS) $(FEASTOL) $(DISPFREQ) \
			$(CONTINUE) $(LOCK) $(VERSION) $(LPS) $(DEBUGTOOL) $(CLIENTTMPDIR) $(REOPT) $(OPTCOMMAND) $(SETCUTOFF) $(MAXJOBS) $(VISUALIZE) \
			$(PERMUTE) $(SEEDS) $(GLBSEEDSHIFT) $(STARTPERM) $(PYTHON) $(EMPHBENCHMARK);

.PHONY: testcluster
testcluster: check/check_cluster.sh check/configuration_cluster.sh check/configuration_set.sh check/configuration_logfiles.sh check/configuration_tmpfile_setup_knapsack.sh check/evalcheck_cluster.sh check/check.awk check/run.sh
		@-(cd check && ln -fs $(SCIPDIR)/check/check.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/evalcheck.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/evalcheck_cluster.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/check.awk);
		@-(cd check && ln -fs $(SCIPDIR)/check/getlastprob.awk);
		@-(cd check && ln -fs $(SCIPDIR)/check/configuration_set.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/configuration_logfiles.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/configuration_tmpfile_setup_scip.sh);
		@-(cd check && ln -fs $(SCIPDIR)/check/run.sh);
		cd check; \
		$(SHELL) ./check_cluster.sh $(TEST) $(EXECUTABLE) $(SETTINGS) $(BINID) \
		$(OUTPUTDIR) $(TIME) $(NODES) $(MEM) $(THREADS) $(FEASTOL) $(LPS) $(DISPFREQ) $(CONTINUE) \
		$(QUEUETYPE) $(QUEUE) $(PPN) $(CLIENTTMPDIR) $(NOWAITCLUSTER) $(EXCLUSIVE) \
		$(PERMUTE) $(SEEDS) $(GLBSEEDSHIFT) $(STARTPERM) $(DEBUGTOOL) $(REOPT) $(OPTCOMMAND) \
                $(SETCUTOFF) $(VISUALIZE) $(CLUSTERNODES) $(EXCLUDENODES) $(SLURMACCOUNT) $(PYTHON) $(EMPHBENCHMARK);

.PHONY: tags
tags:
		rm -f TAGS; ctags -e src/*.c src/*.h src/*/*.h src/*/*.cpp $(SCIPDIR)/src/scip/*.c $(SCIPDIR)/src/scip/*.h;

-include	$(MAINOBJFILES:.o=.d)

# main target
$(MAINFILE):	$(BINDIR) $(OBJDIR) $(OBJSUBDIRS) $(MAINOBJFILES) $(SCIPLIBFILE) $(SCIPLIBBASEFILE) $(OBJSCIPLIBFILE) $(LPILIBFILE) $(TPILIBFILE) $(NLPILIBFILE)
		@echo "-> linking $@"
		$(LINKCXX) $(MAINOBJFILES) $(LINKCXXSCIPALL) $(LDFLAGS) $(LINKCXX_o)$@

$(OBJDIR)/%.o:	$(SRCDIR)/%.c | $(OBJDIR) $(OBJSUBDIRS)
		@echo "-> compiling $@"
		$(CC) $(FLAGS) $(OFLAGS) $(BINOFLAGS) $(CFLAGS) $(DFLAGS) -c $< $(CC_o)$@

$(OBJDIR)/%.o:	$(SRCDIR)/%.cpp | $(OBJDIR) $(OBJSUBDIRS)
		@echo "-> compiling $@"
		$(CXX) $(FLAGS) $(OFLAGS) $(BINOFLAGS) $(CXXFLAGS) $(DFLAGS) -c $< $(CXX_o)$@

$(OBJDIR)/%.o:  $(SRCDIR)/%.ispc | $(OBJDIR) $(OBJSUBDIRS)
		@echo "-> compiling ISPC $@"
		$(ISPC) -O3 --pic --target=${ISPC_TARGET} -h $(OBJDIR)/ispc.h $< $(CXX_o)$@

#---- EOF --------------------------------------------------------------------
