Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

Resistance.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file Resistance.cpp
00003 
00004     Resistance/energy calculation based very closely on Six's circuit
00005     implementation.
00006 
00007     We use the same open source code to solve the linear system that
00008     Six uses. We actually tried linking with two different external
00009     linear algebra libraries (GNU Scientific library and
00010     boost::numeric::ublas) but both fail in some instances that our
00011     current code handles without complaint.
00012 
00013     These instances seem to include a linear dependence among the rows
00014     of our G matrix. In this simplest case, this can happen if one
00015     group's set of connections is a superset of another group's. We
00016     haven't been able to find a way around this, as any fix seems more
00017     expensive than worthwhile.
00018 
00019     We also hoped these external libraries would be faster; again,
00020     this does not appear to be the case. 
00021 
00022     It is possible that a more powerful library like LAPACK would
00023     address both of these issues, but the hassle of adding this
00024     external dependency to benzene probably outweighs the gain.    
00025 */
00026 //----------------------------------------------------------------------------
00027 
00028 #include <cmath>
00029 
00030 #include "Hex.hpp"
00031 #include "BitsetIterator.hpp"
00032 #include "VCSet.hpp"
00033 #include "Resistance.hpp"
00034 #include "Pattern.hpp"
00035 #include "HashedPatternSet.hpp"
00036 
00037 #include "lssolve.h"
00038 
00039 using namespace benzene;
00040 
00041 //----------------------------------------------------------------------------
00042 
00043 Resistance::Resistance()
00044     : m_score(0),
00045       m_simulate_and_over_edge(false)
00046 {
00047 }
00048 
00049 Resistance::~Resistance()
00050 {
00051 }
00052 
00053 //----------------------------------------------------------------------------
00054 
00055 void Resistance::Evaluate(const HexBoard& brd)
00056 {
00057     AdjacencyGraph graph[BLACK_AND_WHITE];
00058     ResistanceUtil::AddAdjacencies(brd, graph);
00059     Evaluate(brd, graph);
00060 }
00061 
00062 void Resistance::Evaluate(const HexBoard& brd, 
00063                           AdjacencyGraph graph[BLACK_AND_WHITE])
00064 {
00065     ConductanceValues values;
00066 
00067     // augment connection graph if option is on
00068     if (m_simulate_and_over_edge)
00069         ResistanceUtil::SimulateAndOverEdge(brd, graph);
00070 
00071     for (BWIterator c; c; ++c) 
00072         ComputeScores(*c, brd.GetGroups(), graph[*c], values, m_scores[*c]);
00073     ComputeScore();
00074 }
00075 
00076 void Resistance::Evaluate(const Groups& groups, 
00077                           AdjacencyGraph graph[BLACK_AND_WHITE])
00078 {
00079     ConductanceValues values;
00080     for (BWIterator c; c; ++c) 
00081         ComputeScores(*c, groups, graph[*c], values, m_scores[*c]);
00082     ComputeScore();
00083 }
00084 
00085 //----------------------------------------------------------------------------
00086 
00087 namespace
00088 {
00089     /** Sets all cell scores to an explicitly undefined value. */
00090     void SetAllToInfinity(const StoneBoard& brd, HexEval* out)
00091     {
00092         for (BoardIterator it(brd.Const().Interior()); it; ++it) 
00093             out[*it] = EVAL_INFINITY;
00094     }
00095 
00096     /** Returns the conductance between two cells by comparing their
00097         colors and whether they are connected or not. */
00098     double Conductance(const StoneBoard& brd, HexColor color, 
00099                        HexPoint a, HexPoint b, bool connected,
00100                        const ConductanceValues& values)
00101     {
00102         if (!connected)
00103             return values.no_connection;
00104     
00105         HexColor ac = brd.GetColor(a);
00106         HexColor bc = brd.GetColor(b);
00107 
00108         if (ac == EMPTY && bc == EMPTY)
00109             return values.empty_to_empty;
00110         
00111         if (ac == color && bc == color)
00112             return values.color_to_color;
00113         
00114         return values.color_to_empty;
00115     }
00116 }
00117 
00118 void Resistance::ComputeScores(HexColor color, const Groups& groups,
00119                                const AdjacencyGraph& graph, 
00120                                const ConductanceValues& values, 
00121                                HexEval* out)
00122 {
00123     const StoneBoard& brd = groups.Board();
00124     SetAllToInfinity(brd, out);
00125 
00126     const HexColorSet not_other = HexColorSetUtil::ColorOrEmpty(color);
00127     const HexPoint source = HexPointUtil::colorEdge1(color);
00128     const HexPoint sink = HexPointUtil::colorEdge2(color);
00129     const int n = groups.NumGroups(not_other) - 1;
00130 
00131     // Compute index that does not contain the sink
00132     int pointToIndex[BITSETSIZE];
00133     HexPoint indexToPoint[BITSETSIZE];
00134     {
00135         int index = 0;
00136         for (GroupIterator i(groups, not_other); i; ++i)
00137         {
00138             if (i->Captain() == sink)
00139                 continue;
00140             pointToIndex[i->Captain()] = index;
00141             indexToPoint[index] = i->Captain();
00142             index++;
00143         }
00144     }
00145 
00146     // Compute conductances between groups
00147     Mat<double> G(n, n);
00148     std::vector<double> sinkG(n, 0.0);
00149     G = 0.0;
00150     for (int i = 0; i < n; ++i)
00151     {
00152         HexPoint ip = indexToPoint[i];
00153         for (int j = 0; j < i; ++j)
00154         {
00155             HexPoint jp = indexToPoint[j];
00156             double c = Conductance(brd, color, ip, jp, graph[ip][jp], values);
00157             G(i, i) += c;
00158             G(j, j) += c;
00159             G(i, j) -= c;
00160             G(j, i) -= c;                
00161         }
00162         double c = Conductance(brd, color, ip, sink, graph[ip][sink], values);
00163         G(i, i) += c;
00164         sinkG[i] += c;
00165     }
00166 
00167     // Put some current on the source
00168     Vec<double> I(n);
00169     I = 0.0;
00170     I[pointToIndex[source]] = 1.0;
00171 
00172     // Solve for voltages
00173     const Vec<double>& V = lsSolve(G, I);
00174     m_resistance[color] = fabs(V[pointToIndex[source]]);
00175 
00176     // Compute energy
00177     for (int i = 0; i < n; ++i)
00178     {
00179         double sum = fabs(sinkG[i] * V[i]);
00180         for (int j = 0; j < n; ++j)
00181             sum += fabs(G(i,j) * (V[i] - V[j]));
00182         out[indexToPoint[i]] = sum;
00183     }
00184 }
00185 
00186 void Resistance::ComputeScore()
00187 {
00188     double r = m_resistance[WHITE] / m_resistance[BLACK];
00189     m_score = log(r);
00190 }
00191 
00192 double Resistance::Resist(HexColor color) const
00193 {
00194     return log(m_resistance[color]);
00195 }
00196 
00197 //---------------------------------------------------------------------------
00198 // AdjacencyGraph computations
00199 
00200 namespace
00201 {
00202 
00203 /** Computes a AdjacencyGraph for color on the given board. */
00204 void AddAdjacent(HexColor color, const HexBoard& brd,
00205                  AdjacencyGraph& graph)
00206 {
00207     HexColorSet not_other = HexColorSetUtil::ColorOrEmpty(color);
00208     for (BoardIterator x(brd.GetPosition().Stones(not_other)); x; ++x) 
00209     {
00210         for (BoardIterator y(brd.GetPosition().Stones(not_other)); *y != *x; ++y) 
00211         {
00212             HexPoint cx = brd.GetGroups().CaptainOf(*x);
00213             HexPoint cy = brd.GetGroups().CaptainOf(*y);
00214             if ((cx==cy) || brd.Cons(color).Exists(cx, cy, VC::FULL))
00215             {
00216                 graph[*x][*y] = true;
00217                 graph[*y][*x] = true;
00218             }
00219         }
00220     }
00221 }
00222 
00223 bool g_ResistanceUtilInitialized = false;
00224 
00225 PatternSet s_capmiai[BLACK_AND_WHITE];
00226 HashedPatternSet* s_hash_capmiai[BLACK_AND_WHITE];
00227 
00228 void InitializeCapMiai()
00229 {
00230     if (g_ResistanceUtilInitialized) return;
00231 
00232     LogFine() << "--InitializeCapMiai" << '\n';
00233 
00234     //
00235     // The center 'B' is marked so the group can be determined. 
00236     //
00237     //              *
00238     //             . .
00239     //            B B B                          [capmiai/0]
00240     // m:0,0,0,0,0;0,0,0,0,0;0,0,0,0,0;0,0,0,0,0;7,6,0,4,0;3,2,0,0,0;1
00241     //
00242     std::string capmiai = "m:0,0,0,0,0;0,0,0,0,0;0,0,0,0,0;0,0,0,0,0;7,6,0,4,0;3,2,0,0,0;1";
00243 
00244     Pattern pattern;
00245     if (!pattern.unserialize(capmiai)) {
00246         HexAssert(false);
00247     }
00248     pattern.setName("capmiai");
00249 
00250     s_capmiai[BLACK].push_back(pattern);
00251     s_hash_capmiai[BLACK] = new HashedPatternSet();
00252     s_hash_capmiai[BLACK]->hash(s_capmiai[BLACK]);
00253 
00254     pattern.flipColors();
00255     s_capmiai[WHITE].push_back(pattern);
00256     s_hash_capmiai[WHITE] = new HashedPatternSet();
00257     s_hash_capmiai[WHITE]->hash(s_capmiai[WHITE]);
00258 }
00259 
00260 /** Simulates and'ing over the edge for the given color and edge. All
00261     empty neighbours of an edge get all the connections the edge
00262     has. All cells that are a captured-miai away from the edge get all
00263     connections the edge has. */
00264 void SimulateAndOverEdge1(const HexBoard& brd, HexColor color, 
00265                          HexPoint edge, AdjacencyGraph& graph)
00266 {
00267     bitset_t augment = brd.GetGroups().Nbs(edge, EMPTY);
00268 
00269     // add in miai-captured empty cells adjacent to edge
00270     HexAssert(g_ResistanceUtilInitialized);
00271 
00272     bitset_t adjToEdge;
00273     for (BitsetIterator p(brd.GetPosition().GetEmpty()); p; ++p) 
00274     {
00275         PatternHits hits;
00276         brd.GetPatternState().MatchOnCell(*s_hash_capmiai[color], *p, 
00277                                           PatternState::MATCH_ALL, hits);
00278         for (unsigned j=0; j<hits.size(); ++j) 
00279         {
00280             HexPoint cj = brd.GetGroups().CaptainOf(hits[j].moves1()[0]);
00281             if (cj == edge) 
00282             {
00283                 augment.set(*p);
00284                 break;
00285             }
00286         }
00287     }
00288 
00289     // add the edge's connections to all cells in augment
00290     for (BitsetIterator p(augment); p; ++p) {
00291         for (BoardIterator q(brd.Const().EdgesAndInterior()); q; ++q) {
00292             graph[*p][*q] = graph[*p][*q] || graph[edge][*q];
00293             graph[*q][*p] = graph[*q][*p] || graph[edge][*q];
00294         }
00295     }
00296 }
00297 
00298 } // annonymous namespace
00299 
00300 void ResistanceUtil::Initialize()
00301 {
00302     InitializeCapMiai();
00303     g_ResistanceUtilInitialized = true;
00304 }
00305 
00306 void ResistanceUtil::AddAdjacencies(const HexBoard& brd,
00307                                     AdjacencyGraph graph[BLACK_AND_WHITE])
00308 {
00309     for (BWIterator c; c; ++c) 
00310         AddAdjacent(*c, brd, graph[*c]);
00311 }
00312 
00313 void ResistanceUtil::SimulateAndOverEdge(const HexBoard& brd,
00314                                          AdjacencyGraph g[BLACK_AND_WHITE])
00315 {
00316     if (brd.Builder().Parameters().and_over_edge)
00317     {
00318         LogWarning() 
00319                  << "**** Simulating and-over-edge "
00320                  << "while vcs are computed over edge!! ****" 
00321                  << '\n';
00322     }
00323 
00324     SimulateAndOverEdge1(brd,BLACK, HexPointUtil::colorEdge1(BLACK), g[BLACK]);
00325     SimulateAndOverEdge1(brd,BLACK, HexPointUtil::colorEdge2(BLACK), g[BLACK]);
00326     SimulateAndOverEdge1(brd,WHITE, HexPointUtil::colorEdge1(WHITE), g[WHITE]);
00327     SimulateAndOverEdge1(brd,WHITE, HexPointUtil::colorEdge2(WHITE), g[WHITE]);
00328 }
00329 
00330 //----------------------------------------------------------------------------


6 Jan 2011 Doxygen 1.6.3