Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -202,10 +202,12 @@ 4B55A113133AC24600B58A93 /* OFReadFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B55A10D133AC24500B58A93 /* OFReadFailedException.m */; }; 4B55A114133AC24600B58A93 /* OFReadOrWriteFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B55A10E133AC24500B58A93 /* OFReadOrWriteFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B55A115133AC24600B58A93 /* OFReadOrWriteFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B55A10F133AC24500B58A93 /* OFReadOrWriteFailedException.m */; }; 4B55A116133AC24600B58A93 /* OFWriteFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B55A110133AC24500B58A93 /* OFWriteFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B55A117133AC24600B58A93 /* OFWriteFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B55A111133AC24600B58A93 /* OFWriteFailedException.m */; }; + 4B6965E213A58B1B004F1C3A /* OFFloatMatrix.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B6965E013A58B1B004F1C3A /* OFFloatMatrix.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4B6965E313A58B1B004F1C3A /* OFFloatMatrix.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B6965E113A58B1B004F1C3A /* OFFloatMatrix.m */; }; 4B7FF3B0133CE6DE00000324 /* OFMutexStillLockedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B7FF3AE133CE6DE00000324 /* OFMutexStillLockedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B7FF3B1133CE6DE00000324 /* OFMutexStillLockedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7FF3AF133CE6DE00000324 /* OFMutexStillLockedException.m */; }; 4B7FF3B4133CED6200000324 /* OFConditionStillWaitingException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B7FF3B2133CED6100000324 /* OFConditionStillWaitingException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B7FF3B5133CED6200000324 /* OFConditionStillWaitingException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B7FF3B3133CED6100000324 /* OFConditionStillWaitingException.m */; }; 4B8B16FE133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B8B16FC133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -467,10 +469,12 @@ 4B6799881099E7C50041064A /* OFXMLElement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFXMLElement.m; path = src/OFXMLElement.m; sourceTree = ""; }; 4B6799891099E7C50041064A /* OFXMLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFXMLParser.h; path = src/OFXMLParser.h; sourceTree = ""; }; 4B67998A1099E7C50041064A /* OFXMLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFXMLParser.m; path = src/OFXMLParser.m; sourceTree = ""; }; 4B67998B1099E7C50041064A /* threading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = threading.h; path = src/threading.h; sourceTree = ""; }; 4B67998C1099E7C50041064A /* unicode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unicode.h; path = src/unicode.h; sourceTree = ""; }; + 4B6965E013A58B1B004F1C3A /* OFFloatMatrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFFloatMatrix.h; path = src/OFFloatMatrix.h; sourceTree = ""; }; + 4B6965E113A58B1B004F1C3A /* OFFloatMatrix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFFloatMatrix.m; path = src/OFFloatMatrix.m; sourceTree = ""; }; 4B6AF96C10A8D3E40003FB0A /* asprintf.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = asprintf.m; path = src/asprintf.m; sourceTree = ""; }; 4B6AF96F10A8D40E0003FB0A /* iso_8859_15.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iso_8859_15.m; path = src/iso_8859_15.m; sourceTree = ""; }; 4B6AF97210A8D42E0003FB0A /* windows_1252.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = windows_1252.m; path = src/windows_1252.m; sourceTree = ""; }; 4B6AF97310A8D4450003FB0A /* ObjFW.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjFW.h; path = src/ObjFW.h; sourceTree = ""; }; 4B6EF66E1235358D0076B512 /* OFArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFArrayTests.m; path = tests/OFArrayTests.m; sourceTree = SOURCE_ROOT; }; @@ -791,10 +795,12 @@ 4B6799631099E7C50041064A /* OFDictionary.m */, 4B0108C910EB8C9300631877 /* OFEnumerator.h */, 4B0108CA10EB8C9300631877 /* OFEnumerator.m */, 4B6799661099E7C50041064A /* OFFile.h */, 4B6799671099E7C50041064A /* OFFile.m */, + 4B6965E013A58B1B004F1C3A /* OFFloatMatrix.h */, + 4B6965E113A58B1B004F1C3A /* OFFloatMatrix.m */, 4BE920A613A2ECEF00154B94 /* OFFloatVector.h */, 4BE920A713A2ECEF00154B94 /* OFFloatVector.m */, 4BF1BCC011C9663F0025511F /* OFHash.h */, 4BF1BCC111C9663F0025511F /* OFHash.m */, 4B99250F12E0780000215DBE /* OFHTTPRequest.h */, @@ -974,10 +980,11 @@ 4B3D23C41337FC8300DD29B8 /* OFDate.h in Headers */, 4B3D23C51337FCB000DD29B8 /* OFDictionary.h in Headers */, 4B3D23C61337FCB000DD29B8 /* OFEnumerator.h in Headers */, 4B17FF74133A2AAB003E6DCD /* OFException.h in Headers */, 4B3D23C81337FCB000DD29B8 /* OFFile.h in Headers */, + 4B6965E213A58B1B004F1C3A /* OFFloatMatrix.h in Headers */, 4BE920A813A2ECEF00154B94 /* OFFloatVector.h in Headers */, 4B3D23C91337FCB000DD29B8 /* OFHash.h in Headers */, 4B3D23CA1337FCB000DD29B8 /* OFHTTPRequest.h in Headers */, 4B3D23CB1337FCB000DD29B8 /* OFList.h in Headers */, 4B3D23CC1337FCB000DD29B8 /* OFMD5Hash.h in Headers */, @@ -1226,10 +1233,11 @@ 4B3D23911337FC0D00DD29B8 /* OFDataArray+Hashing.m in Sources */, 4B3D23921337FC0D00DD29B8 /* OFDate.m in Sources */, 4B3D23931337FC0D00DD29B8 /* OFDictionary.m in Sources */, 4B3D23941337FC0D00DD29B8 /* OFEnumerator.m in Sources */, 4B3D23961337FC0D00DD29B8 /* OFFile.m in Sources */, + 4B6965E313A58B1B004F1C3A /* OFFloatMatrix.m in Sources */, 4BE920A913A2ECEF00154B94 /* OFFloatVector.m in Sources */, 4B3D23971337FC0D00DD29B8 /* OFHash.m in Sources */, 4B3D23981337FC0D00DD29B8 /* OFHTTPRequest.m in Sources */, 4B3D23991337FC0D00DD29B8 /* OFList.m in Sources */, 4B3D239A1337FC0D00DD29B8 /* OFMD5Hash.m in Sources */, Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -16,10 +16,11 @@ OFDataArray+Hashing.m \ OFDate.m \ OFDictionary.m \ OFEnumerator.m \ OFFile.m \ + OFFloatMatrix.m \ OFFloatVector.m \ OFHash.m \ OFHTTPRequest.m \ OFList.m \ OFMD5Hash.m \ ADDED src/OFFloatMatrix.h Index: src/OFFloatMatrix.h ================================================================== --- src/OFFloatMatrix.h +++ src/OFFloatMatrix.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include + +#import "OFObject.h" + +/** + * \brief A class for storing and manipulating matrices of floats. + */ +@interface OFFloatMatrix: OFObject +{ + size_t rows, columns; + float *data; +} + +/** + * \brief Creates a new matrix with the specified dimension. + * + * If the number of rows and columns is equal, the matrix is initialized to be + * the identity. + * + * \param rows The number of rows for the matrix + * \param columns The number of colums for the matrix + * \return A new autoreleased OFFloatMatrix + */ ++ matrixWithRows: (size_t)rows + columns: (size_t)columns; + +/** + * \brief Creates a new matrix with the specified dimension and data. + * + * \param rows The number of rows for the matrix + * \param columns The number of colums for the matrix + * \return A new autoreleased OFFloatMatrix + */ ++ matrixWithRows: (size_t)rows + columnsAndData: (size_t)columns, ...; + +/** + * \brief Initializes the matrix with the specified dimension. + * + * If the number of rows and columns is equal, the matrix is initialized to be + * the identity. + * + * \param rows The number of rows for the matrix + * \param columns The number of colums for the matrix + * \return An initialized OFFloatMatrix + */ +- initWithRows: (size_t)rows + columns: (size_t)columns; + +/** + * \brief Initializes the matrix with the specified dimension and data. + * + * \param rows The number of rows for the matrix + * \param columns The number of colums for the matrix + * \return An initialized OFFloatMatrix + */ +- initWithRows: (size_t)rows + columnsAndData: (size_t)columns, ...; + +/** + * \brief Initializes the matrix with the specified dimension and arguments. + * + * \param rows The number of rows for the matrix + * \param columns The number of colums for the matrix + * \param arguments A va_list with data for the matrix + * \return An initialized OFFloatMatrix + */ +- initWithRows: (size_t)rows + columns: (size_t)columns + arguments: (va_list)arguments; + +/** + * \brief Sets the value for the specified row and colmn. + * + * \param value The value + * \param row The row for the value + * \param column The column for the value + */ +- (void)setValue: (float)value + forRow: (size_t)row + column: (size_t)column; + +/** + * \brief Returns the value for the specified row and column. + * + * \param row The row for which the value should be returned + * \param column The column for which the value should be returned + * \return The value for the specified row and column + */ +- (float)valueForRow: (size_t)row + column: (size_t)column; + +/** + * \brief Returns the number of rows of the matrix. + * + * \return The number of rows of the matrix + */ +- (size_t)rows; + +/** + * \brief Returns the number of columns of the matrix. + * + * \return The number of columns of the matrix + */ +- (size_t)columns; + +/** + * \brief Returns an array of floats with the contents of the matrix. + * + * The returned array is in the format columns-rows. + * Modifying the returned array directly is allowed and will change the matrix. + * + * \brief An array of floats with the contents of the vector + */ +- (float*)cArray; + +/** + * \brief Adds the specified matrix to the receiver. + * + * \param matrix The matrix to add + */ +- (void)addMatrix: (OFFloatMatrix*)matrix; + +/** + * \brief Subtracts the specified matrix from the receiver. + * + * \param matrix The matrix to subtract + */ +- (void)subtractMatrix: (OFFloatMatrix*)matrix; + +/** + * \brief Multiplies the receiver with the specified scalar. + * + * \param scalar The scalar to multiply with + */ +- (void)multiplyWithScalar: (float)scalar; + +/** + * \brief Divides the receiver by the specified scalar. + * + * \param scalar The scalar to divide by + */ +- (void)divideByScalar: (float)scalar; + +/** + * \brief Multiplies the receiver with the specified matrix on the left side and + * the receiver on the right. + * + * \param matrix The matrix to multiply the receiver with + */ +- (void)multiplyWithMatrix: (OFFloatMatrix*)matrix; + +/** + * \brief Transposes the receiver. + */ +- (void)transpose; +@end ADDED src/OFFloatMatrix.m Index: src/OFFloatMatrix.m ================================================================== --- src/OFFloatMatrix.m +++ src/OFFloatMatrix.m @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include +#include + +#import "OFFloatMatrix.h" +#import "OFString.h" + +#import "OFInvalidArgumentException.h" +#import "OFNotImplementedException.h" +#import "OFOutOfRangeException.h" + +#import "macros.h" + +@implementation OFFloatMatrix ++ matrixWithRows: (size_t)rows + columns: (size_t)columns +{ + return [[[self alloc] initWithRows: rows + columns: columns] autorelease]; +} + ++ matrixWithRows: (size_t)rows + columnsAndData: (size_t)columns, ... +{ + id ret; + va_list arguments; + + va_start(arguments, columns); + ret = [[[self alloc] initWithRows: rows + columns: columns + arguments: arguments] autorelease]; + va_end(arguments); + + return ret; +} + +- init +{ + Class c = isa; + [self release]; + @throw [OFNotImplementedException newWithClass: c + selector: _cmd]; +} + +- initWithRows: (size_t)rows_ + columns: (size_t)columns_ +{ + self = [super init]; + + @try { + rows = rows_; + columns = columns_; + + if (SIZE_MAX / rows < columns) + @throw [OFOutOfRangeException + newWithClass: isa]; + + data = [self allocMemoryForNItems: rows * columns + withSize: sizeof(float)]; + + memset(data, 0, rows * columns * sizeof(float)); + + if (rows == columns) { + size_t i; + + for (i = 0; i < rows * columns; i += rows + 1) + data[i] = 1; + } + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- initWithRows: (size_t)rows_ + columnsAndData: (size_t)columns_, ... +{ + id ret; + va_list arguments; + + va_start(arguments, columns_); + ret = [self initWithRows: rows_ + columns: columns_ + arguments: arguments]; + va_end(arguments); + + return ret; +} + +- initWithRows: (size_t)rows_ + columns: (size_t)columns_ + arguments: (va_list)arguments +{ + self = [super init]; + + @try { + size_t i; + + rows = rows_; + columns = columns_; + + if (SIZE_MAX / rows < columns) + @throw [OFOutOfRangeException + newWithClass: isa]; + + data = [self allocMemoryForNItems: rows * columns + withSize: sizeof(float)]; + + for (i = 0; i < rows; i++) { + size_t j; + + for (j = i; j < rows * columns; j += rows) + data[j] = (float)va_arg(arguments, double); + } + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)setValue: (float)value + forRow: (size_t)row + column: (size_t)column +{ + if (row >= rows || column >= columns) + @throw [OFOutOfRangeException newWithClass: isa]; + + data[row * columns + column] = value; +} + +- (float)valueForRow: (size_t)row + column: (size_t)column +{ + if (row >= rows || column >= columns) + @throw [OFOutOfRangeException newWithClass: isa]; + + return data[row * columns + column]; +} + +- (size_t)rows +{ + return rows; +} + +- (size_t)columns +{ + return columns; +} + +- (BOOL)isEqual: (id)object +{ + OFFloatMatrix *otherMatrix; + + if (object->isa != isa) + return NO; + + otherMatrix = object; + + if (otherMatrix->rows != rows || otherMatrix->columns != columns) + return NO; + + if (memcmp(otherMatrix->data, data, rows * columns * sizeof(float))) + return NO; + + return YES; +} + +- (uint32_t)hash +{ + size_t i; + uint32_t hash; + + OF_HASH_INIT(hash); + + for (i = 0; i < rows * columns; i++) { + union { + float f; + uint32_t i; + } u; + + u.f = data[i]; + + OF_HASH_ADD_INT32(hash, u.i); + } + + OF_HASH_FINALIZE(hash); + + return hash; +} + +- copy +{ + OFFloatMatrix *copy = [[isa alloc] initWithRows: rows + columns: columns]; + + memcpy(copy->data, data, rows * columns * sizeof(float)); + + return copy; +} + +- (OFString*)description +{ + OFMutableString *description; + size_t i; + + description = [OFMutableString stringWithFormat: @"<%@, (\n", + [self className]]; + + for (i = 0; i < rows; i++) { + size_t j; + + [description appendString: @"\t"]; + + for (j = 0; j < columns; j++) { + + if (j != columns - 1) + [description + appendFormat: @"%10f ", + data[j * rows + i]]; + else + [description + appendFormat: @"%10f\n", + data[j * rows + i]]; + } + } + + [description appendString: @")>"]; + + /* + * Class swizzle the string to be immutable. We declared the return type + * to be OFString*, so it can't be modified anyway. But not swizzling it + * would create a real copy each time -[copy] is called. + */ + description->isa = [OFString class]; + return description; +} + +- (float*)cArray +{ + return data; +} + +- (void)addMatrix: (OFFloatMatrix*)matrix +{ + size_t i; + + if (matrix->isa != isa || matrix->rows != rows || + matrix->columns != columns) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + for (i = 0; i < rows * columns; i++) + data[i] += matrix->data[i]; +} + +- (void)subtractMatrix: (OFFloatMatrix*)matrix +{ + size_t i; + + if (matrix->isa != isa || matrix->rows != rows || + matrix->columns != columns) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + for (i = 0; i < rows * columns; i++) + data[i] -= matrix->data[i]; +} + + +- (void)multiplyWithScalar: (float)scalar +{ + size_t i; + + for (i = 0; i < rows * columns; i++) + data[i] *= scalar; +} + +- (void)divideByScalar: (float)scalar +{ + size_t i; + + for (i = 0; i < rows * columns; i++) + data[i] /= scalar; +} + +- (void)multiplyWithMatrix: (OFFloatMatrix*)matrix +{ + float *newData; + size_t i, base1, base2; + + if (rows != matrix->columns) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + newData = [self allocMemoryForNItems: matrix->rows * columns + withSize: sizeof(float)]; + + base1 = 0; + base2 = 0; + + for (i = 0; i < columns; i++) { + size_t base3 = base2; + size_t j; + + for (j = 0; j < matrix->rows; j++) { + size_t base4 = j; + size_t base5 = base1; + float tmp = 0.0f; + size_t k; + + for (k = 0; k < matrix->columns; k++) { + tmp += matrix->data[base4] * data[base5]; + base4 += matrix->rows; + base5++; + } + + newData[base3] = tmp; + base3++; + } + + base1 += rows; + base2 += matrix->rows; + } + + [self freeMemory: data]; + data = newData; + + rows = matrix->rows; +} + +- (void)transpose +{ + float *newData = [self allocMemoryForNItems: rows * columns + withSize: sizeof(float)]; + size_t i, k; + + rows ^= columns; + columns ^= rows; + rows ^= columns; + + for (i = k = 0; i < rows; i++) { + size_t j; + + for (j = i; j < rows * columns; j += rows) + newData[j] = data[k++]; + } + + [self freeMemory: data]; + data = newData; +} +@end Index: src/OFFloatVector.h ================================================================== --- src/OFFloatVector.h +++ src/OFFloatVector.h @@ -94,15 +94,15 @@ - (size_t)dimension; /** * \brief Returns an array of floats with the contents of the vector. * - * Modifying the returned array is allowed and will change the vector. + * Modifying the returned array directly is allowed and will change the vector. * * \brief An array of floats with the contents of the vector */ -- (float*)floatArray; +- (float*)cArray; /** * \brief Adds the specified vector to the receiver. * * \param vector The vector to add Index: src/OFFloatVector.m ================================================================== --- src/OFFloatVector.m +++ src/OFFloatVector.m @@ -99,11 +99,11 @@ data = [self allocMemoryForNItems: dimension withSize: sizeof(float)]; for (i = 0; i < dimension; i++) - data[i] = va_arg(arguments, double); + data[i] = (float)va_arg(arguments, double); } @catch (id e) { [self release]; @throw e; } @@ -133,23 +133,21 @@ } - (BOOL)isEqual: (id)object { OFFloatVector *otherVector; - size_t i; if (object->isa != isa) return NO; otherVector = object; if (otherVector->dimension != dimension) return NO; - for (i = 0; i < dimension; i++) - if (otherVector->data[i] != data[i]) - return NO; + if (memcmp(otherVector->data, data, dimension * sizeof(float))) + return NO; return YES; } - (uint32_t)hash @@ -175,15 +173,12 @@ return hash; } - copy { - OFFloatVector *copy = [[isa alloc] init]; + OFFloatVector *copy = [[isa alloc] initWithDimension: dimension]; - copy->dimension = dimension; - copy->data = [copy allocMemoryForNItems: dimension - withSize: sizeof(float)]; memcpy(copy->data, data, dimension * sizeof(float)); return copy; } @@ -209,11 +204,11 @@ */ description->isa = [OFString class]; return description; } -- (float*)floatArray +- (float*)cArray { return data; } - (void)addVector: (OFFloatVector*)vector @@ -287,11 +282,11 @@ if (vector->isa != isa || vector->dimension != dimension) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; - dotProduct = 0.0; + dotProduct = 0.0f; for (i = 0; i < dimension; i++) dotProduct += data[i] * vector->data[i]; return dotProduct; @@ -300,11 +295,11 @@ - (float)magnitude { float magnitude; size_t i; - magnitude = 0.0; + magnitude = 0.0f; for (i = 0; i < dimension; i++) magnitude += data[i] * data[i]; magnitude = sqrtf(magnitude); Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -52,10 +52,11 @@ #import "OFXMLElement.h" #import "OFXMLParser.h" #import "OFXMLElementBuilder.h" #import "OFFloatVector.h" +#import "OFFloatMatrix.h" #import "OFSerialization.h" #import "OFApplication.h"