mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-22 19:01:15 +00:00
317 lines
7.6 KiB
Objective-C
317 lines
7.6 KiB
Objective-C
/* Copyright (C) 2023 Free Software Foundation, Inc.
|
|
|
|
By: Benjamin Johnson
|
|
Date: 19-3-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 "GSCSFloatComparator.h"
|
|
#import "GSCSVariable.h"
|
|
#import "GSFastEnumeration.h"
|
|
|
|
@implementation GSCSLinearExpression
|
|
|
|
- (instancetype) init
|
|
{
|
|
self = [super init];
|
|
if (self)
|
|
{
|
|
ASSIGN(_terms, [NSMapTable strongToStrongObjectsMapTable]);
|
|
ASSIGN(_termVariables, [NSMutableArray array]);
|
|
_constant = 0;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (instancetype) initWithVariable: (GSCSVariable *)variable
|
|
{
|
|
self = [self init];
|
|
if (self)
|
|
{
|
|
[self addVariable: variable coefficient: 1.0];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (instancetype) initWithVariables: (NSArray *)variables
|
|
{
|
|
self = [self init];
|
|
if (self)
|
|
{
|
|
FOR_IN(GSCSVariable *, variable, variables)
|
|
[self addVariable: variable coefficient: 1.0];
|
|
END_FOR_IN(variables)
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (instancetype) initWithConstant: (CGFloat)constant
|
|
{
|
|
self = [self init];
|
|
if (self)
|
|
{
|
|
_constant = constant;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (instancetype) initWithVariable: (GSCSVariable *)variable
|
|
coefficient: (CGFloat)coefficient
|
|
constant: (CGFloat)constant
|
|
{
|
|
self = [self init];
|
|
if (self)
|
|
{
|
|
[self addVariable: variable coefficient: coefficient];
|
|
_constant = constant;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (CGFloat) constant
|
|
{
|
|
return _constant;
|
|
}
|
|
|
|
- (void) setConstant: (CGFloat)constant
|
|
{
|
|
_constant = constant;
|
|
}
|
|
|
|
- (NSMapTable *) terms
|
|
{
|
|
return _terms;
|
|
}
|
|
|
|
- (NSArray *) termVariables
|
|
{
|
|
return _termVariables;
|
|
}
|
|
|
|
- (void) removeVariable: (GSCSVariable *)variable
|
|
{
|
|
[_terms removeObjectForKey: variable];
|
|
[_termVariables removeObject: variable];
|
|
}
|
|
|
|
- (NSNumber *) multiplierForTerm: (GSCSVariable *)variable
|
|
{
|
|
return [_terms objectForKey: variable];
|
|
}
|
|
|
|
- (CGFloat) newSubject: (GSCSVariable *)subject
|
|
{
|
|
CGFloat reciprocal = 1.0 / [self coefficientForTerm: subject];
|
|
|
|
[self multiplyConstantAndTermsBy: -reciprocal];
|
|
|
|
[self removeVariable: subject];
|
|
return reciprocal;
|
|
}
|
|
|
|
- (void) multiplyConstantAndTermsBy: (CGFloat)value
|
|
{
|
|
_constant = _constant * value;
|
|
|
|
NSMutableArray *keys = [NSMutableArray arrayWithCapacity: [_terms count]];
|
|
FOR_IN(GSCSVariable *, term, _terms)
|
|
[keys addObject: term];
|
|
END_FOR_IN(_terms)
|
|
|
|
FOR_IN(GSCSVariable *, term, keys)
|
|
NSNumber *termCoefficent = [_terms objectForKey: term];
|
|
CGFloat multipliedTermCoefficent = [termCoefficent doubleValue] * value;
|
|
[_terms setObject: [NSNumber numberWithDouble: multipliedTermCoefficent]
|
|
forKey: term];
|
|
END_FOR_IN(keys)
|
|
}
|
|
|
|
- (void) divideConstantAndTermsBy: (CGFloat)value
|
|
{
|
|
[self multiplyConstantAndTermsBy: 1 / value];
|
|
}
|
|
|
|
- (CGFloat) coefficientForTerm: (GSCSVariable *)variable
|
|
{
|
|
return [[self multiplierForTerm: variable] floatValue];
|
|
}
|
|
|
|
- (void) normalize
|
|
{
|
|
[self multiplyConstantAndTermsBy: -1];
|
|
}
|
|
|
|
- (id) copyWithZone: (NSZone *)zone
|
|
{
|
|
GSCSLinearExpression *expression = [[[self class] allocWithZone: zone] init];
|
|
if (expression)
|
|
{
|
|
[expression setConstant: [self constant]];
|
|
FOR_IN(GSCSVariable *, variable, _termVariables)
|
|
[expression addVariable: variable
|
|
coefficient: [self coefficientForTerm: variable]];
|
|
END_FOR_IN(_termVariables)
|
|
}
|
|
|
|
return expression;
|
|
}
|
|
|
|
- (NSArray *) findPivotableVariablesWithMostNegativeCoefficient
|
|
{
|
|
CGFloat mostNegativeCoefficient = 0;
|
|
FOR_IN(GSCSVariable *, term, _termVariables)
|
|
CGFloat coefficientForTerm = [self coefficientForTerm: term];
|
|
if ([term isPivotable] && coefficientForTerm < mostNegativeCoefficient)
|
|
{
|
|
mostNegativeCoefficient = coefficientForTerm;
|
|
}
|
|
END_FOR_IN(_termVariables)
|
|
|
|
NSMutableArray *candidates = [NSMutableArray array];
|
|
FOR_IN(GSCSVariable *, term, _termVariables)
|
|
CGFloat coefficientForTerm = [self coefficientForTerm: term];
|
|
if ([term isPivotable] &&
|
|
[GSCSFloatComparator isApproxiatelyEqual: coefficientForTerm
|
|
b: mostNegativeCoefficient])
|
|
{
|
|
[candidates addObject: term];
|
|
}
|
|
END_FOR_IN(_termVariables)
|
|
|
|
return candidates;
|
|
}
|
|
|
|
- (BOOL) isConstant
|
|
{
|
|
return [_terms count] == 0;
|
|
}
|
|
|
|
- (BOOL) isTermForVariable: (GSCSVariable *)variable
|
|
{
|
|
return [_terms objectForKey: variable] != nil;
|
|
}
|
|
|
|
- (GSCSVariable *) anyPivotableVariable
|
|
{
|
|
if ([self isConstant])
|
|
{
|
|
[[NSException exceptionWithName: NSInternalInconsistencyException
|
|
reason: @"anyPivotableVariable invoked on a "
|
|
@"constant expression"
|
|
userInfo: nil] raise];
|
|
}
|
|
|
|
FOR_IN(GSCSVariable *, variable, _termVariables)
|
|
if ([variable isPivotable])
|
|
{
|
|
return variable;
|
|
}
|
|
END_FOR_IN(_termVariables)
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (BOOL) containsOnlyDummyVariables
|
|
{
|
|
FOR_IN(GSCSVariable *, term, _termVariables)
|
|
if (![term isDummy])
|
|
{
|
|
return NO;
|
|
}
|
|
END_FOR_IN(_termVariables)
|
|
|
|
return YES;
|
|
}
|
|
|
|
- (NSArray *) externalVariables
|
|
{
|
|
NSMutableArray *externalVariables = [NSMutableArray array];
|
|
FOR_IN(GSCSVariable *, variable, _terms)
|
|
if ([variable isExternal])
|
|
{
|
|
[externalVariables addObject: variable];
|
|
}
|
|
END_FOR_IN(_terms)
|
|
|
|
return externalVariables;
|
|
}
|
|
|
|
- (void) addVariable: (GSCSVariable *)variable
|
|
{
|
|
[self addVariable: variable coefficient: 1];
|
|
}
|
|
|
|
- (void) addVariable: (GSCSVariable *)variable
|
|
coefficient: (CGFloat)coefficient;
|
|
{
|
|
if (![GSCSFloatComparator isApproxiatelyZero: coefficient])
|
|
{
|
|
if ([self isTermForVariable: variable])
|
|
{
|
|
[_termVariables removeObject: variable];
|
|
}
|
|
[_terms setObject: [NSNumber numberWithFloat: coefficient]
|
|
forKey: variable];
|
|
[_termVariables addObject: variable];
|
|
}
|
|
}
|
|
|
|
- (NSString *) description
|
|
{
|
|
NSString *descriptionString = [NSString stringWithFormat:@"%f", _constant];
|
|
FOR_IN(GSCSVariable *, term, _termVariables)
|
|
descriptionString = [descriptionString
|
|
stringByAppendingString:
|
|
[NSString stringWithFormat: @" + %f * %@",
|
|
[self coefficientForTerm: term],
|
|
[term description]]];
|
|
END_FOR_IN(_termVariables)
|
|
|
|
return descriptionString;
|
|
}
|
|
|
|
- (void) addExpression: (GSCSLinearExpression *)expression
|
|
{
|
|
[self addExpression: expression multiplier: 1];
|
|
}
|
|
|
|
- (void) addExpression: (GSCSLinearExpression *)expression
|
|
multiplier: (CGFloat)multiplier
|
|
{
|
|
[self setConstant: [self constant] + [expression constant] * multiplier];
|
|
NSArray *termVariables = [expression termVariables];
|
|
FOR_IN(GSCSVariable *, term, termVariables)
|
|
CGFloat termCoefficient =
|
|
[expression coefficientForTerm: term] * multiplier;
|
|
[self addVariable: term coefficient: termCoefficient];
|
|
END_FOR_IN(termVariables)
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
RELEASE(_terms);
|
|
RELEASE(_termVariables);
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
@end
|