1 #include <iostream>
2 #include <algorithm>
3 #include "mmn_csp_solver.h"
4 //:
5 // \file
6 // \brief see if the Constraint Satisfaction Problem is satisfiable
7 // \author Martin Roberts
8 
9 #ifdef _MSC_VER
10 #  include "vcl_msvc_warnings.h"
11 #endif
12 #include <cassert>
13 
14 //: Default constructor
mmn_csp_solver()15 mmn_csp_solver::mmn_csp_solver() { init(); }
16 
17 //: Construct with arcs
mmn_csp_solver(unsigned num_nodes,const std::vector<mmn_arc> & arcs)18 mmn_csp_solver::mmn_csp_solver(unsigned num_nodes,const std::vector<mmn_arc>& arcs):
19         nnodes_(num_nodes),verbose_(false)
20 {
21     init();
22     set_arcs(num_nodes,arcs);
23 }
24 
init()25 void mmn_csp_solver::init()
26 {
27 }
28 
29 //: Pass in the arcs, which are then used to build the graph object
set_arcs(unsigned num_nodes,const std::vector<mmn_arc> & arcs)30 void mmn_csp_solver::set_arcs(unsigned num_nodes,const std::vector<mmn_arc>& arcs)
31 {
32     nnodes_=num_nodes;
33     arcs_ = arcs;
34     //Verify consistency
35     unsigned max_node=0;
36     for (auto arc : arcs)
37     {
38         max_node=std::max(max_node,arc.max_v());
39     }
40     if (nnodes_ != max_node+1)
41     {
42         std::cerr<<"Arcs appear to be inconsistent with number of nodes in mmn_csp_solver::set_arcs\n"
43                 <<"Max node in Arcs is: "<<max_node<<" but number of nodes= "<<nnodes_ << '\n';
44     }
45 
46     graph_.build(nnodes_,arcs_);
47 }
48 
49 
50 //: Run the algorithm
operator ()(const std::vector<mmn_csp_solver::label_subset_t> & node_labels_subset,const std::vector<mmn_csp_solver::arc_labels_subset_t> & links_subset)51 bool mmn_csp_solver::operator()(const std::vector<mmn_csp_solver::label_subset_t >& node_labels_subset,
52                                 const std::vector<mmn_csp_solver::arc_labels_subset_t >& links_subset)
53 {
54     init();
55 
56     node_labels_present_ = node_labels_subset;
57     initialise_arc_labels_linked(links_subset);
58 
59 
60     bool deletedNode=false;
61     bool deletedArc=false;
62 
63     do
64     {
65         deletedNode = check_for_node_deletions();
66         deletedArc = check_for_arc_deletions();
67     }
68     while (deletedNode || deletedArc);
69 
70     bool emptyKernel=true;
71 
72     for (unsigned i=0; i<nnodes_;i++)
73     {
74         emptyKernel = emptyKernel && node_labels_present_[i].empty();
75     }
76 
77     return !emptyKernel;
78 }
79 
initialise_arc_labels_linked(const std::vector<mmn_csp_solver::arc_labels_subset_t> & links_subset)80 void  mmn_csp_solver::initialise_arc_labels_linked(const std::vector<mmn_csp_solver::arc_labels_subset_t >& links_subset)
81 {
82     arc_labels_linked1_.clear();
83     arc_labels_linked2_.clear();
84     unsigned narcs=arcs_.size();
85     arc_labels_linked1_.resize(narcs);
86     arc_labels_linked2_.resize(narcs);
87 
88     for (unsigned iarc=0;iarc<narcs;++iarc)
89     {
90         arc_labels_subset_t1& labels_linked1=arc_labels_linked1_[iarc];
91         arc_labels_subset_t2& labels_linked2=arc_labels_linked2_[iarc];
92 
93         auto linkIter=links_subset[iarc].begin();
94         auto linkIterEnd=links_subset[iarc].end();
95         while (linkIter != linkIterEnd)
96         {
97             labels_linked1.insert(*linkIter);
98             labels_linked2.insert(*linkIter);
99             ++linkIter;
100         }
101     }
102 }
103 
check_for_node_deletions()104 bool mmn_csp_solver::check_for_node_deletions()
105 {
106     bool deleted=false;
107     for (unsigned inode=0;inode<nnodes_;++inode)
108     {
109         auto labelIter=node_labels_present_[inode].begin();
110         auto labelIterEnd=node_labels_present_[inode].end();
111         const std::vector<std::pair<unsigned,unsigned> >& neighbourhood = graph_.node_data()[inode];
112         while (labelIter != labelIterEnd)
113         {
114             unsigned label = *labelIter; //this label value
115             //Now loop over all arcs in the node's neighbourhood
116             auto neighIter=neighbourhood.begin();
117             auto neighIterEnd=neighbourhood.end();
118             bool found=true;
119             while (neighIter != neighIterEnd)
120             {
121                 bool foundThisNeighbour=false;
122                 unsigned arcId=neighIter->second;
123                 if (inode<neighIter->first)
124                 {
125                     std::pair<unsigned ,unsigned > sought(label,0);
126                     auto linkIter=arc_labels_linked1_[arcId].lower_bound(sought);
127                     if (linkIter != arc_labels_linked1_[arcId].end())
128                     {
129                         if (linkIter->first==label)
130                         {
131                             foundThisNeighbour=true;
132                         }
133                     }
134                 }
135                 else
136                 {
137                     std::pair<unsigned ,unsigned > sought(0,label);
138                     auto linkIter=arc_labels_linked2_[arcId].lower_bound(sought);
139                     if (linkIter != arc_labels_linked2_[arcId].end())
140                     {
141                         if (linkIter->second==label)
142                         {
143                             foundThisNeighbour=true;
144                         }
145                     }
146                 }
147                 found = found && foundThisNeighbour;
148                 if (!foundThisNeighbour)
149                 {
150                     if (verbose_)
151                     {
152                         std::cout<<"Found no arc linking labels for node "<<inode<<" label "<<label<<" to node "<<neighIter->first<<"along arc ID "<<arcId<<std::endl;
153                     }
154                     break;
155                 }
156                 ++neighIter;
157             } //loop over all neighbours (pencils)
158 
159             if (!found)
160             {
161                 //Found no links from this label to anywhere
162                 //So delete it
163                 auto labelIterNext=labelIter;
164                 ++labelIterNext;
165                 if (verbose_)
166                 {
167                     std::cout<<"Have removed label "<<*labelIter<<" for node "<<inode<<" as it has no linking arcs"<<std::endl;
168                 }
169                 node_labels_present_[inode].erase(labelIter);
170                 labelIter=labelIterNext;
171                 deleted=true;
172             }
173             else
174             {
175                 ++labelIter;
176             }
177         } //next label of this node (object)
178     } //next node (object)
179     return deleted;
180 }
181 
check_for_arc_deletions()182 bool mmn_csp_solver::check_for_arc_deletions()
183 {
184     bool deleted=false;
185     for (unsigned iarc=0;iarc<arcs_.size();++iarc)
186     {
187         arc_labels_subset_t1& labels_linked1=arc_labels_linked1_[iarc];
188         arc_labels_subset_t2& labels_linked2=arc_labels_linked2_[iarc];
189         auto linkIter=labels_linked1.begin();
190         auto linkIterEnd=labels_linked1.end();
191         while (linkIter != linkIterEnd)
192         {
193             unsigned label1=linkIter->first;
194             unsigned label2=linkIter->second;
195             unsigned node1=arcs_[iarc].min_v();
196             unsigned node2=arcs_[iarc].max_v();
197             assert(node1<node2);
198             std::set<unsigned>& labelSet1=node_labels_present_[node1];
199 
200             bool found=false;
201             if (labelSet1.find(label1)!=labelSet1.end())
202             {
203                 std::set<unsigned>& labelSet2=node_labels_present_[node2];
204                 found = labelSet2.find(label2)!=labelSet2.end();
205             }
206             if (!found) //failed to find at least one of target labels
207             {
208                 deleted=true;
209                 //std::pair<unsigned,unsigned > pair2(linkIter->second,linkIter->first); //transpose
210                 std::pair<unsigned,unsigned > pair2(linkIter->first,linkIter->second); //transpose
211 
212                 labels_linked1.erase(linkIter++); //remove from multset 1
213                 //Find all possible instances in multiset 2 for removal
214                 std::pair<arc_labels_subset_t2::iterator,arc_labels_subset_t2::iterator> range=
215                     labels_linked2.equal_range(pair2);
216                 auto killer=range.first;
217 
218                 while (killer != range.second)
219                 {
220                     if (killer->first==pair2.first)
221                     {
222                         //remove target link
223                         labels_linked2.erase(killer++);
224                         if (verbose_)
225                         {
226                             std::cout<<"Have removed arc Id "<<iarc<<" Linking nodes "<<node1<<'\t'<<node2
227                                     <<" for respective labels "<<pair2.second<<'\t'<<pair2.first<<std::endl;
228                         }
229                     }
230                     else
231                     {
232                         ++killer;
233                     }
234                 }
235             }
236             else
237             {
238                 ++linkIter;
239             }
240         }
241     }
242     return deleted;
243 }
244