virtual std::string generateIndexedIndependent(const OperationNode<Base>& indexedIndep,
            const IndexPattern& ip) override {
        bool isX = indexedIndep.getInfo()[0] == 0;
        if (isX) {
            return _nameGen->generateIndexedIndependent(indexedIndep, ip);
        }

        size_t nIndex = indexedIndep.getArguments().size();

        CPPADCG_ASSERT_KNOWN(indexedIndep.getOperationType() == CGOpCode::LoopIndexedIndep, "Invalid node type");
        CPPADCG_ASSERT_KNOWN(nIndex > 0, "Invalid number of arguments");

        std::vector<const IndexDclrOperationNode<Base>*> indices(nIndex);
        for (size_t i = 0; i < nIndex; ++i) {// typically there is only one index but there may be more
            CPPADCG_ASSERT_KNOWN(indexedIndep.getArguments()[i].getOperation() != nullptr, "Invalid argument");
            CPPADCG_ASSERT_KNOWN(indexedIndep.getArguments()[i].getOperation()->getOperationType() == CGOpCode::Index, "Invalid argument");
            indices[i] = &static_cast<const IndexOperationNode<Base>&> (*indexedIndep.getArguments()[i].getOperation()).getIndex();
        }

        _ss.clear();
        _ss.str("");

        _ss << _multName << "[" << LanguageC<Base>::indexPattern2String(ip, indices) << "]";
        return _ss.str();
    }
    inline const IndexDclrOperationNode<Base>& getIndex() const {
        const std::vector<Argument<Base> >& args = this->getArguments();
        CPPADCG_ASSERT_KNOWN(!args.empty(), "Invalid number of arguments");

        OperationNode<Base>* aNode = args[0].getOperation();
        CPPADCG_ASSERT_KNOWN(aNode != nullptr && aNode->getOperationType() == CGOpCode::IndexDeclaration, "Invalid argument operation type");

        return static_cast<const IndexDclrOperationNode<Base>&> (*aNode);
    }
    LangCDefaultHessianVarNameGenerator(VariableNameGenerator<Base>* nameGen,
                                        const std::string& multName,
                                        size_t n) :
        _nameGen(nameGen),
        _minMultiplierID(n + 1),
        _multName(multName) {

        CPPADCG_ASSERT_KNOWN(_nameGen != nullptr, "The name generator must not be null");
        CPPADCG_ASSERT_KNOWN(_multName.size() > 0, "The name for the multipliers must not be empty");

        initialize();
    }
    inline ModelLibraryCSourceGen(ModelCSourceGen<Base>& headModel, Ms&... rest) :
        ModelLibraryCSourceGen(rest...) {
        CPPADCG_ASSERT_KNOWN(_models.find(headModel.getName()) == _models.end(),
                             "Another model with the same name was already registered");

        _models[headModel.getName()] = &headModel;
    }
    /**
     * Creates a new helper class for the generation of dynamic libraries
     * using the C language.
     * 
     * @param model A model compilation helper (must only be deleted after
     *              this object)
     */
    inline ModelLibraryCSourceGen(ModelCSourceGen<Base>& model):
        _multiThreading(MultiThreadingType::NONE) {
        CPPADCG_ASSERT_KNOWN(_models.find(model.getName()) == _models.end(),
                             "Another model with the same name was already registered");

        _models[model.getName()] = &model; // must not use initializer_list constructor of map!
    }
    /**
     * Adds additional models to be compiled into the created library.
     * 
     * @param model a model compilation helper (must only be deleted after
     *              this object)
     */
    inline void addModel(ModelCSourceGen<Base>& model) {
        CPPADCG_ASSERT_KNOWN(_models.find(model.getName()) == _models.end(),
                             "Another model with the same name was already registered");

        _models[model.getName()] = &model;

        _libSources.clear(); // must regenerate library sources again
    }
    LangCDefaultHessianVarNameGenerator(VariableNameGenerator<Base>* nameGen,
                                        size_t n) :
        _nameGen(nameGen),
        _minMultiplierID(n + 1),
        _multName("mult") {

        CPPADCG_ASSERT_KNOWN(_nameGen != nullptr, "The name generator must not be NULL");

        initialize();
    }
    LinuxDynamicLib(const std::string& dynLibName) :
        _dynLibName(dynLibName),
        _dynLibHandle(nullptr) {

        std::string path;
        if (dynLibName[0] == '/') {
            path = dynLibName; // absolute path
        } else if (!(dynLibName[0] == '.' && dynLibName[1] == '/') &&
                !(dynLibName[0] == '.' && dynLibName[1] == '.')) {
            path = "./" + dynLibName; // relative path
        } else {
            path = dynLibName;
        }

        // load the dynamic library
        _dynLibHandle = dlopen(path.c_str(), RTLD_NOW);
        CPPADCG_ASSERT_KNOWN(_dynLibHandle != nullptr, ("Failed to dynamically load library '" + dynLibName + "': " + dlerror()).c_str());

        // validate the dynamic library
        validate();
    }
inline std::string LanguageC<Base>::indexPattern2String(const IndexPattern& ip,
                                                        const std::vector<const IndexDclrOperationNode<Base>*>& indexes) {
    std::stringstream ss;
    switch (ip.getType()) {
        case IndexPatternType::Linear: // y = x * a + b
        {
            CPPADCG_ASSERT_KNOWN(indexes.size() == 1, "Invalid number of indexes");
            const LinearIndexPattern& lip = static_cast<const LinearIndexPattern&> (ip);
            return linearIndexPattern2String(lip, *indexes[0]);
        }
        case IndexPatternType::Sectioned:
        {
            CPPADCG_ASSERT_KNOWN(indexes.size() == 1, "Invalid number of indexes");
            const SectionedIndexPattern* lip = static_cast<const SectionedIndexPattern*> (&ip);
            const std::map<size_t, IndexPattern*>& sections = lip->getLinearSections();
            size_t sSize = sections.size();
            CPPADCG_ASSERT_UNKNOWN(sSize > 1);

            std::map<size_t, IndexPattern*>::const_iterator its = sections.begin();
            for (size_t s = 0; s < sSize - 1; s++) {
                const IndexPattern* lp = its->second;
                ++its;
                size_t xStart = its->first;

                ss << "(" << (*indexes[0]->getName()) << "<" << xStart << ")? "
                        << indexPattern2String(*lp, *indexes[0]) << ": ";
            }
            ss << indexPattern2String(*its->second, *indexes[0]);

            return ss.str();
        }

        case IndexPatternType::Plane2D: // y = f(x) + f(z)
        {
            CPPADCG_ASSERT_KNOWN(indexes.size() >= 1, "Invalid number of indexes");
            std::string indexExpr;
            const Plane2DIndexPattern& pip = static_cast<const Plane2DIndexPattern&> (ip);
            bool useParens = pip.getPattern1() != nullptr && pip.getPattern2() != nullptr;

            if (useParens) indexExpr += "(";

            if (pip.getPattern1() != nullptr)
                indexExpr += indexPattern2String(*pip.getPattern1(), *indexes[0]);

            if (useParens) indexExpr += ") + (";

            if (pip.getPattern2() != nullptr)
                indexExpr += indexPattern2String(*pip.getPattern2(), *indexes.back());

            if (useParens) indexExpr += ")";

            return indexExpr;
        }
        case IndexPatternType::Random1D:
        {
            CPPADCG_ASSERT_KNOWN(indexes.size() == 1, "Invalid number of indexes");
            const Random1DIndexPattern& rip = static_cast<const Random1DIndexPattern&> (ip);
            CPPADCG_ASSERT_KNOWN(!rip.getName().empty(), "Invalid name for array");
            return rip.getName() + "[" + (*indexes[0]->getName()) + "]";
        }
        case IndexPatternType::Random2D:
        {
            CPPADCG_ASSERT_KNOWN(indexes.size() == 2, "Invalid number of indexes");
            const Random2DIndexPattern& rip = static_cast<const Random2DIndexPattern&> (ip);
            CPPADCG_ASSERT_KNOWN(!rip.getName().empty(), "Invalid name for array");
            return rip.getName() + "[" + (*indexes[0]->getName()) + "][" + (*indexes[1]->getName()) + "]";
        }
        default:
            CPPADCG_ASSERT_UNKNOWN(false); // should never reach this
            return "";
    }
}
 inline IndexDclrOperationNode(const std::string& name) :
     OperationNode<Base>(CGOpCode::IndexDeclaration) {
     CPPADCG_ASSERT_KNOWN(!name.empty(), "index name cannot be empty");
     this->setName(name);
 }
 inline OperationNode<Base>& getIndexCreationNode() const {
     const std::vector<Argument<Base> >& args = this->getArguments();
     CPPADCG_ASSERT_KNOWN(!args.empty(), "Invalid number of arguments");
     CPPADCG_ASSERT_KNOWN(args.back().getOperation() != nullptr, "Invalid argument type");
     return *args.back().getOperation();
 }
    inline void setLibraryName(const std::string& libraryName) {
        CPPADCG_ASSERT_KNOWN(!libraryName.empty(), "Library name cannot be empty");

        _libraryName = libraryName;
    }
    void addCustomFunctionSource(const std::string& filename, const std::string& source) {
        CPPADCG_ASSERT_KNOWN(!filename.empty(), "The filename name cannot be empty");

        _customSource[filename] = source;
    }