diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp
index 8f17048e3..f6f03add8 100644
--- a/src/tactic/portfolio/parallel_tactic.cpp
+++ b/src/tactic/portfolio/parallel_tactic.cpp
@@ -142,15 +142,16 @@ class parallel_tactic : public tactic {
     };
 
     class solver_state {
-        task_type       m_type;
-        expr_ref_vector m_cubes, m_asserted_cubes;
-        params_ref      m_params;
-        scoped_ptr<ast_manager> m_manager;
-        ref<solver>     m_solver;
-        unsigned        m_depth;
-        unsigned        m_width;
-        unsigned        m_cube_cutoff;
-        double          m_cube_fraction;
+        task_type       m_type;                   // current work role of the task
+        expr_ref_vector m_cubes;                  // set of cubes to process by task
+        expr_ref_vector m_asserted_cubes;         // set of cubes asserted on the current solver
+        params_ref      m_params;                 // configuration parameters
+        scoped_ptr<ast_manager> m_manager;        // ownership handle to ast_manager
+        ref<solver>     m_solver;                 // solver state
+        unsigned        m_depth;                  // number of nested calls to cubing
+        unsigned        m_width;                  // estimate of fraction of problem handled by state
+        unsigned        m_cube_cutoff;            // saved configuration value
+        double          m_cube_fraction;          // saved configuration value
 
         expr_ref_vector cube_literals(expr* cube) {
             expr_ref_vector literals(m());
@@ -184,10 +185,6 @@ class parallel_tactic : public tactic {
 
         solver const& get_solver() const { return *m_solver; }
 
-        params_ref const& params() const { return m_params; }
-
-        params_ref& params() { return m_params; }        
-        
         solver_state* clone() {
             SASSERT(!m_cubes.empty());
             ast_manager& m = m_solver->get_manager();
@@ -238,8 +235,13 @@ class parallel_tactic : public tactic {
                 if (r != l_undef) return r;
                 
                 // copy over the resulting clauses with a configuration that blasts PB constraints
-                set_simplify_params(false, true);        
-                m_solver = get_solver().translate(m(), m_params);
+                set_simplify_params(false, true);
+                expr_ref_vector fmls(m());
+                get_solver().get_assertions(fmls);
+                model_converter_ref mc = get_solver().get_model_converter();
+                m_solver = mk_fd_solver(m(), m_params);
+                m_solver->set_model_converter(mc.get());
+                m_solver->assert_expr(fmls);
             }
             set_simplify_params(false, true);         // remove PB, retain blocked (TBD, sat solver does not blast PB constraints on its own)
             r = get_solver().check_sat(0,0);
@@ -271,11 +273,13 @@ class parallel_tactic : public tactic {
             }
             m_params.set_uint ("sat.lookahead.cube.cutoff", depth);
             m_params.set_double("sat.lookahead.cube.fraction", fraction);
+            get_solver().updt_params(m_params);
         }
         
         void set_conquer_params() {            
             m_params.set_bool("sat.lookahead_simplify", false);
             m_params.set_uint("sat.restart.max", 10);
+            get_solver().updt_params(m_params);
         }
 
         void set_simplify_params(bool pb_simp, bool retain_blocked) {
@@ -288,6 +292,7 @@ class parallel_tactic : public tactic {
             m_params.set_sym ("sat.pb.solver", pb_simp ? symbol("solver") : symbol("circuit"));
             m_params.set_uint("sat.restart.max", UINT_MAX);
             m_params.set_bool("sat.retain_blocked_clauses", retain_blocked);
+            get_solver().updt_params(m_params);
         }
 
         bool canceled() { 
@@ -296,7 +301,7 @@ class parallel_tactic : public tactic {
 
         std::ostream& display(std::ostream& out) {
             out << ":depth " << m_depth << " :width " << m_width << "\n";
-            out << ":asserted cubes " << m_asserted_cubes << "\n";
+            out << ":asserted " << m_asserted_cubes.size() << "\n";
             return out;
         }
     };    
@@ -313,12 +318,14 @@ private:
     double       m_progress;
     bool         m_has_undef;
     bool         m_allsat;
+    unsigned     m_num_unsat;
 
     void init() {
         m_num_threads = 2 * omp_get_num_procs();  // TBD adjust by possible threads used inside each solver.
         m_progress = 0;
         m_has_undef = false;
         m_allsat = false;
+        m_num_unsat = 0;
     }
 
     void close_branch(solver_state& s, lbool status) {
@@ -329,7 +336,6 @@ private:
         IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :progress " << m_progress << " " << st << ")\n";);
     }
 
-
     void report_sat(solver_state& s) {
         close_branch(s, l_true);
         model_ref mdl;
@@ -347,8 +353,10 @@ private:
         }
     }
 
-    void report_unsat(solver_state& s) {
+    void report_unsat(solver_state& s) {        
         close_branch(s, l_false);
+        std::lock_guard<std::mutex> lock(m_mutex);
+        ++m_num_unsat;
     }
         
     void report_undef(solver_state& s) {
@@ -357,7 +365,7 @@ private:
     }
 
     void cube_and_conquer(solver_state& s) {
-        ast_manager& m = s.get_solver().get_manager();
+        ast_manager& m = s.m();
         expr_ref_vector cubes(m), cube(m), hard_cubes(m);
 
         switch (s.type()) {
@@ -365,7 +373,6 @@ private:
         case conquer_task: goto conquer;
         }
 
-
     cube:
         SASSERT(s.type() == cube_task);
 
@@ -374,22 +381,18 @@ private:
         cube.reset();
         cube.append(s.split_cubes(1));
         SASSERT(cube.size() <= 1);
-
-        if (!s.cubes().empty()) {
-            m_queue.add_task(s.clone());
-        }
+        if (!s.cubes().empty()) m_queue.add_task(s.clone());
         if (!cube.empty()) s.assert_cube(cube.get(0));
-        
+
+        // simplify
         switch (s.simplify()) {
         case l_undef: break;
         case l_true:  report_sat(s); return;
         case l_false: report_unsat(s); return;                
         }
-
         if (s.canceled()) return;
         
         // extract cubes.
-
         cubes.reset();
         s.set_cube_params();
         while (true) {
@@ -418,16 +421,13 @@ private:
             goto conquer;
         }
 
-    conquer:
-        
+    conquer:        
         SASSERT(s.type() == conquer_task);
 
         // extract a batch of cubes
         cubes.reset();
         cubes.append(s.split_cubes(conquer_batch_size()));
-        if (!s.cubes().empty()) {
-            m_queue.add_task(s.clone());
-        }
+        if (!s.cubes().empty()) m_queue.add_task(s.clone());
 
         s.set_conquer_params();
         hard_cubes.reset();
@@ -440,29 +440,33 @@ private:
             if (s.canceled()) return;
         }
         IF_VERBOSE(1, verbose_stream() << "(parallel_tactic :cubes " << cubes.size() << " :hard-cubes" << hard_cubes.size() << ")";);
-        if (!hard_cubes.empty()) {
-            s.set_cubes(hard_cubes);
-            s.set_type(cube_task);
-            goto cube;
-        }
-        else {
-            return;
-        }
+        if (hard_cubes.empty()) return;
+
+        s.set_cubes(hard_cubes);
+        s.set_type(cube_task);
+        goto cube;        
     }
 
     void run_solver() {
-        while (solver_state* st = m_queue.get_task()) {
-            cube_and_conquer(*st);
-            {
-                std::lock_guard<std::mutex> lock(m_mutex);
-                st->get_solver().collect_statistics(m_stats);
+        try {
+            while (solver_state* st = m_queue.get_task()) {
+                cube_and_conquer(*st);
+                collect_statistics(*st);
+                m_queue.task_done(st);
+                if (st->m().canceled()) m_queue.shutdown();
+                IF_VERBOSE(1, display(verbose_stream()););
+                dealloc(st);
             }
-            m_queue.task_done(st);
-            if (st->m().canceled()) {
-                m_queue.shutdown();
-            }
-            dealloc(st);
         }
+        catch (z3_exception& ex) {
+            std::cout << ex.msg() << "\n";
+            m_queue.shutdown();
+        }
+    }
+
+    void collect_statistics(solver_state& s) {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        s.get_solver().collect_statistics(m_stats);
     }
 
     lbool solve(model_ref& mdl) {        
@@ -474,16 +478,19 @@ private:
             t.join();
         }
         if (!m_models.empty()) {
-            mdl = m_models.back();
+            mdl = m_models.back();            
             return l_true;
         }
-        if (m_has_undef) return l_undef;
+        if (m_has_undef || m_manager.canceled()) 
+            return l_undef;
         return l_false;
     }
 
     std::ostream& display(std::ostream& out) {
         m_stats.display(out);
         m_queue.display(out);
+        std::lock_guard<std::mutex> lock(m_mutex);
+        out << "(parallel_tactic :unsat " << m_num_unsat << " :progress " << m_progress << " :models " << m_models.size() << ")\n";
         return out;
     }
 
@@ -555,7 +562,6 @@ public:
     }
 
     virtual void collect_statistics(statistics & st) const {
-        // m_queue.collect_statistics(st);
         st.copy(m_stats);
     }
     virtual void reset_statistics() {