Implement GSCSTableau, GSCSEditInfo, GSCSEditVariableManager (#186)

* Implement GSCSTableau, GSCSEditInfo, GSCSEditVariableManager

* Update GSTableau based on feedback

* Remove adding expression term variable to external parameteric variables
This commit is contained in:
Benjamin Johnson 2023-08-05 18:26:22 +10:00 committed by GitHub
parent eb480b7748
commit 305bcd56a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 1187 additions and 8 deletions

View file

@ -365,7 +365,10 @@ GSCSVariable.m \
GSCSSolution.m \
GSCSFloatComparator.m \
GSCSLinearExpression.m \
GSCSStrength.m
GSCSStrength.m \
GSCSEditInfo.m \
GSCSEditVariableManager.m \
GSCSTableau.m
# Turn off NSMenuItem warning that NSMenuItem conforms to <NSObject>,
# but does not implement <NSObject>'s methods itself (it inherits
@ -690,7 +693,10 @@ GSCSFloatComparator.h \
GSCSSolution.h \
GSCSLinearExpression.h \
GSCSConstraintOperator.h \
GSCSStrength.h
GSCSStrength.h \
GSCSEditVariableManager.h \
GSCSEditInfo.h \
GSCSTableau.h
libgnustep-gui_HEADER_FILES = ${GUI_HEADERS}

59
Source/GSCSEditInfo.h Normal file
View file

@ -0,0 +1,59 @@
/* Copyright (C) 2023 Free Software Foundation, Inc.
By: Benjamin Johnson
Date: 12-6-2023
This file is part of the GNUstep Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import "GSCSConstraint.h"
#import "GSCSVariable.h"
#import <Foundation/Foundation.h>
#ifndef _GS_CS_EDIT_INFO_H
#define _GS_CS_EDIT_INFO_H
@interface GSCSEditInfo : NSObject
{
GSCSConstraint *_constraint;
GSCSVariable *_variable;
GSCSVariable *_plusVariable;
GSCSVariable *_minusVariable;
NSInteger _previousConstant;
}
#if GS_HAS_DECLARED_PROPERTIES
@property (nonatomic, readonly) GSCSConstraint *constraint;
#else
- (GSCSConstraint *) constraint;
#endif
#if GS_HAS_DECLARED_PROPERTIES
@property (nonatomic, readonly) GSCSVariable *variable;
#else
- (GSCSVariable *) variable;
#endif
- (instancetype) initWithVariable: (GSCSVariable *)variable
constraint: (GSCSConstraint *)constraint
plusVariable: (GSCSVariable *)plusVariable
minusVariable: (GSCSVariable *)minusVariable
previousConstant: (NSInteger)previousConstant;
@end
#endif

66
Source/GSCSEditInfo.m Normal file
View file

@ -0,0 +1,66 @@
/* Copyright (C) 2023 Free Software Foundation, Inc.
By: Benjamin Johnson
Date: 12-6-2023
This file is part of the GNUstep Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import "GSCSEditInfo.h"
@implementation GSCSEditInfo
- (instancetype) initWithVariable: (GSCSVariable *)variable
constraint: (GSCSConstraint *)constraint
plusVariable: (GSCSVariable *)plusVariable
minusVariable: (GSCSVariable *)minusVariable
previousConstant: (NSInteger)previousConstant
{
self = [super init];
if (self != nil)
{
_variable = variable;
_plusVariable = plusVariable;
_minusVariable = minusVariable;
_constraint = constraint;
_previousConstant = previousConstant;
}
return self;
}
- (GSCSConstraint*) constraint
{
return _constraint;
}
- (GSCSVariable*) variable
{
return _variable;
}
- (void) dealloc
{
RELEASE(_variable);
RELEASE(_plusVariable);
RELEASE(_minusVariable);
RELEASE(_constraint);
[super dealloc];
}
@end

View file

@ -0,0 +1,60 @@
/* Copyright (C) 2023 Free Software Foundation, Inc.
By: Benjamin Johnson
Date: 12-6-2023
This file is part of the GNUstep Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import "GSCSEditInfo.h"
#import <Foundation/Foundation.h>
#ifndef _GS_CS_EDIT_VARIABLE_MANAGER_H
#define _GS_CS_EDIT_VARIABLE_MANAGER_H
@interface GSCSEditVariableManager : NSObject
{
NSMutableArray *_editVariablesList;
NSMutableArray *_editVariablesStack;
NSMapTable *_editVariablesMap;
}
- (NSArray *) editInfos;
- (BOOL) isEmpty;
- (void) addEditInfo: (GSCSEditInfo *)editInfo;
- (void) removeEditInfo: (GSCSEditInfo *)editInfo;
- (GSCSEditInfo *) editInfoForConstraint: (GSCSConstraint *)constraint;
- (NSArray *) editInfosForVariable: (GSCSVariable *)editVariable;
- (void) removeEditInfoForConstraint: (GSCSConstraint *)constraint;
- (void) pushEditVariableCount;
- (NSInteger) topEditVariableStack;
- (NSInteger) editVariableStackCount;
- (NSArray *) getNextSet;
@end
#endif

View file

@ -0,0 +1,141 @@
/* Copyright (C) 2023 Free Software Foundation, Inc.
By: Benjamin Johnson
Date: 12-6-2023
This file is part of the GNUstep Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import "GSCSEditVariableManager.h"
#import "GSFastEnumeration.h"
@implementation GSCSEditVariableManager
- (instancetype) init
{
self = [super init];
if (self)
{
ASSIGN(_editVariablesList, [NSMutableArray array]);
ASSIGN(_editVariablesStack, [NSMutableArray array]);
ASSIGN(_editVariablesMap,
[NSMapTable mapTableWithKeyOptions: NSMapTableStrongMemory
valueOptions: NSMapTableStrongMemory]);
[self pushEditVariableCount];
}
return self;
}
- (BOOL) isEmpty
{
return [_editVariablesList count] == 0;
}
- (NSArray *) editInfos
{
return _editVariablesList;
}
- (NSInteger) editVariableStackCount
{
return [_editVariablesStack count];
}
- (NSInteger) topEditVariableStack
{
return [[_editVariablesStack lastObject] integerValue];
}
- (void) pushEditVariableCount
{
[_editVariablesStack
addObject: [NSNumber numberWithInteger: [_editVariablesList count]]];
}
- (void) popEditVariableStack
{
[_editVariablesStack removeLastObject];
}
- (void) addEditInfo: (GSCSEditInfo *)editInfo
{
[_editVariablesMap setObject: editInfo forKey: [editInfo variable]];
[_editVariablesList addObject: editInfo];
}
- (void) removeEditInfo: (GSCSEditInfo *)editInfo
{
[_editVariablesList removeObject: editInfo];
}
- (void) removeEditInfoForConstraint: (GSCSConstraint *)constraint
{
GSCSEditInfo *editInfo = [self editInfoForConstraint: constraint];
[self removeEditInfo: editInfo];
}
- (GSCSEditInfo *) editInfoForConstraint: (GSCSConstraint *)constraint
{
FOR_IN(GSCSEditInfo *, editInfo, _editVariablesList)
if ([editInfo constraint] == constraint)
{
return editInfo;
}
END_FOR_IN(_editVariablesList);
return nil;
}
- (NSArray *) editInfosForVariable: (GSCSVariable *)editVariable
{
NSMutableArray *editInfos = [NSMutableArray array];
FOR_IN(GSCSEditInfo *, editInfo, _editVariablesList)
if ([editInfo variable] == editVariable)
{
[editInfos addObject: editInfo];
}
END_FOR_IN(_editVariablesList);
return editInfos;
}
- (NSArray *) getNextSet
{
[_editVariablesStack removeLastObject];
NSInteger index = [self topEditVariableStack];
NSInteger count = [_editVariablesList count];
NSMutableArray *editableInfosInDescendingOrder = [NSMutableArray array];
while (count > index)
{
GSCSEditInfo *editInfo = [[self editInfos] objectAtIndex: count - 1];
[editableInfosInDescendingOrder addObject: editInfo];
count--;
}
return editableInfosInDescendingOrder;
}
- (void) dealloc
{
RELEASE(_editVariablesList);
RELEASE(_editVariablesStack);
RELEASE(_editVariablesMap);
[super dealloc];
}
@end

View file

@ -32,7 +32,8 @@ const float GSCSStrengthWeak = 250;
- (instancetype) initWithName: (NSString *)name strength: (double)strength;
{
if (self = [super init])
self = [super init];
if (self != nil)
{
ASSIGN(_name, name);
_strength = strength;

147
Source/GSCSTableau.h Normal file
View file

@ -0,0 +1,147 @@
/* Copyright (C) 2023 Free Software Foundation, Inc.
By: Benjamin Johnson
Date: 12-6-2023
This file is part of the GNUstep Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import "GSCSLinearExpression.h"
#import "GSCSVariable.h"
#import <Foundation/Foundation.h>
#ifndef _GS_CS_TABLEAU_H
#define _GS_CS_TABLEAU_H
@interface GSCSTableau : NSObject
{
NSMutableSet *_externalParametricVariables;
NSMapTable *_rows;
NSMapTable *_columns;
NSMapTable *_externalRows;
NSMutableArray *_infeasibleRows;
GSCSVariable *_objective;
}
#if GS_HAS_DECLARED_PROPERTIES
@property (nonatomic, assign) GSCSVariable *objective;
#else
- (GSCSVariable *) objective;
- (void) setObjective: (GSCSVariable *)objective;
#endif
#if GS_HAS_DECLARED_PROPERTIES
@property (nonatomic, assign) NSMapTable *externalRows;
#else
- (NSMapTable *) externalRows;
- (void) setExternalRows: (NSMapTable *)externalRows;
#endif
#if GS_HAS_DECLARED_PROPERTIES
@property (nonatomic, assign) NSMutableArray *infeasibleRows;
#else
- (NSMutableArray *) infeasibleRows;
- (void) setInfeasibleRows: (NSMutableArray *)infeasibleRows;
#endif
- (void) addRowForVariable: (GSCSVariable *)variable
equalsExpression: (GSCSLinearExpression *)expression;
- (void) removeRowForVariable: (GSCSVariable *)variable;
- (BOOL) hasRowForVariable: (GSCSVariable *)variable;
- (void) substituteOutVariable: (GSCSVariable *)variable
forExpression: (GSCSLinearExpression *)expression;
- (void) substituteOutTerm: (GSCSVariable *)term
withExpression: (GSCSLinearExpression *)newExpression
inExpression: (GSCSLinearExpression *)expression
subject: (GSCSVariable *)subject;
- (BOOL) isBasicVariable: (GSCSVariable *)variable;
- (void) addVariable: (GSCSVariable *)variable
toExpression: (GSCSLinearExpression *)expression;
- (void) addVariable: (GSCSVariable *)variable
toExpression: (GSCSLinearExpression *)expression
withCoefficient: (CGFloat)coefficient;
- (void) addVariable: (GSCSVariable *)variable
toExpression: (GSCSLinearExpression *)expression
withCoefficient: (CGFloat)coefficient
subject: (GSCSVariable *)subject;
- (void) setVariable: (GSCSVariable *)variable
onExpression: (GSCSLinearExpression *)expression
withCoefficient: (CGFloat)coefficient;
- (void) addNewExpression: (GSCSLinearExpression *)newExpression
toExpression: (GSCSLinearExpression *)existingExpression
n: (CGFloat)n
subject: (GSCSVariable *)subject;
- (void) addNewExpression: (GSCSLinearExpression *)newExpression
toExpression: (GSCSLinearExpression *)existingExpression;
- (void) addMappingFromExpressionVariable: (GSCSVariable *)columnVariable
toRowVariable: (GSCSVariable *)rowVariable;
- (void) removeColumn: (GSCSVariable *)variable;
- (BOOL) hasColumnForVariable: (GSCSVariable *)variable;
- (NSSet *) columnForVariable: (GSCSVariable *)variable;
- (GSCSLinearExpression *) rowExpressionForVariable: (GSCSVariable *)variable;
- (void) changeSubjectOnExpression: (GSCSLinearExpression *)expression
existingSubject: (GSCSVariable *)existingSubject
newSubject: (GSCSVariable *)newSubject;
- (void) pivotWithEntryVariable: (GSCSVariable *)entryVariable
exitVariable: (GSCSVariable *)exitVariable;
- (BOOL) hasInfeasibleRows;
- (BOOL) containsExternalParametricVariableForEveryExternalTerm;
- (BOOL) containsExternalRowForEachExternalRowVariable;
- (NSArray *) substitedOutNonBasicPivotableVariables:
(GSCSVariable *)objective;
- (GSCSVariable *) findPivotableExitVariable: (GSCSVariable *)entryVariable;
- (GSCSVariable *)
findExitVariableForEquationWhichMinimizesRatioOfRestrictedVariables:
(GSCSVariable *)constraintMarkerVariable;
- (GSCSVariable *) findNonBasicVariables;
- (GSCSVariable *) findPivotableExitVariableWithoutCheck:
(GSCSVariable *)entryVariable;
@end
#endif

693
Source/GSCSTableau.m Normal file
View file

@ -0,0 +1,693 @@
/* Copyright (C) 2023 Free Software Foundation, Inc.
By: Benjamin Johnson
Date: 12-6-2023
This file is part of the GNUstep Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110 USA.
*/
#import "GSCSTableau.h"
#import "GSCSFloatComparator.h"
#import "GSFastEnumeration.h"
@interface GSCSTableau (PrivateMethods)
- (void) recordUpdatedVariable: (GSCSVariable *)variable;
- (void) addTermVariablesForExpression: (GSCSLinearExpression *)expression
variable: (GSCSVariable *)variable;
- (void) substituteOutTermInExpression: (GSCSLinearExpression *)expression
newExpression:
(GSCSLinearExpression *)newExpression
subject: (GSCSVariable *)subject
term: (GSCSVariable *)term
multiplier: (CGFloat)multiplier;
- (CGFloat) calculateNewCoefficent: (CGFloat)coefficentInExistingExpression
coefficentInNewExpression: (CGFloat)coefficentInNewExpression
multiplier: (CGFloat)multiplier;
- (void) removeColumnVariable: (GSCSVariable *)variable
subject: (GSCSVariable *)subject;
- (void) recordUpdatedVariable: (GSCSVariable *)variable;
- (void) addNewExpression: (GSCSLinearExpression *)newExpression
toExpression: (GSCSLinearExpression *)existingExpression
n: (CGFloat)n
subject: (GSCSVariable *)subject;
- (NSString *) columnsDescription;
- (NSString *) rowsDescription;
@end
@implementation GSCSTableau
- (instancetype) init
{
self = [super init];
if (self != nil)
{
ASSIGN(_rows,
[NSMapTable mapTableWithKeyOptions: NSMapTableStrongMemory
valueOptions: NSMapTableStrongMemory]);
ASSIGN(_columns,
[NSMapTable mapTableWithKeyOptions: NSMapTableStrongMemory
valueOptions: NSMapTableStrongMemory]);
ASSIGN(_externalParametricVariables, [NSMutableSet set]);
ASSIGN(_externalRows,
[NSMapTable mapTableWithKeyOptions: NSMapTableStrongMemory
valueOptions: NSMapTableStrongMemory]);
ASSIGN(_infeasibleRows, [NSMutableArray array]);
ASSIGN(_objective, [GSCSVariable objectiveVariableWithName: @"Z"]);
GSCSLinearExpression *expression = [[GSCSLinearExpression alloc] init];
[self addRowForVariable: _objective equalsExpression: expression];
}
return self;
}
- (GSCSVariable *) objective
{
return _objective;
}
- (void) setObjective: (GSCSVariable *)objective
{
ASSIGN(_objective, objective);
}
- (NSMapTable *) externalRows
{
return _externalRows;
}
- (void) setExternalRows: (NSMapTable *)externalRows
{
ASSIGN(_externalRows, externalRows);
}
- (NSMutableArray *) infeasibleRows
{
return _infeasibleRows;
}
- (void) setInfeasibleRows: (NSMutableArray *)infeasibleRows
{
ASSIGN(_infeasibleRows, infeasibleRows);
}
- (BOOL) shouldPreferPivotableVariable: (GSCSVariable *)lhs
overPivotableVariable: (GSCSVariable *)rhs
{
return [lhs id] < [rhs id];
}
- (BOOL) hasColumnForVariable: (GSCSVariable *)variable
{
return [_columns objectForKey: variable] != nil;
}
- (NSSet *) columnForVariable: (GSCSVariable *)variable
{
return [_columns objectForKey: variable];
}
// Add v=expr to the tableau, update column cross indices
// v becomes a basic variable
- (void) addRowForVariable: (GSCSVariable *)variable
equalsExpression: (GSCSLinearExpression *)expression
{
[_rows setObject: expression forKey: variable];
if ([variable isExternal])
{
[_externalRows setObject: expression forKey: variable];
}
[self addTermVariablesForExpression: expression variable: variable];
}
- (void) addTermVariablesForExpression: (GSCSLinearExpression *)expression
variable: (GSCSVariable *)variable
{
NSArray *termVariables = [expression termVariables];
FOR_IN(GSCSVariable *, expressionTermVariable, termVariables)
[self addMappingFromExpressionVariable: expressionTermVariable
toRowVariable: variable];
if ([expressionTermVariable isExternal])
{
[_externalParametricVariables addObject: expressionTermVariable];
}
END_FOR_IN(termVariables);
}
- (void) addMappingFromExpressionVariable: (GSCSVariable *)columnVariable
toRowVariable: (GSCSVariable *)rowVariable
{
NSMutableSet *columnSet = [_columns objectForKey: columnVariable];
if (columnSet == nil)
{
columnSet = [NSMutableSet set];
[_columns setObject: columnSet forKey: columnVariable];
}
[columnSet addObject: rowVariable];
}
- (void) removeMappingFromExpressionVariable: (GSCSVariable *)columnVariable
toRowVariable: (GSCSVariable *)rowVariable
{
NSMutableSet *columnSet = [_columns objectForKey: columnVariable];
if (columnSet == nil)
{
return;
}
[columnSet removeObject: rowVariable];
}
- (void) removeColumn: (GSCSVariable *)variable
{
NSSet *crows = [_columns objectForKey: variable];
if (_rows != nil)
{
FOR_IN(GSCSVariable *, clv, crows)
GSCSLinearExpression *expression = [_rows objectForKey: clv];
[expression removeVariable: variable];
END_FOR_IN(crows);
[_columns removeObjectForKey: variable];
}
if ([variable isExternal])
{
[_externalRows removeObjectForKey: variable];
}
}
- (void) removeRowForVariable: (GSCSVariable *)variable
{
GSCSLinearExpression *expression = [_rows objectForKey: variable];
if (expression == nil)
{
NSException *missingExpressionException = [NSException
exceptionWithName: NSInvalidArgumentException
reason: @"No expression exists for the provided variable"
userInfo: nil];
[missingExpressionException raise];
}
[_rows removeObjectForKey: variable];
if ([variable isExternal])
{
[_externalRows removeObjectForKey: variable];
}
NSArray *expressionTermVariables = [expression termVariables];
FOR_IN(GSCSVariable *, expressionTermVariable, expressionTermVariables)
[self removeMappingFromExpressionVariable: expressionTermVariable
toRowVariable: variable];
END_FOR_IN(expressionTermVariables);
}
- (BOOL) hasRowForVariable: (GSCSVariable *)variable
{
return [_rows objectForKey: variable] != nil;
}
- (void) substituteOutVariable: (GSCSVariable *)variable
forExpression: (GSCSLinearExpression *)expression
{
NSSet *variableSet = [[_columns objectForKey: variable] copy];
FOR_IN(GSCSVariable *, columnVariable, variableSet)
GSCSLinearExpression *row = [_rows objectForKey: columnVariable];
[self substituteOutTerm: variable
withExpression: expression
inExpression: row
subject: columnVariable];
if ([columnVariable isRestricted] && [row constant] < 0.0)
{
[_infeasibleRows addObject: columnVariable];
}
END_FOR_IN(variableSet);
RELEASE(variableSet);
if ([variable isExternal])
{
[_externalRows setObject: expression forKey: variable];
[_externalParametricVariables removeObject: variable];
}
[_columns removeObjectForKey: variable];
}
- (void) substituteOutTerm: (GSCSVariable *)term
withExpression: (GSCSLinearExpression *)newExpression
inExpression: (GSCSLinearExpression *)expression
subject: (GSCSVariable *)subject
{
CGFloat coefficieint = [expression coefficientForTerm: term];
[expression removeVariable: term];
[expression setConstant: (coefficieint * [newExpression constant]) +
[expression constant]];
NSArray *termVariables = [expression termVariables];
FOR_IN(GSCSVariable *, newExpressionTerm, termVariables)
[self substituteOutTermInExpression: expression
newExpression: newExpression
subject: subject
term: newExpressionTerm
multiplier: coefficieint];
END_FOR_IN(termVariables);
}
- (void) substituteOutTermInExpression: (GSCSLinearExpression *)expression
newExpression:
(GSCSLinearExpression *)newExpression
subject: (GSCSVariable *)subject
term: (GSCSVariable *)term
multiplier: (CGFloat)multiplier
{
NSNumber *coefficentInNewExpression =
[newExpression multiplierForTerm: term];
NSNumber *coefficentInExistingExpression =
[expression multiplierForTerm: term];
if (coefficentInExistingExpression != nil)
{
CGFloat newCoefficent = [self
calculateNewCoefficent: [coefficentInExistingExpression floatValue]
coefficentInNewExpression: [coefficentInNewExpression floatValue]
multiplier: multiplier];
if ([GSCSFloatComparator isApproxiatelyZero: newCoefficent])
{
[expression removeVariable: term];
[self removeMappingFromExpressionVariable: term
toRowVariable: subject];
}
else
{
[expression addVariable: term coefficient: newCoefficent];
}
}
else
{
CGFloat updatedCoefficent
= multiplier * [coefficentInNewExpression floatValue];
[expression addVariable: term coefficient: updatedCoefficent];
[self addMappingFromExpressionVariable: term toRowVariable: subject];
}
}
- (CGFloat) calculateNewCoefficent: (CGFloat)coefficentInExistingExpression
coefficentInNewExpression: (CGFloat)coefficentInNewExpression
multiplier: (CGFloat)multiplier
{
return coefficentInExistingExpression + multiplier * coefficentInNewExpression;
}
- (BOOL) isBasicVariable: (GSCSVariable *)variable
{
return [_rows objectForKey: variable] != nil;
}
- (void) addVariable: (GSCSVariable *)variable
toExpression: (GSCSLinearExpression *)expression
{
[self addVariable: variable
toExpression: expression
withCoefficient: 1.0
subject: nil];
}
- (void) addVariable: (GSCSVariable *)variable
toExpression: (GSCSLinearExpression *)expression
withCoefficient: (CGFloat)coefficient;
{
[self addVariable: variable
toExpression: expression
withCoefficient: coefficient
subject: nil];
}
- (void) addVariable: (GSCSVariable *)variable
toExpression: (GSCSLinearExpression *)expression
withCoefficient: (CGFloat)coefficient
subject: (GSCSVariable *)subject
{
if ([expression isTermForVariable: variable])
{
CGFloat newCoefficient =
[expression coefficientForTerm: variable] + coefficient;
if (newCoefficient == 0 ||
[GSCSFloatComparator isApproxiatelyZero: newCoefficient])
{
[expression removeVariable: variable];
[self removeColumnVariable: variable subject: subject];
}
else
{
[self setVariable: variable
onExpression: expression
withCoefficient: newCoefficient];
}
}
else
{
if (![GSCSFloatComparator isApproxiatelyZero: coefficient])
{
[self setVariable: variable
onExpression: expression
withCoefficient: coefficient];
if (subject)
{
[self addMappingFromExpressionVariable: variable
toRowVariable: subject];
}
}
}
}
- (void) removeColumnVariable: (GSCSVariable *)variable
subject: (GSCSVariable *)subject
{
NSMutableSet *column = [_columns objectForKey: variable];
if (subject != nil && column != nil)
{
[column removeObject: subject];
}
}
- (void) addNewExpression: (GSCSLinearExpression *)newExpression
toExpression: (GSCSLinearExpression *)existingExpression
{
[self addNewExpression: newExpression
toExpression: existingExpression
n: 1
subject: nil];
}
- (void) addNewExpression: (GSCSLinearExpression *)newExpression
toExpression: (GSCSLinearExpression *)existingExpression
n: (CGFloat)n
subject: (GSCSVariable *)subject
{
[existingExpression setConstant: [existingExpression constant]
+ (n * [newExpression constant])];
NSArray *newExpressionTermVariables = [newExpression termVariables];
FOR_IN(GSCSVariable *, term, newExpressionTermVariables)
CGFloat newCoefficient = [newExpression coefficientForTerm: term] * n;
[self addVariable: term
toExpression: existingExpression
withCoefficient: newCoefficient
subject: subject];
[self recordUpdatedVariable: term];
END_FOR_IN(newExpressionTermVariables);
}
- (void) recordUpdatedVariable: (GSCSVariable *)variable
{
if ([variable isExternal])
{
[_externalParametricVariables addObject: variable];
}
}
- (void) setVariable: (GSCSVariable *)variable
onExpression: (GSCSLinearExpression *)expression
withCoefficient: (CGFloat)coefficient
{
[expression addVariable: variable coefficient: coefficient];
[self recordUpdatedVariable: variable];
}
- (void) changeSubjectOnExpression: (GSCSLinearExpression *)expression
existingSubject: (GSCSVariable *)existingSubject
newSubject: (GSCSVariable *)newSubject
{
[self setVariable: existingSubject
onExpression: expression
withCoefficient: [expression newSubject: newSubject]];
}
- (GSCSLinearExpression *) rowExpressionForVariable: (GSCSVariable *)variable
{
return [_rows objectForKey: variable];
}
- (void) pivotWithEntryVariable: (GSCSVariable *)entryVariable
exitVariable: (GSCSVariable *)exitVariable
{
// The expression represents the exit variable, which is about to be removed from the basis.
// This means that the old tableau should contain the equation: exitVar = expr.
GSCSLinearExpression *expression =
[self rowExpressionForVariable: exitVariable];
[self removeRowForVariable: exitVariable];
// Calculate an expression for the entry variable.
// As "expression" has been removed from the tableau,
// we can make destructive modifications to it in order to construct this expression.
[self changeSubjectOnExpression: expression
existingSubject: exitVariable
newSubject: entryVariable];
[self substituteOutVariable: entryVariable forExpression: expression];
if ([entryVariable isExternal])
{
[_externalParametricVariables removeObject: entryVariable];
}
[self addRowForVariable: entryVariable equalsExpression: expression];
}
- (NSString *) description
{
NSMutableString *description =
[NSMutableString stringWithString: @"Tableau Information\n"];
[description appendFormat: @"Rows: %ld (%ld constraints)\n", [_rows count],
[_rows count] - 1];
[description appendFormat: @"Columns: %ld\n", [_columns count]];
[description appendFormat: @"Infeasible rows: %ld\n", [_infeasibleRows count]];
[description
appendFormat: @"External basic variables: %ld\n", [_externalRows count]];
[description appendFormat: @"External parametric variables: %ld\n\n",
[_externalParametricVariables count]];
[description appendString: @"Columns: \n"];
[description appendString: [self columnsDescription]];
[description appendString: @"\nRows:\n"];
[description appendString: [self rowsDescription]];
return description;
}
- (NSString *) columnsDescription
{
NSMutableString *description = [NSMutableString string];
FOR_IN(GSCSVariable *, columnVariable, _columns)
[description appendFormat: @"%@ : %@", columnVariable,
[_columns objectForKey: columnVariable]];
END_FOR_IN(_columns);
return description;
}
- (NSString *) rowsDescription
{
NSMutableString *description = [NSMutableString string];
FOR_IN(GSCSVariable *, variable, _rows)
[description
appendFormat: @"%@ : %@\n", variable, [_rows objectForKey: variable]];
END_FOR_IN(_rows);
return description;
}
- (BOOL) hasInfeasibleRows
{
return [_infeasibleRows count] > 0;
}
- (BOOL) containsExternalParametricVariableForEveryExternalTerm
{
FOR_IN(GSCSVariable *, rowVariable, _rows)
GSCSLinearExpression *expression = [_rows objectForKey: rowVariable];
NSArray *termVariables = [expression termVariables];
FOR_IN(GSCSVariable *, variable, termVariables)
if ([variable isExternal])
{
if (![_externalParametricVariables containsObject: variable])
{
return NO;
}
}
END_FOR_IN(termVariables);
END_FOR_IN(_rows);
return YES;
}
- (BOOL) containsExternalRowForEachExternalRowVariable
{
FOR_IN(GSCSVariable *, rowVariable, _rows)
if ([rowVariable isExternal] &&
[_externalRows objectForKey: rowVariable] == nil)
{
return NO;
}
END_FOR_IN(_rows);
return YES;
}
- (NSArray *) substitedOutNonBasicPivotableVariables: (GSCSVariable *)objective
{
GSCSLinearExpression *objectiveRowExpression =
[self rowExpressionForVariable: objective];
NSMutableArray *substitutedOutVariables = [NSMutableArray array];
FOR_IN(GSCSVariable *, columnVariable, _columns)
if ([columnVariable isPivotable] && ![self isBasicVariable: columnVariable]
&& ![objectiveRowExpression isTermForVariable: columnVariable])
{
[substitutedOutVariables addObject: columnVariable];
}
END_FOR_IN(_columns);
return substitutedOutVariables;
}
- (GSCSVariable *) findPivotableExitVariable: (GSCSVariable *)entryVariable
{
CGFloat minRatio = DBL_MAX;
CGFloat r = 0;
GSCSVariable *exitVariable = nil;
NSSet *column = [self columnForVariable: entryVariable];
FOR_IN(GSCSVariable *, variable, column)
if ([variable isPivotable])
{
GSCSLinearExpression *expression =
[self rowExpressionForVariable: variable];
CGFloat coefficient = [expression coefficientForTerm: entryVariable];
if (coefficient < 0)
{
r = -[expression constant] / coefficient;
// Bland's anti-cycling rule:
// if multiple variables are about the same,
// always pick the lowest via some total
// ordering -- in this implementation we preferred the variable
// created first
if (r < minRatio
|| ([GSCSFloatComparator isApproxiatelyEqual: r b: minRatio] &&
[self shouldPreferPivotableVariable: variable
overPivotableVariable: exitVariable]))
{
minRatio = r;
exitVariable = variable;
}
}
}
END_FOR_IN(column);
return exitVariable;
}
- (GSCSVariable *) findPivotableExitVariableWithoutCheck:
(GSCSVariable *)entryVariable
{
CGFloat minRatio = DBL_MAX;
CGFloat r = 0;
GSCSVariable *exitVariable = nil;
NSSet *column = [self columnForVariable: entryVariable];
FOR_IN(GSCSVariable *, variable, column)
GSCSLinearExpression *expression =
[self rowExpressionForVariable: variable];
CGFloat coefficient = [expression coefficientForTerm: entryVariable];
r = -[expression constant] / coefficient;
// Bland's anti-cycling rule
if (r < minRatio
|| ([GSCSFloatComparator isApproxiatelyEqual: r b: minRatio] &&
[self shouldPreferPivotableVariable: variable
overPivotableVariable: exitVariable]))
{
minRatio = r;
exitVariable = variable;
}
END_FOR_IN(column);
return exitVariable;
}
- (GSCSVariable *)
findExitVariableForEquationWhichMinimizesRatioOfRestrictedVariables:
(GSCSVariable *)constraintMarkerVariable
{
GSCSVariable *exitVariable = nil;
CGFloat minRatio = 0;
NSSet *column = [self columnForVariable: constraintMarkerVariable];
FOR_IN(GSCSVariable *, variable, column)
if ([variable isRestricted])
{
GSCSLinearExpression *expression =
[self rowExpressionForVariable: variable];
CGFloat coefficient =
[expression coefficientForTerm: constraintMarkerVariable];
CGFloat r = [expression constant] / coefficient;
if (exitVariable == nil || r < minRatio)
{
minRatio = r;
exitVariable = variable;
}
}
END_FOR_IN(column);
return exitVariable;
}
- (GSCSVariable *) findNonBasicVariables
{
FOR_IN(GSCSVariable *, variable, _externalParametricVariables)
if (![self isBasicVariable: variable])
{
return variable;
}
END_FOR_IN(_externalParametricVariables);
return nil;
}
- (void) dealloc
{
RELEASE(_rows);
RELEASE(_columns);
RELEASE(_externalParametricVariables);
RELEASE(_externalRows);
RELEASE(_infeasibleRows);
RELEASE(_objective);
[super dealloc];
}
@end

View file

@ -69,6 +69,12 @@ typedef enum GSCSVariableType GSCSVariableType;
+ (instancetype) variableWithValue: (CGFloat)value name: (NSString *)name;
+ (instancetype) dummyVariableWithName: (NSString*)name;
+ (instancetype) slackVariableWithName: (NSString*)name;
+ (instancetype) objectiveVariableWithName: (NSString*)name;
@end
#endif

View file

@ -24,11 +24,6 @@
@implementation GSCSVariable
- (instancetype) init
{
return [self initWithName: nil type: GSCSVaraibleTypeVariable];
}
- (instancetype) initWithName: (NSString *)name
{
self = [super init];
@ -53,6 +48,11 @@
return self;
}
- (instancetype) init
{
return [self initWithName: nil type: GSCSVaraibleTypeVariable];
}
+ (instancetype) dummyVariableWithName: (NSString *)name
{
return AUTORELEASE([[GSCSVariable alloc] initWithName: name type: GSCSVariableTypeDummy]);