void solve1( int M1, int L1, const Bipartite *m_to_l1, const double *P1, double *q1 ) { M = M1; L = L1; P = P1; q = q1; m_to_l = m_to_l1; double *qp = q; for ( int l=0; l<L; l++ ) { auto &_to_m = m_to_l->getFromSet( l ); memset( qp, 0, sizeof(double) * LabelSet::classes ); for ( auto& ele : _to_m ) { int m = ele.first; double alpha = ele.second; addScaledTo( qp, P + m * LabelSet::classes, LabelSet::classes, alpha ); } double s = sum_vec( qp, LabelSet::classes ); scale( qp, LabelSet::classes, 1.0 / s ); qp += LabelSet::classes; } }
/* * Restricted Energy on q(l) is * sum_m ( D(m) - alpha(l,m) * q(l) + alpha(l,m) * q'(l) )^2 * + sum_j w(i,j) * ( q'(l) - q(j) )^2 */ inline double restrict_energy( int l, double *q_l = nullptr ) { auto& _to_m = m_to_l->getFromSet( l ); auto& _to_j = forest->GetWeights( l ); double energy = 0.0; double t0[LabelSet::classes]; if ( nullptr == q_l ) { for ( auto& ele : _to_m ) { int m = ele.first; energy += norm2( D + m * LabelSet::classes, LabelSet::classes ); } for ( auto& ele : _to_j ) { int j = ele.first; double wt = static_cast<double>( ele.second ); minus( q + l * LabelSet::classes, q + j * LabelSet::classes, t0, LabelSet::classes ); energy += options.beta * wt * norm2( t0, LabelSet::classes ); } } else { double t0[LabelSet::classes]; for ( auto& ele : _to_m ) { int m = ele.first; double alpha = ele.second; memcpy( t0, D + m * LabelSet::classes, sizeof(double) * LabelSet::classes ); minusScaledFrom( t0, q + l * LabelSet::classes, LabelSet::classes, alpha ); addScaledTo( t0, q_l, LabelSet::classes, alpha ); energy += norm2( t0, LabelSet::classes ); } for ( auto& ele : _to_j ) { int j = ele.first; double wt = static_cast<double>( ele.second ); minus( q_l, q + j * LabelSet::classes, t0, LabelSet::classes ); energy += options.beta * wt * norm2( t0, LabelSet::classes ); } } return energy; }
inline void update_q( int l ) { auto& _to_m = m_to_l->getFromSet( l ); auto& _to_j = forest->GetWeights( l ); double t0[LabelSet::classes]; memset( t0, 0, sizeof(double) * LabelSet::classes ); double t1[LabelSet::classes]; // t0 = sum_m alpha(l,m) * D(m) for ( auto& ele : _to_m ) { int m = ele.first; double alpha = ele.second; addScaledTo( t0, D + m * LabelSet::classes, LabelSet::classes, alpha ); } // t0 += sum_m wt(l,j) (q(l) - q(j) ) for ( auto& ele : _to_j ) { int j = ele.first; double wt = static_cast<double>( ele.second ); minus( q + l * LabelSet::classes, q + j * LabelSet::classes, t1, LabelSet::classes ); addScaledTo( t0, t1, LabelSet::classes, wt ); } // negate t0 to get negative gradient direction negate( t0, LabelSet::classes ); // Line Search double energy_old = restrict_energy( l ) * options.wolf; bool updated = false; normalize_vec( t0, t0, LabelSet::classes ); double energy_new = 0.0; for ( int i=0; i<40; i++ ) { scale( t0, LabelSet::classes, options.shrinkRatio ); add( t0, q + l * LabelSet::classes, t1, LabelSet::classes ); // Simplex Projection watershed( t1, t0, LabelSet::classes ); energy_new = restrict_energy( l, t0 ); if ( energy_new < energy_old ) { updated = true; break; } } if ( updated ) { for ( auto& ele : _to_m ) { int m = ele.first; double alpha = ele.second; update_D( m, l, t0, alpha ); } memcpy( q + l * LabelSet::classes, t0, sizeof(double) * LabelSet::classes ); } }