无法使Jacobi算法在Objective-C中工作

时间:2010-05-02 00:20:59

标签: objective-c cocoa

出于某种原因,我无法让这个程序工作。我有其他的CS专业人员看着它,他们也无法弄明白。

该程序执行Jacobi算法(您可以看到逐步指令和MATLAB实现here)。顺便说一句,它与维基百科的同名文章不同。

由于NSArray是一维的,我添加了一个让它像二维C数组一样的方法。在多次运行Jacobi算法之后,NSArrayi[0][0]i[1][1]等)中的对角线条目应该变得更大而其他条纹接近0.但出于某种原因,它们都呈指数级增长。例如,i[2][4]应该等于0.0000009,而不是9999999,而i[2][2]应该很大。

谢谢,

克里斯

的NSArray + Matrix.m

@implementation NSArray (Matrix)

@dynamic offValue, transposed;

- (double)offValue {
    double sum = 0.0;
    for ( MatrixItem *item in self )
        if ( item.nonDiagonal )
            sum += pow( item.value, 2.0 );
    return sum;
}

- (NSMutableArray *)transposed {
    NSMutableArray *transpose = [[[NSMutableArray alloc] init] autorelease];
    int i, j;

    for ( i = 0; i < 5; i++ ) {
        for ( j = 0; j < 5; j++ ) {
            [transpose addObject:[self objectAtRow:j andColumn:i]];
        }
    }
    return transpose;
}

- (id)objectAtRow:(NSUInteger)row andColumn:(NSUInteger)column {
    NSUInteger index = 5 * row + column;
    return [self objectAtIndex:index];
}

- (NSMutableArray *)multiplyWithMatrix:(NSArray *)array {
    NSMutableArray *result = [[NSMutableArray alloc] init];
    int i = 0, j = 0, k = 0;
    double value;

    for ( i = 0; i < 5; i++ ) {
        for ( j = 0; j < 5; j++ ) {
            value = 0.0; // (JeremyP's answer)
            for ( k = 0; k < 5; k++ ) {
                MatrixItem *firstItem = [self objectAtRow:i andColumn:k];
                MatrixItem *secondItem = [array objectAtRow:k andColumn:j];
                value += firstItem.value * secondItem.value;
            }
            MatrixItem *item = [[MatrixItem alloc] initWithValue:value];
            item.row = i;
            item.column = j;
            [result addObject:item];
        }
    }
    return result;
}
@end

Jacobi_AlgorithmAppDelegate.m

// ...

- (void)jacobiAlgorithmWithEntry:(MatrixItem *)entry {
    MatrixItem *b11 = [matrix objectAtRow:entry.row andColumn:entry.row];
    MatrixItem *b22 = [matrix objectAtRow:entry.column andColumn:entry.column];

    double muPlus = ( b22.value + b11.value ) / 2.0;
    muPlus += sqrt( pow((b22.value - b11.value), 2.0) + 4.0 * pow(entry.value, 2.0) );

    Vector *u1 = [[[Vector alloc] initWithX:(-1.0 * entry.value) andY:(b11.value - muPlus)] autorelease];
    [u1 normalize];
    Vector *u2 = [[[Vector alloc] initWithX:-u1.y andY:u1.x] autorelease];

    NSMutableArray *g = [[[NSMutableArray alloc] init] autorelease];
    for ( int i = 0; i <= 24; i++ ) {
        MatrixItem *item = [[[MatrixItem alloc] init] autorelease];
        if ( i == 6*entry.row )
            item.value = u1.x;
        else if ( i == 6*entry.column )
            item.value = u2.y;
        else if ( i == ( 5*entry.row + entry.column ) || i == ( 5*entry.column + entry.row ) )
            item.value = u1.y;
        else if ( i % 6 == 0 )
            item.value = 1.0;
        else
            item.value = 0.0;

        [g addObject:item];
    }

    NSMutableArray *firstResult = [[g.transposed multiplyWithMatrix:matrix] autorelease];

    matrix = [firstResult multiplyWithMatrix:g];
}

// ...

2 个答案:

答案 0 :(得分:3)

您的矩阵类别是否有任何单元测试?我的意思是,你确定乘法算法有效吗?我会说初始化值为0会发生在错误的循环中。我想你需要在j循环中完成它。

其他一些观察结果:

  • 您不需要@dynamic属性声明,因为您自己定义了属性的实现。
  • 考虑创建一个自己的Matrix类,它包含一个普通的C数组双精度数。您可能会发现实现更简单一些。

答案 1 :(得分:1)

将平方根词添加到muPlus时,不要除以2。计算应该是:

double muPlus = ( b22.value + b11.value ) / 2.0;
muPlus += sqrt( pow((b22.value - b11.value), 2.0) 
                + 4.0 * pow(entry.value, 2.0) 
              ) / 2.0;

或:

double muPlus = ( b22.value + b11.value );
muPlus += sqrt( pow((b22.value - b11.value), 2.0) 
                + 4.0 * pow(entry.value, 2.0) );
muPlus /= 2.0;

此外,您将u1.y分配给G r,c 和G c,r 。从算法描述中,您需要G r,c = U 1,2 (或u1.y)和G c,r = U 2,1 (或u2.x)。请注意,您实际上并不需要u2;您可以将-u1.y替换为u2.x,将u1.x替换为u2.y

题外话

根据Fundamental Rule of Cocoa Memory Management-[NSArray multiplyWithMatrix:]应该返回一个自动释放的数组,因为被乘数应该放弃所有权。此外,您应该使用访问者将GT * A * G分配给matrix,而不是直接执行,以便可以对其进行妥善管理。

由于在每次迭代过程中填充g的循环中的大多数测试都是错误的,因此使用某些默认值填充g然后更新g更有效率。您可以创建一个零矩阵,然后将对角线设置为1,然后填入U中的值,或者您可以创建一个单位矩阵(在循环中保留i%6 == 0测试),然后填写U中的值。分析三种方法中的每一种。