diff --git a/.gitignore b/.gitignore
index e0e9b8b..ad9d7f7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
 __pycache__/
 .nox/
+*.d
+/SolverComponent
diff --git a/AMPLSolver.cpp b/AMPLSolver.cpp
index 198afe4..84aee4f 100644
--- a/AMPLSolver.cpp
+++ b/AMPLSolver.cpp
@@ -161,8 +161,11 @@ void AMPLSolver::SolveProblem(
   // objective functions as 'dropped'. Note that this is experimental code
   // as the multi-objective possibilities in AMPL are not well documented.
 
+  std::string 
+  OptimisationGoal = TheContext.at( Solver::ObjectiveFunctionLabel );
+
   for( auto TheObjective : ProblemDefinition.getObjectives() )
-    if( TheObjective.name() == TheContext.at( Solver::ObjectiveFunctionLabel ) )
+    if( TheObjective.name() == OptimisationGoal )
       TheObjective.restore();
     else
       TheObjective.drop();
diff --git a/Bin/.gitignore b/Bin/.gitignore
new file mode 100644
index 0000000..31dc307
--- /dev/null
+++ b/Bin/.gitignore
@@ -0,0 +1,2 @@
+*.d
+*.o
diff --git a/MetricUpdater.cpp b/MetricUpdater.cpp
index 3af6e15..19f6623 100644
--- a/MetricUpdater.cpp
+++ b/MetricUpdater.cpp
@@ -87,6 +87,12 @@ void MetricUpdater::AddMetricSubscription( const MetricTopic & TheMetrics,
 // The sender address will contain the metric topic, but this will contain the
 // generic metric prediction root string, and this string must be removed 
 // before the metric name can be updated. 
+//
+// Note that the map's [] operator cannot be used to look up the topic in the
+// current map because it assumes the implicit creation of non-existing keys,
+// which means that an empty metric value record should be constructed first
+// and then used. To modify the existing record, the 'at' function must be 
+// used.
 
 void MetricUpdater::UpdateMetricValue( 
      const MetricValueUpdate & TheMetricValue, const Address TheMetricTopic)
@@ -96,8 +102,8 @@ void MetricUpdater::UpdateMetricValue(
         
   if( MetricValues.contains( TheTopic ) )
   {
-    MetricValues[ TheTopic ].Value = TheMetricValue[ NebulOuS::ValueLabel ];
-
+    MetricValues.at( TheTopic ).Value = TheMetricValue[ NebulOuS::ValueLabel ];
+    
     ValidityTime = std::max( ValidityTime, 
       TheMetricValue[ NebulOuS::TimePoint ].get< Solver::TimePointType >() );
   }
diff --git a/MetricUpdater.hpp b/MetricUpdater.hpp
index 85d0215..5eada0e 100644
--- a/MetricUpdater.hpp
+++ b/MetricUpdater.hpp
@@ -164,7 +164,7 @@ private:
     const std::string OptimisationName;
     JSON              Value;
 
-    MetricValueRecord( const std::string & TheName, JSON InitialValue )
+    MetricValueRecord( const std::string & TheName, const JSON InitialValue )
     : OptimisationName( TheName ), Value( InitialValue )
     {}
 
diff --git a/SolverComponent.cpp b/SolverComponent.cpp
index e63e34f..8f85fe9 100644
--- a/SolverComponent.cpp
+++ b/SolverComponent.cpp
@@ -46,16 +46,10 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/)
 // Standard headers
 
 #include <string>           // For standard strings
-// #include <memory>           // For smart pointers
 #include <source_location>  // Making informative error messages
 #include <sstream>          // To format error messages
 #include <stdexcept>        // standard exceptions
 #include <filesystem>       // Access to the file system
-// #include <initializer_list> // To unpack variable arguments
-// #include <concepts>         // To constrain types
-// #include <vector>           // To store subscribed topics
-// #include <thread>           // To sleep while waiting for termination
-// #include <chrono>           // To have a concept of fime
 
 // Theron++ headers
 
@@ -89,10 +83,9 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/)
 
 /*==============================================================================
 
- Main file
+ Main
 
 ==============================================================================*/
-//
 
 int main( int NumberOfCLIOptions, char ** CLIOptionStrings )
 {
@@ -201,12 +194,19 @@ int main( int NumberOfCLIOptions, char ** CLIOptionStrings )
   // a parameter to the constructor of the Metric Updater so the latter actor 
   // knows where to send application execution contexts whenever a new solution
   // is requested by the SLO Violation Detector through the Optimzer Controller.
+  // Then follows the number of solvers to use in the solver pool and the root 
+  // name of the solvers. This root name string will be extended with _n where n
+  // where n is a sequence number from 1.As all solvers are of the same type 
+  // given by the template parameter (here AMPLSolver), they are assumed to need
+  // the same set of constructor arguments and the constructor arguments follow
+  // the root solver name.
 
   NebulOuS::SolverManager< NebulOuS::AMPLSolver > 
   WorkloadMabager( "WorkloadManager", 
     std::string( NebulOuS::Solver::Solution::MessageIdentifier ), 
     std::string( NebulOuS::Solver::ApplicationExecutionContext::MessageIdentifier ),
-    "AMPLSolver", ampl::Environment( TheAMPLDirectory.native() ), ModelDirectory );
+    1, "AMPLSolver", 
+    ampl::Environment( TheAMPLDirectory.native() ), ModelDirectory );
 
   NebulOuS::MetricUpdater 
   ContextMabager( "MetricUpdater", WorkloadMabager.GetAddress() );
diff --git a/SolverManager.hpp b/SolverManager.hpp
index 7f91358..6392f1c 100644
--- a/SolverManager.hpp
+++ b/SolverManager.hpp
@@ -49,11 +49,13 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/)
 #include <list>                                 // Pool of local solvers
 #include <ranges>                               // Range based views
 #include <algorithm>                            // Standard algorithms
+#include <iterator>                             // For inserters
 #include <sstream>                              // For nice error messages
 #include <stdexcept>                            // Standard exceptions
 #include <source_location>                      // Error location reporting
 #include <condition_variable>                   // Execution stop management
 #include <mutex>                                // Lock the condtion variable
+#include <tuple>                                // For constructing solvers
 
 // Other packages
 
@@ -143,7 +145,7 @@ private:
     if( !PassiveSolvers.empty() && !ContextExecutionQueue.empty() )
     {
       for( const auto & [ SolverAddress, ContextElement ] : 
-          ranges::views::zip( PassiveSolvers, ContextExecutionQueue ) )
+          std::ranges::views::zip( PassiveSolvers, ContextExecutionQueue ) )
         Send( Contexts.at( ContextElement.second ), SolverAddress );
 
       // The number of contexts dispatched must equal the minimum of the 
@@ -156,13 +158,15 @@ private:
 
       std::ranges::move( 
         std::ranges::subrange( PassiveSolvers.begin(), 
-                               PassiveSolvers.begin() + DispatchedContexts ),
-        std::inserter( ActiveSolvers ) );
+                std::ranges::next( PassiveSolvers.begin(), DispatchedContexts, 
+                                   PassiveSolvers.end() ) ),
+        std::inserter( ActiveSolvers, ActiveSolvers.end() ) );
 
       // Then the dispatched context identifiers are removed from queue
 
       ContextExecutionQueue.erase( ContextExecutionQueue.begin(), 
-        ContextExecutionQueue.begin() + DispatchedContexts );
+        std::ranges::next( ContextExecutionQueue.begin(), DispatchedContexts,
+                           ContextExecutionQueue.end() ) );
     }
   }
 
@@ -216,7 +220,7 @@ private:
   // contexts, if any.
 
   void PublishSolution( const Solver::Solution & TheSolution, 
-                        const Addres TheSolver )
+                        const Address TheSolver )
   {
     Send( TheSolution, SolutionReceiver );
     PassiveSolvers.insert( ActiveSolvers.extract( TheSolver ) );
@@ -243,10 +247,13 @@ private:
 
 public:
 
+  template< typename ...SolverArgTypes >
   SolverManager( const std::string & TheActorName, 
-                const Theron::AMQ::TopicName & SolutionTopic,
-                const Theron::AMQ::TopicName & ContextPublisherTopic,
-                const auto & ...SolverArguments )
+                 const Theron::AMQ::TopicName & SolutionTopic,
+                 const Theron::AMQ::TopicName & ContextPublisherTopic,
+                 const unsigned int NumberOfSolvers,
+                 const std::string SolverRootName,
+                 SolverArgTypes && ...SolverArguments )
   : Actor( TheActorName ),
     StandardFallbackHandler( Actor::GetAddress().AsString() ),
     NetworkingActor( Actor::GetAddress().AsString() ),
@@ -256,10 +263,22 @@ public:
     Contexts(), ContextExecutionQueue()
   {
     // The solvers are created by expanding the arguments for the solvers 
-    // one by one creating new elements in the solver pool
+    // one by one creating new elements in the solver pool. The solvers 
+    // will be named with a sequence number from 1 and up added to the 
+    // root solver name, e.g., if the root name is "MySolver" the solvers
+    // will have names "MySolver_1", "MySolver_2",... and so forth. Since
+    // all solvers are of the same type they should take the same arguments
+    // and so the given arguments are just fowarded to each solver constructor.
 
-    ( SolverPool.emplace_back( std::forward( SolverArguments ) ), ... );
+    for( unsigned int i = 1; i <= NumberOfSolvers; i++ )
+    {
+      std::ostringstream TheSolverName;
 
+      TheSolverName << SolverRootName << "_" << i;
+      SolverPool.emplace_back( TheSolverName.str(), 
+                 std::forward< SolverArgTypes >(SolverArguments)... );
+    }
+    
     // If the solvers were successfully created, their addresses are recorded as
     // passive servers, and a publisher is made for the solution channel, and 
     // optionally, a subscritpion is made for the alternative context publisher 
@@ -268,8 +287,9 @@ public:
 
     if( !SolverPool.empty() )
     {
-      std::ranges::transform( ServerPool, std::inserter( PassiveSolvers ),
-      [](const SolverType & TheSolver){ return TheSolver.GetAddress(); } );
+      std::ranges::transform( SolverPool, 
+        std::inserter( PassiveSolvers, PassiveSolvers.end() ),
+        [](const SolverType & TheSolver){ return TheSolver.GetAddress(); } );
 
       Send( Theron::AMQ::NetworkLayer::TopicSubscription( 
             Theron::AMQ::NetworkLayer::TopicSubscription::Action::Publisher, 
diff --git a/makefile b/makefile
index 8e661de..db988a2 100644
--- a/makefile
+++ b/makefile
@@ -22,6 +22,17 @@ RM = rm -f
 
 THERON = /home/GHo/Documents/Code/Theron++
 
+# Location of the AMPL API directory
+
+AMPL_INCLUDE = /opt/AMPL/amplapi/include
+
+# The solver component uses the CxxOpts class for parsing the command line 
+# options since it is header only and lighter than the Options library of 
+# boost, which seems to have lost the most recent C++ features. The CxxOpts
+# library can be cloned from https://github.com/jarro2783/cxxopts
+
+CxxOpts_DIR = /home/GHo/Documents/Code/CxxOpts/include
+
 # Optimisation -O3 is the highest level of optimisation and should be used 
 # with production code. -Og is the code optimising and offering debugging 
 # transparency and should be use while the code is under development
@@ -40,7 +51,8 @@ DEPENDENCY_FLAGS = -MMD -MP
 # Options 
 
 GENERAL_OPTIONS = -Wall -std=c++23 -ggdb -D_DEBUG
-INCLUDE_DIRECTORIES = -I. -I/usr/include -I$(THERON)
+INCLUDE_DIRECTORIES = -I. -I/usr/include -I$(THERON) -I$(AMPL_INCLUDE) \
+					  -I$(CxxOpts_DIR)
 
 CXXFLAGS = $(GENERAL_OPTIONS) $(INCLUDE_DIRECTORIES) $(DEPENDENCY_FLAGS) \
 		   $(OPTIMISATION_FLAG)
@@ -55,7 +67,7 @@ CXXFLAGS = $(GENERAL_OPTIONS) $(INCLUDE_DIRECTORIES) $(DEPENDENCY_FLAGS) \
 
 CFLAGS = $(DEPENDENCY_FLAGS) $(OPTIMISATION_FLAG) $(GENERAL_OPTIONS)
 LDFLAGS = -fuse-ld=gold -ggdb -D_DEBUG -pthread -l$(THERON)/Theron++.a \
-		  -lqpid-proton-cpp
+		  -lqpid-proton-cpp -l/opt/AMPL/amplapi/lib/libampl.so
 
 #------------------------------------------------------------------------------
 # Theron library
@@ -82,29 +94,34 @@ OBJECTS_DIR = Bin
 # Listing the actors' source files and expected object files
 
 SOLVER_SOURCE = $(wildcard *.cpp)
-SOLVER_OBJECTS = $(addprefix $(OBJECTS_DIR)/, $(SOLVER_SOURCE:.cpp=.o)
+SOLVER_OBJECTS = $(addprefix $(OBJECTS_DIR)/, $(SOLVER_SOURCE:.cpp=.o) )
 
 # Since all source files are in the same directory as the make file and the
 # component's objective file, they can be built by a general rule
 
 $(OBJECTS_DIR)/%.o : %.cpp
-	$(CXX) $(CXXFLAGS) $< -o $@ $(INCLUDE_DIRECTORIES)
+	$(CXX) $(CXXFLAGS) -c $< -o $@ $(INCLUDE_DIRECTORIES)
 
 #------------------------------------------------------------------------------
 # Solver component
 #------------------------------------------------------------------------------
 #
-# The solver component uses the CxxOpts class for parsing the command line 
-# options since it is header only and lighter than the Options library of 
-# boost, which seems to have lost the most recent C++ features. The CxxOpts
-# library can be cloned from https://github.com/jarro2783/cxxopts
-
-CxxOpts_DIR = /home/GHo/Documents/Code/CxxOpts/include
 
 # The only real target is to build the solver component whenever some of 
 # the object files or the solver actors.
 
-SolverComponent: SolverComponent.cpp $(SOLVER_OBJECTS) $(THERON)/Theron++.a
-	$(CXX) SolverComponent.cpp -o SolverComponent $(CXXFLAGS) \
-	-I$(CxxOpts_DIR) $(LDFLAGS)
+SolverComponent: $(SOLVER_OBJECTS) $(THERON)/Theron++.a
+	$(CXX) -o SolverComponent $(CXXFLAGS) $(SOLVER_OBJECTS) $(LDFLAGS)
 
+# There is also a standard target to clean the automatically generated build 
+# files
+
+clean:
+	$(RM) $(OBJECTS_DIR)/*.o $(OBJECTS_DIR)/*.d
+
+#------------------------------------------------------------------------------
+# Dependencies
+#------------------------------------------------------------------------------
+#
+
+-include $(SOLVER_OBJECTS:.o=.d)
\ No newline at end of file