diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 24daefedf9..2eee66dcac 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -38,7 +38,7 @@ BEOS_BIN = addattr alert basename beep cat catattr chgrp chmod chop chown clear BEOS_APPS = Terminal Expander People ShowImage Clock Pulse ProcessController Playground SoundRecorder BitmapDrawing Magnify DiskProbe AboutHaiku StyledEdit Installer Chart Workspaces $(X86_ONLY)Cortex $(X86_ONLY)CortexAddOnHost $(X86_ONLY)GLTeapot - MediaPlayer DeskCalc MidiPlayer + MediaPlayer DeskCalc MidiPlayer Icon-O-Matic ; BEOS_PREFERENCES = Backgrounds DataTranslations FileTypes Fonts Media Menu Mouse Keyboard Keymap Screen ScreenSaver Sounds Time VirtualMemory @@ -47,7 +47,7 @@ BEOS_SYSTEM_LIB = libbe.so $(HAIKU_LIBSTDC++) libmedia.so libtracker.so libtranslation.so libnetwork.so libdebug.so libbsd.so libtextencoding.so libz.so libfreetype.so libpng.so libmidi.so libmidi2.so libdevice.so libgame.so libscreensaver.so libroot.so $(X86_ONLY)libGL.so - libfluidsynth.so + libfluidsynth.so libqoca.so ; BEOS_SYSTEM_SERVERS = registrar debug_server syslog_daemon media_server media_addon_server input_server app_server fake_app_server midi_server diff --git a/headers/build/HaikuBuildCompatibility.h b/headers/build/HaikuBuildCompatibility.h index 15a83650b2..7203ee125e 100644 --- a/headers/build/HaikuBuildCompatibility.h +++ b/headers/build/HaikuBuildCompatibility.h @@ -27,10 +27,16 @@ typedef unsigned long haiku_build_addr_t; # define B_CURRENT_TEAM 0 #endif + +#ifndef SYMLOOP_MAX +# define SYMLOOP_MAX (16) +#endif + #ifndef B_FIRST_REAL_TIME_PRIORITY # define B_FIRST_REAL_TIME_PRIORITY B_REAL_TIME_DISPLAY_PRIORITY #endif + #ifdef __cplusplus extern "C" { #endif diff --git a/headers/libs/expat/expat.h b/headers/libs/expat/expat.h new file mode 100644 index 0000000000..cb07c1c92e --- /dev/null +++ b/headers/libs/expat/expat.h @@ -0,0 +1,1004 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef XmlParse_INCLUDED +#define XmlParse_INCLUDED 1 + +#ifdef __VMS +/* 0 1 2 3 0 1 2 3 + 1234567890123456789012345678901 1234567890123456789012345678901 */ +#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler +#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler +#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler +#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg +#endif + +#include +#include "expat_external.h" + +struct XML_ParserStruct; +typedef struct XML_ParserStruct *XML_Parser; + +/* Should this be defined using stdbool.h when C99 is available? */ +typedef unsigned char XML_Bool; +#define XML_TRUE ((XML_Bool) 1) +#define XML_FALSE ((XML_Bool) 0) + +/* The XML_Status enum gives the possible return values for several + API functions. The preprocessor #defines are included so this + stanza can be added to code that still needs to support older + versions of Expat 1.95.x: + + #ifndef XML_STATUS_OK + #define XML_STATUS_OK 1 + #define XML_STATUS_ERROR 0 + #endif + + Otherwise, the #define hackery is quite ugly and would have been + dropped. +*/ +enum XML_Status { + XML_STATUS_ERROR = 0, +#define XML_STATUS_ERROR XML_STATUS_ERROR + XML_STATUS_OK = 1, +#define XML_STATUS_OK XML_STATUS_OK + XML_STATUS_SUSPENDED = 2, +#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED +}; + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE, + XML_ERROR_ENTITY_DECLARED_IN_PE, + XML_ERROR_FEATURE_REQUIRES_XML_DTD, + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING, + /* Added in 1.95.7. */ + XML_ERROR_UNBOUND_PREFIX, + /* Added in 1.95.8. */ + XML_ERROR_UNDECLARING_PREFIX, + XML_ERROR_INCOMPLETE_PE, + XML_ERROR_XML_DECL, + XML_ERROR_TEXT_DECL, + XML_ERROR_PUBLICID, + XML_ERROR_SUSPENDED, + XML_ERROR_NOT_SUSPENDED, + XML_ERROR_ABORTED, + XML_ERROR_FINISHED, + XML_ERROR_SUSPEND_PE +}; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + XML_Char * name; + unsigned int numchildren; + XML_Content * children; +}; + + +/* This is called for an element declaration. See above for + description of the model argument. It's the caller's responsibility + to free model when finished with it. +*/ +typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData, + const XML_Char *name, + XML_Content *model); + +XMLPARSEAPI(void) +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl); + +/* The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" + keyword. The "isrequired" parameter will be true and the default + value will be NULL in the case of "#REQUIRED". If "isrequired" is + true and default is non-NULL, then this is a "#FIXED" default. +*/ +typedef void (XMLCALL *XML_AttlistDeclHandler) ( + void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired); + +XMLPARSEAPI(void) +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl); + +/* The XML declaration handler is called for *both* XML declarations + and text declarations. The way to distinguish is that the version + parameter will be NULL for text declarations. The encoding + parameter may be NULL for XML declarations. The standalone + parameter will be -1, 0, or 1 indicating respectively that there + was no standalone parameter in the declaration, that it was given + as no, or that it was given as yes. +*/ +typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +XMLPARSEAPI(void) +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler xmldecl); + + +typedef struct { + void *(*malloc_fcn)(size_t size); + void *(*realloc_fcn)(void *ptr, size_t size); + void (*free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the + external protocol or NULL if there is none specified. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type + names and attribute names that belong to a namespace will be + expanded; unprefixed attribute names are never expanded; unprefixed + element type names are expanded only if there is a default + namespace. The expanded name is the concatenation of the namespace + URI, the namespace separator character, and the local part of the + name. If the namespace separator is '\0' then the namespace URI + and the local part will be concatenated without any separator. + When a namespace is not declared, the name and prefix will be + passed through without expansion. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* Constructs a new parser using the memory management suite referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* Prepare a parser object to be re-used. This is particularly + valuable when memory allocation overhead is disproportionatly high, + such as when a large number of small documnents need to be parsed. + All handlers are cleared from the parser, except for the + unknownEncodingHandler. The parser's external state is re-initialized + except for the values of ns and ns_triplets. + + Added in Expat 1.95.3. +*/ +XMLPARSEAPI(XML_Bool) +XML_ParserReset(XML_Parser parser, const XML_Char *encoding); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. +*/ +typedef void (XMLCALL *XML_StartElementHandler) (void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (XMLCALL *XML_EndElementHandler) (void *userData, + const XML_Char *name); + + +/* s is not 0 terminated. */ +typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (XMLCALL *XML_ProcessingInstructionHandler) ( + void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (XMLCALL *XML_CommentHandler) (void *userData, + const XML_Char *data); + +typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData); +typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData); + +/* This is called for any characters in the XML document for which + there is no applicable handler. This includes both characters that + are part of markup which is of a kind that is not reported + (comments, markup declarations), or characters that are part of a + construct which could be reported but for which no handler has been + supplied. The characters are passed exactly as they were in the XML + document except that they will be encoded in UTF-8 or UTF-16. + Line boundaries are not normalized. Note that a byte order mark + character is not passed to the default handler. There are no + guarantees about how characters are divided between calls to the + default handler: for example, a comment might be split between + multiple calls. +*/ +typedef void (XMLCALL *XML_DefaultHandler) (void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. +*/ +typedef void (XMLCALL *XML_StartDoctypeDeclHandler) ( + void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset); + +/* This is called for the start of the DOCTYPE declaration when the + closing > is encountered, but after processing any external + subset. +*/ +typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (), value will + be non-NULL and systemId, publicID, and notationName will be NULL. + The value string is NOT nul-terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be NULL and systemId will be + non-NULL. The publicId argument will be NULL unless a public + identifier was provided. The notationName argument will have a + non-NULL value only for unparsed entity declarations. + + Note that is_parameter_entity can't be changed to XML_Bool, since + that would break binary compatibility. +*/ +typedef void (XMLCALL *XML_EntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +XMLPARSEAPI(void) +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superceded by the EntityDeclHandler above. + It is provided here for backward compatibility. + + This is called for a declaration of an unparsed (NDATA) entity. + The base argument is whatever was set by XML_SetBase. The + entityName, systemId and notationName arguments will never be + NULL. The other arguments may be. +*/ +typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. The base argument is + whatever was set by XML_SetBase. The notationName will never be + NULL. The other arguments can be. +*/ +typedef void (XMLCALL *XML_NotationDeclHandler) ( + void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for + each namespace declaration. The call to the start and end element + handlers occur between the calls to the start and end namespace + declaration handlers. For an xmlns attribute, prefix will be + NULL. For an xmlns="" attribute, uri will be NULL. +*/ +typedef void (XMLCALL *XML_StartNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (XMLCALL *XML_EndNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone, that is, it has an + external subset or a reference to a parameter entity, but does not + have standalone="yes". If this handler returns XML_STATUS_ERROR, + then processing will not continue, and the parser will return a + XML_ERROR_NOT_STANDALONE error. + If parameter entity parsing is enabled, then in addition to the + conditions above this handler will only be called if the referenced + entity was actually read. +*/ +typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData); + +/* This is called for a reference to an external parsed general + entity. The referenced entity is not automatically parsed. The + application can parse it immediately or later using + XML_ExternalEntityParserCreate. + + The parser argument is the parser parsing the entity containing the + reference; it can be passed as the parser argument to + XML_ExternalEntityParserCreate. The systemId argument is the + system identifier as specified in the entity declaration; it will + not be NULL. + + The base argument is the system identifier that should be used as + the base for resolving systemId if systemId was relative; this is + set by XML_SetBase; it may be NULL. + + The publicId argument is the public identifier as specified in the + entity declaration, or NULL if none was specified; the whitespace + in the public identifier will have been normalized as required by + the XML spec. + + The context argument specifies the parsing context in the format + expected by the context argument to XML_ExternalEntityParserCreate; + context is valid only until the handler returns, so if the + referenced entity is to be parsed later, it must be copied. + context is NULL only when the entity is a parameter entity. + + The handler should return XML_STATUS_ERROR if processing should not + continue because of a fatal error in the handling of the external + entity. In this case the calling parser will return an + XML_ERROR_EXTERNAL_ENTITY_HANDLING error. + + Note that unlike other handlers the first argument is the parser, + not userData. +*/ +typedef int (XMLCALL *XML_ExternalEntityRefHandler) ( + XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This is called in two situations: + 1) An entity reference is encountered for which no declaration + has been read *and* this is not an error. + 2) An internal entity reference is read, but not expanded, because + XML_SetDefaultHandler has been called. + Note: skipped parameter entities in declarations and skipped general + entities in attribute values cannot be reported, because + the event would be out of sync with the reporting of the + declarations or attribute values +*/ +typedef void (XMLCALL *XML_SkippedEntityHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity); + +/* This structure is filled in by the XML_UnknownEncodingHandler to + provide information to the parser about encodings that are unknown + to the parser. + + The map[b] member gives information about byte sequences whose + first byte is b. + + If map[b] is c where c is >= 0, then b by itself encodes the + Unicode scalar value c. + + If map[b] is -1, then the byte sequence is malformed. + + If map[b] is -n, where n >= 2, then b is the first byte of an + n-byte sequence that encodes a single Unicode scalar value. + + The data member will be passed as the first argument to the convert + function. + + The convert function is used to convert multibyte sequences; s will + point to a n-byte sequence where map[(unsigned char)*s] == -n. The + convert function must return the Unicode scalar value represented + by this byte sequence or -1 if the byte sequence is malformed. + + The convert function may be NULL if the encoding is a single-byte + encoding, that is if map[b] >= -1 for all bytes b. + + When the parser is finished with the encoding, then if release is + not NULL, it will call release passing it the data member; once + release has been called, the convert function will not be called + again. + + Expat places certain restrictions on the encodings that are supported + using this mechanism. + + 1. Every ASCII character that can appear in a well-formed XML document, + other than the characters + + $@\^`{}~ + + must be represented by a single byte, and that byte must be the + same byte that represents that character in ASCII. + + 2. No character may require more than 4 bytes to encode. + + 3. All characters encoded must have Unicode scalar values <= + 0xFFFF, (i.e., characters that would be encoded by surrogates in + UTF-16 are not allowed). Note that this restriction doesn't + apply to the built-in support for UTF-8 and UTF-16. + + 4. No Unicode character may be encoded by more than one distinct + sequence of bytes. +*/ +typedef struct { + int map[256]; + void *data; + int (XMLCALL *convert)(void *data, const char *s); + void (XMLCALL *release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. + + The encodingHandlerData argument is that which was passed as the + second argument to XML_SetUnknownEncodingHandler. + + The name argument gives the name of the encoding as specified in + the encoding declaration. + + If the callback can provide information about the encoding, it must + fill in the XML_Encoding structure, and return XML_STATUS_OK. + Otherwise it must return XML_STATUS_ERROR. + + If info does not describe a suitable encoding, then the parser will + return an XML_UNKNOWN_ENCODING error. +*/ +typedef int (XMLCALL *XML_UnknownEncodingHandler) ( + void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +XMLPARSEAPI(void) +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +XMLPARSEAPI(void) +XML_SetStartElementHandler(XML_Parser parser, + XML_StartElementHandler handler); + +XMLPARSEAPI(void) +XML_SetEndElementHandler(XML_Parser parser, + XML_EndElementHandler handler); + +XMLPARSEAPI(void) +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +XMLPARSEAPI(void) +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +XMLPARSEAPI(void) +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +XMLPARSEAPI(void) +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +XMLPARSEAPI(void) +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +XMLPARSEAPI(void) +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of + internal entities. These entity references will be passed to the + default handler, or to the skipped entity handler, if one is set. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of + internal entities. The entity reference will not be passed to the + default handler. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +XMLPARSEAPI(void) +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-NULL value for arg is specified here, then it will be + passed as the first argument to the external entity ref handler + instead of the parser object. +*/ +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandlerArg(XML_Parser parser, + void *arg); + +XMLPARSEAPI(void) +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler); + +XMLPARSEAPI(void) +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end + element, processing instruction or character data. It causes the + corresponding markup to be passed to the default handler. +*/ +XMLPARSEAPI(void) +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single string separated by + the separator character specified when the parser was created: URI + + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the name + has a prefix. + + Note: Calling XML_SetReturnNSTriplet after XML_Parse or + XML_ParseBuffer has no effect. +*/ + +XMLPARSEAPI(void) +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +XMLPARSEAPI(void) +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or NULL. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument to + XML_ParserCreate. On success XML_SetEncoding returns non-zero, + zero otherwise. + Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer + has no effect and returns XML_STATUS_ERROR. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed as the + first argument to callbacks instead of userData. The userData will + still be accessible using XML_GetUserData. +*/ +XMLPARSEAPI(void) +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* If useDTD == XML_TRUE is passed to this function, then the parser + will assume that there is an external subset, even if none is + specified in the document. In such a case the parser will call the + externalEntityRefHandler with a value of NULL for the systemId + argument (the publicId and context arguments will be NULL as well). + Note: For the purpose of checking WFC: Entity Declared, passing + useDTD == XML_TRUE will make the parser behave as if the document + had a DTD with an external subset. + Note: If this function is called, then this must be done before + the first call to XML_Parse or XML_ParseBuffer, since it will + have no effect after that. Returns + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING. + Note: If the document does not have a DOCTYPE declaration at all, + then startDoctypeDeclHandler and endDoctypeDeclHandler will not + be called, despite an external subset being parsed. + Note: If XML_DTD is not defined when Expat is compiled, returns + XML_ERROR_FEATURE_REQUIRES_XML_DTD. +*/ +XMLPARSEAPI(enum XML_Error) +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD); + + +/* Sets the base to be used for resolving relative URIs in system + identifiers in declarations. Resolving relative identifiers is + left to the application: this value will be passed through as the + base argument to the XML_ExternalEntityRefHandler, + XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base + argument will be copied. Returns XML_STATUS_ERROR if out of memory, + XML_STATUS_OK otherwise. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetBase(XML_Parser parser, const XML_Char *base); + +XMLPARSEAPI(const XML_Char *) +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call + to the XML_StartElementHandler that were specified in the start-tag + rather than defaulted. Each attribute/value pair counts as 2; thus + this correspondds to an index into the atts array passed to the + XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to + XML_StartElementHandler, or -1 if there is no ID attribute. Each + attribute/value pair counts as 2; thus this correspondds to an + index into the atts array passed to the XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetIdAttributeIndex(XML_Parser parser); + +/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is + detected. The last call to XML_Parse must have isFinal true; len + may be zero for this call (or any other). + + Though the return values for these functions has always been + described as a Boolean value, the implementation, at least for the + 1.95.x series, has always returned exactly one of the XML_Status + values. +*/ +XMLPARSEAPI(enum XML_Status) +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +XMLPARSEAPI(void *) +XML_GetBuffer(XML_Parser parser, int len); + +XMLPARSEAPI(enum XML_Status) +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return. + Must be called from within a call-back handler, except when aborting + (resumable = 0) an already suspended parser. Some call-backs may + still follow because they would otherwise get lost. Examples: + - endElementHandler() for empty elements when stopped in + startElementHandler(), + - endNameSpaceDeclHandler() when stopped in endElementHandler(), + and possibly others. + + Can be called from most handlers, including DTD related call-backs, + except when parsing an external parameter entity and resumable != 0. + Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise. + Possible error codes: + - XML_ERROR_SUSPENDED: when suspending an already suspended parser. + - XML_ERROR_FINISHED: when the parser has already finished. + - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE. + + When resumable != 0 (true) then parsing is suspended, that is, + XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED. + Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer() + return XML_STATUS_ERROR with error code XML_ERROR_ABORTED. + + *Note*: + This will be applied to the current parser instance only, that is, if + there is a parent parser then it will continue parsing when the + externalEntityRefHandler() returns. It is up to the implementation of + the externalEntityRefHandler() to call XML_StopParser() on the parent + parser (recursively), if one wants to stop parsing altogether. + + When suspended, parsing can be resumed by calling XML_ResumeParser(). +*/ +XMLPARSEAPI(enum XML_Status) +XML_StopParser(XML_Parser parser, XML_Bool resumable); + +/* Resumes parsing after it has been suspended with XML_StopParser(). + Must not be called from within a handler call-back. Returns same + status codes as XML_Parse() or XML_ParseBuffer(). + Additional error code XML_ERROR_NOT_SUSPENDED possible. + + *Note*: + This must be called on the most deeply nested child parser instance + first, and on its parent parser only after the child parser has finished, + to be applied recursively until the document entity's parser is restarted. + That is, the parent parser will not resume by itself and it is up to the + application to call XML_ResumeParser() on it at the appropriate moment. +*/ +XMLPARSEAPI(enum XML_Status) +XML_ResumeParser(XML_Parser parser); + +enum XML_Parsing { + XML_INITIALIZED, + XML_PARSING, + XML_FINISHED, + XML_SUSPENDED +}; + +typedef struct { + enum XML_Parsing parsing; + XML_Bool finalBuffer; +} XML_ParsingStatus; + +/* Returns status of parser with respect to being initialized, parsing, + finished, or suspended and processing the final buffer. + XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus, + XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED +*/ +XMLPARSEAPI(void) +XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status); + +/* Creates an XML_Parser object that can parse an external general + entity; context is a '\0'-terminated string specifying the parse + context; encoding is a '\0'-terminated string giving the name of + the externally specified encoding, or NULL if there is no + externally specified encoding. The context string consists of a + sequence of tokens separated by formfeeds (\f); a token consisting + of a name specifies that the general entity of the name is open; a + token of the form prefix=uri specifies the namespace for a + particular prefix; a token of the form =uri specifies the default + namespace. This can be called at any point after the first call to + an ExternalEntityRefHandler so longer as the parser has not yet + been freed. The new parser is completely independent and may + safely be used in a separate thread. The handlers and userData are + initialized from the parser argument. Returns NULL if out of memory. + Otherwise returns a new XML_Parser object. +*/ +XMLPARSEAPI(XML_Parser) +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD + subset). If parsing of parameter entities is enabled, then + references to external parameter entities (including the external + DTD subset) will be passed to the handler set with + XML_SetExternalEntityRefHandler. The context passed will be 0. + + Unlike external general entities, external parameter entities can + only be parsed synchronously. If the external parameter entity is + to be parsed, it must be parsed during the call to the external + entity ref handler: the complete sequence of + XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and + XML_ParserFree calls must be made during this call. After + XML_ExternalEntityParserCreate has been called to create the parser + for the external parameter entity (context must be 0 for this + call), it is illegal to make any calls on the old parser until + XML_ParserFree has been called on the newly created parser. + If the library has been compiled without support for parameter + entity parsing (ie without XML_DTD being defined), then + XML_SetParamEntityParsing will return 0 if parsing of parameter + entities is requested; otherwise it will return non-zero. + Note: If XML_SetParamEntityParsing is called after XML_Parse or + XML_ParseBuffer, then it has no effect and will always return 0. +*/ +XMLPARSEAPI(int) +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then + XML_GetErrorCode returns information about the error. +*/ +XMLPARSEAPI(enum XML_Error) +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse + location. They may be called from any callback called to report + some parse event; in this case the location is the location of the + first of the sequence of characters that generated the event. When + called from callbacks generated by declarations in the document + prologue, the location identified isn't as neatly defined, but will + be within the relevant markup. When called outside of the callback + functions, the position indicated will be just past the last parse + event (regardless of whether there was an associated callback). + + They may also be called after returning from a call to XML_Parse + or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then + the location is the location of the character at which the error + was detected; otherwise the location is the location of the last + parse event, as described above. +*/ +XMLPARSEAPI(int) XML_GetCurrentLineNumber(XML_Parser parser); +XMLPARSEAPI(int) XML_GetCurrentColumnNumber(XML_Parser parser); +XMLPARSEAPI(long) XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. + Returns 0 if the event is in an internal entity. +*/ +XMLPARSEAPI(int) +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a NULL pointer. Also returns a NULL pointer if a parse isn't + active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. +*/ +XMLPARSEAPI(const char *) +XML_GetInputContext(XML_Parser parser, + int *offset, + int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees the content model passed to the element declaration handler */ +XMLPARSEAPI(void) +XML_FreeContentModel(XML_Parser parser, XML_Content *model); + +/* Exposing the memory handling functions used in Expat */ +XMLPARSEAPI(void *) +XML_MemMalloc(XML_Parser parser, size_t size); + +XMLPARSEAPI(void *) +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size); + +XMLPARSEAPI(void) +XML_MemFree(XML_Parser parser, void *ptr); + +/* Frees memory used by the parser. */ +XMLPARSEAPI(void) +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +XMLPARSEAPI(const XML_LChar *) +XML_ErrorString(enum XML_Error code); + +/* Return a string containing the version number of this expat */ +XMLPARSEAPI(const XML_LChar *) +XML_ExpatVersion(void); + +typedef struct { + int major; + int minor; + int micro; +} XML_Expat_Version; + +/* Return an XML_Expat_Version structure containing numeric version + number information for this version of expat. +*/ +XMLPARSEAPI(XML_Expat_Version) +XML_ExpatVersionInfo(void); + +/* Added in Expat 1.95.5. */ +enum XML_FeatureEnum { + XML_FEATURE_END = 0, + XML_FEATURE_UNICODE, + XML_FEATURE_UNICODE_WCHAR_T, + XML_FEATURE_DTD, + XML_FEATURE_CONTEXT_BYTES, + XML_FEATURE_MIN_SIZE, + XML_FEATURE_SIZEOF_XML_CHAR, + XML_FEATURE_SIZEOF_XML_LCHAR + /* Additional features must be added to the end of this enum. */ +}; + +typedef struct { + enum XML_FeatureEnum feature; + const XML_LChar *name; + long int value; +} XML_Feature; + +XMLPARSEAPI(const XML_Feature *) +XML_GetFeatureList(void); + + +/* Expat follows the GNU/Linux convention of odd number minor version for + beta/development releases and even number minor version for stable + releases. Micro is bumped with each release, and set to 0 with each + change to major or minor version. +*/ +#define XML_MAJOR_VERSION 1 +#define XML_MINOR_VERSION 95 +#define XML_MICRO_VERSION 8 + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlParse_INCLUDED */ diff --git a/headers/libs/expat/expat_config.h b/headers/libs/expat/expat_config.h new file mode 100644 index 0000000000..d4faafd1bb --- /dev/null +++ b/headers/libs/expat/expat_config.h @@ -0,0 +1,93 @@ +/* expat_config.h. Generated by configure. */ +/* expat_config.h.in. Generated from configure.in by autoheader. */ + +/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ +#define BYTEORDER 1234 + +/* Define to 1 if you have the `bcopy' function. */ +#define HAVE_BCOPY 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CHECK_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `getpagesize' function. */ +/* #undef HAVE_GETPAGESIZE */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have a working `mmap' system call. */ +/* #undef HAVE_MMAP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "expat-bugs@mail.libexpat.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "expat" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "expat 1.95.8" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "expat" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.95.8" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* whether byteorder is bigendian */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to specify how much context to retain around the current parse + point. */ +#define XML_CONTEXT_BYTES 1024 + +/* Define to make parameter entity parsing functionality available. */ +#define XML_DTD 1 + +/* Define to make XML Namespaces functionality available. */ +#define XML_NS 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `long' if does not define. */ +/* #undef off_t */ + +/* Define to `unsigned' if does not define. */ +/* #undef size_t */ diff --git a/headers/libs/expat/expat_external.h b/headers/libs/expat/expat_external.h new file mode 100644 index 0000000000..4145cacacd --- /dev/null +++ b/headers/libs/expat/expat_external.h @@ -0,0 +1,92 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +/* External API definitions */ + +#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__) +#define XML_USE_MSC_EXTENSIONS 1 +#endif + +/* Expat tries very hard to make the API boundary very specifically + defined. There are two macros defined to control this boundary; + each of these can be defined before including this header to + achieve some different behavior, but doing so it not recommended or + tested frequently. + + XMLCALL - The calling convention to use for all calls across the + "library boundary." This will default to cdecl, and + try really hard to tell the compiler that's what we + want. + + XMLIMPORT - Whatever magic is needed to note that a function is + to be imported from a dynamically loaded library + (.dll, .so, or .sl, depending on your platform). + + The XMLCALL macro was added in Expat 1.95.7. The only one which is + expected to be directly useful in client code is XMLCALL. + + Note that on at least some Unix versions, the Expat library must be + compiled with the cdecl calling convention as the default since + system headers may assume the cdecl convention. +*/ +#ifndef XMLCALL +#if defined(XML_USE_MSC_EXTENSIONS) +#define XMLCALL __cdecl +#elif defined(__GNUC__) && defined(__i386) +#define XMLCALL __attribute__((cdecl)) +#else +/* For any platform which uses this definition and supports more than + one calling convention, we need to extend this definition to + declare the convention used on that platform, if it's possible to + do so. + + If this is the case for your platform, please file a bug report + with information on how to identify your platform via the C + pre-processor and how to specify the same calling convention as the + platform's malloc() implementation. +*/ +#define XMLCALL +#endif +#endif /* not defined XMLCALL */ + + +#if !defined(XML_STATIC) && !defined(XMLIMPORT) +#ifndef XML_BUILDING_EXPAT +/* using Expat from an application */ + +#ifdef XML_USE_MSC_EXTENSIONS +#define XMLIMPORT __declspec(dllimport) +#endif + +#endif +#endif /* not defined XML_STATIC */ + +/* If we didn't define it above, define it away: */ +#ifndef XMLIMPORT +#define XMLIMPORT +#endif + + +#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef XML_UNICODE_WCHAR_T +#define XML_UNICODE +#endif + +#ifdef XML_UNICODE /* Information is UTF-16 encoded. */ +#ifdef XML_UNICODE_WCHAR_T +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; +#else +typedef unsigned short XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE_WCHAR_T */ +#else /* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE */ diff --git a/headers/libs/icon/IconUtils.h b/headers/libs/icon/IconUtils.h new file mode 100644 index 0000000000..bd97b6452c --- /dev/null +++ b/headers/libs/icon/IconUtils.h @@ -0,0 +1,80 @@ +/* + * Copyright 2006, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + * + */ + +#ifndef ICON_UTILS_H +#define ICON_UTILS_H + +#include + +class BBitmap; +class BNode; + +// This class is a little different from many other classes. +// You don't create an instance of it; you just call its various +// static member functions for utility-like operations. +class BIconUtils { + BIconUtils(); + ~BIconUtils(); + BIconUtils(const BIconUtils&); + BIconUtils& operator=(const BIconUtils&); + + public: + + // Utility function to import an icon from the node that + // has either of the provided attribute names. Which icon type + // is preferred (vector, small or large B_CMAP8 icon) depends + // on the colorspace of the provided bitmap. If the colorspace + // is B_CMAP8, B_CMAP8 icons are preferred. If no vector icon + // is available, the bitmap size must match the provided + // icon_size "size"! + static status_t GetIcon(BNode* node, + const char* vectorIconAttrName, + const char* smallIconAttrName, + const char* largeIconAttrName, + icon_size size, + BBitmap* result); + + // Utility functions to import a vector icon in "flat icon" + // format from a BNode attribute or from a flat buffer in + // memory into the preallocated BBitmap "result". + // The colorspace of result needs to be B_RGBA32 or at + // least B_RGB32 (though that makes less sense). The icon + // will be scaled from it's "native" size of 64x64 to the + // size of the bitmap, the scale is derived from the bitmap + // width, the bitmap should have square dimension, or the + // icon will be cut off at the bottom (or have room left). + static status_t GetVectorIcon(BNode* node, + const char* attrName, + BBitmap* result); + + static status_t GetVectorIcon(const uint8* buffer, + size_t size, + BBitmap* result); + + // Utility function to import an "old" BeOS icon in B_CMAP8 + // colorspace from either the small icon attribute or the + // large icon attribute as given in "smallIconAttrName" and + // "largeIconAttrName". Which icon is loaded depends on + // the given "size". + static status_t GetCMAP8Icon(BNode* node, + const char* smallIconAttrName, + const char* largeIconAttrName, + icon_size size, + BBitmap* icon); + + // Utility functions to convert from old icon colorspace + // into colorspace of BBitmap "result" (should be B_RGBA32 + // to make any sense). + static status_t ConvertFromCMAP8(BBitmap* source, + BBitmap* result); + + static status_t ConvertFromCMAP8(const uint8* data, + uint32 width, uint32 height, + uint32 bytesPerRow, + BBitmap* result); +}; + +#endif // ICON_UTILS_H diff --git a/headers/os/app/AppDefs.h b/headers/os/app/AppDefs.h index f14c772153..4066f0eb24 100644 --- a/headers/os/app/AppDefs.h +++ b/headers/os/app/AppDefs.h @@ -50,6 +50,7 @@ enum { B_KEY_UP = '_KYU', B_UNMAPPED_KEY_DOWN = '_UKD', B_UNMAPPED_KEY_UP = '_UKU', + B_LAYOUT_WINDOW = '_LAY', B_MODIFIERS_CHANGED = '_MCH', B_MINIMIZE = '_WMN', B_MOUSE_DOWN = '_MDN', diff --git a/headers/os/interface/AbstractLayoutItem.h b/headers/os/interface/AbstractLayoutItem.h new file mode 100644 index 0000000000..49fbdf916a --- /dev/null +++ b/headers/os/interface/AbstractLayoutItem.h @@ -0,0 +1,40 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _ABSTRACT_LAYOUT_ITEM_H +#define _ABSTRACT_LAYOUT_ITEM_H + +#include +#include +#include + + +class BAbstractLayoutItem : public BLayoutItem { +public: + BAbstractLayoutItem(); + virtual ~BAbstractLayoutItem(); + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + virtual BAlignment Alignment(); + + virtual void SetExplicitMinSize(BSize size); + virtual void SetExplicitMaxSize(BSize size); + virtual void SetExplicitPreferredSize(BSize size); + virtual void SetExplicitAlignment(BAlignment alignment); + + virtual BSize BaseMinSize(); + virtual BSize BaseMaxSize(); + virtual BSize BasePreferredSize(); + virtual BAlignment BaseAlignment(); + +private: + BSize fMinSize; + BSize fMaxSize; + BSize fPreferredSize; + BAlignment fAlignment; +}; + +#endif // _ABSTRACT_LAYOUT_ITEM_H diff --git a/headers/os/interface/Alignment.h b/headers/os/interface/Alignment.h new file mode 100644 index 0000000000..55bc6fcf10 --- /dev/null +++ b/headers/os/interface/Alignment.h @@ -0,0 +1,128 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _ALIGNMENT_H +#define _ALIGNMENT_H + +#include + +class BAlignment { +public: + alignment horizontal; + vertical_alignment vertical; + + inline BAlignment(); + inline BAlignment(const BAlignment& other); + inline BAlignment(alignment horizontal, + vertical_alignment vertical); + + inline alignment Horizontal() const; + inline vertical_alignment Vertical() const; + + float RelativeHorizontal() const; + float RelativeVertical() const; + + inline void SetHorizontal(alignment horizontal); + inline void SetVertical(vertical_alignment vertical); + + inline bool IsHorizontalSet() const; + inline bool IsVerticalSet() const; + + inline bool operator==(const BAlignment& other) const; + inline bool operator!=(const BAlignment& other) const; + + inline BAlignment& operator=(const BAlignment& other); +}; + + +// constructor +inline +BAlignment::BAlignment() + : horizontal(B_ALIGN_HORIZONTAL_UNSET), + vertical(B_ALIGN_VERTICAL_UNSET) +{ +} + +// copy constructor +inline +BAlignment::BAlignment(const BAlignment& other) + : horizontal(other.horizontal), + vertical(other.vertical) +{ +} + +// constructor +inline +BAlignment::BAlignment(alignment horizontal, vertical_alignment vertical) + : horizontal(horizontal), + vertical(vertical) +{ +} + +// Horizontal +inline alignment +BAlignment::Horizontal() const +{ + return horizontal; +} + +// Vertical +inline vertical_alignment +BAlignment::Vertical() const +{ + return vertical; +} + +// SetHorizontal +inline void +BAlignment::SetHorizontal(alignment horizontal) +{ + this->horizontal = horizontal; +} + +// SetVertical +inline void +BAlignment::SetVertical(vertical_alignment vertical) +{ + this->vertical = vertical; +} + +// IsHorizontalSet +inline bool +BAlignment::IsHorizontalSet() const +{ + return (horizontal != B_ALIGN_HORIZONTAL_UNSET); +} + +// IsVerticalSet +inline bool +BAlignment::IsVerticalSet() const +{ + return (vertical != B_ALIGN_VERTICAL_UNSET); +} + +// == +inline bool +BAlignment::operator==(const BAlignment& other) const +{ + return (horizontal == other.horizontal && vertical == other.vertical); +} + +// != +inline bool +BAlignment::operator!=(const BAlignment& other) const +{ + return !(*this == other); +} + +// = +inline BAlignment& +BAlignment::operator=(const BAlignment& other) +{ + horizontal = other.horizontal; + vertical = other.vertical; + return *this; +} + +#endif // _ALIGNMENT_H diff --git a/headers/os/interface/Button.h b/headers/os/interface/Button.h index af1c9f76bc..ac69e03dbc 100644 --- a/headers/os/interface/Button.h +++ b/headers/os/interface/Button.h @@ -52,6 +52,10 @@ public: BMessage *message, uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + BButton(const char* name, const char* label, + BMessage *message, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + BButton(const char* label, BMessage *message); virtual ~BButton(); @@ -92,6 +96,9 @@ virtual BHandler *ResolveSpecifier(BMessage *message, virtual status_t GetSupportedSuites(BMessage *message); virtual status_t Perform(perform_code d, void *arg); +virtual BSize MaxSize(); + + private: virtual void _ReservedButton1(); diff --git a/headers/os/interface/CardLayout.h b/headers/os/interface/CardLayout.h new file mode 100644 index 0000000000..f775320aed --- /dev/null +++ b/headers/os/interface/CardLayout.h @@ -0,0 +1,47 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _CARD_LAYOUT_H +#define _CARD_LAYOUT_H + +#include + + +class BCardLayout : public BLayout { +public: + BCardLayout(); + virtual ~BCardLayout(); + + BLayoutItem* VisibleItem() const; + int32 VisibleIndex() const; + void SetVisibleItem(int32 index); + void SetVisibleItem(BLayoutItem* item); + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + virtual BAlignment Alignment(); + + virtual bool HasHeightForWidth(); + virtual void GetHeightForWidth(float width, float* min, + float* max, float* preferred); + + virtual void InvalidateLayout(); + virtual void LayoutView(); + +protected: + virtual void ItemAdded(BLayoutItem* item); + virtual void ItemRemoved(BLayoutItem* item); + +private: + BSize fMin; + BSize fMax; + BSize fPreferred; + BLayoutItem* fVisibleItem; + bool fMinMaxValid; + + void _ValidateMinMax(); +}; + +#endif // _CARD_LAYOUT_H diff --git a/headers/os/interface/ColorControl.h b/headers/os/interface/ColorControl.h index 6d93ed7d43..c7f7172518 100644 --- a/headers/os/interface/ColorControl.h +++ b/headers/os/interface/ColorControl.h @@ -33,6 +33,8 @@ class BColorControl : public BControl { static BArchivable* Instantiate(BMessage* archive); virtual status_t Archive(BMessage* archive, bool deep = true) const; + virtual void SetLayout(BLayout* layout); + virtual void SetValue(int32 color_value); void SetValue(rgb_color color); rgb_color ValueAsColor(); diff --git a/headers/os/interface/GridLayout.h b/headers/os/interface/GridLayout.h new file mode 100644 index 0000000000..b6557a1a58 --- /dev/null +++ b/headers/os/interface/GridLayout.h @@ -0,0 +1,95 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _GRID_LAYOUT_H +#define _GRID_LAYOUT_H + +#include + + + +class BGridLayout : public BTwoDimensionalLayout { +public: + BGridLayout(float horizontal = 0.0f, + float vertical = 0.0f); + virtual ~BGridLayout(); + + float HorizontalSpacing() const; + float VerticalSpacing() const; + + void SetHorizontalSpacing(float spacing); + void SetVerticalSpacing(float spacing); + void SetSpacing(float horizontal, float vertical); + + float ColumnWeight(int32 column) const; + void SetColumnWeight(int32 column, float weight); + + float MinColumnWidth(int32 column) const; + void SetMinColumnWidth(int32 column, float width); + + float MaxColumnWidth(int32 column) const; + void SetMaxColumnWidth(int32 column, float width); + + float RowWeight(int32 row) const; + void SetRowWeight(int32 row, float weight); + + float MinRowHeight(int row) const; + void SetMinRowHeight(int32 row, float height); + + float MaxRowHeight(int32 row) const; + void SetMaxRowHeight(int32 row, float height); + + virtual BLayoutItem* AddView(BView* child); + virtual BLayoutItem* AddView(int32 index, BView* child); + virtual BLayoutItem* AddView(BView* child, int32 column, int32 row, + int32 columnCount = 1, int32 rowCount = 1); + + virtual bool AddItem(BLayoutItem* item); + virtual bool AddItem(int32 index, BLayoutItem* item); + virtual bool AddItem(BLayoutItem* item, int32 column, + int32 row, int32 columnCount = 1, + int32 rowCount = 1); + +protected: + virtual void ItemAdded(BLayoutItem* item); + virtual void ItemRemoved(BLayoutItem* item); + + virtual bool HasMultiColumnItems(); + virtual bool HasMultiRowItems(); + + virtual int32 InternalCountColumns(); + virtual int32 InternalCountRows(); + virtual void GetColumnRowConstraints( + enum orientation orientation, + int32 index, + ColumnRowConstraints* constraints); + virtual void GetItemDimensions(BLayoutItem* item, + Dimensions* dimensions); + +private: + class DummyLayoutItem; + class RowInfoArray; + struct ItemLayoutData; + + bool _IsGridCellEmpty(int32 column, int32 row); + bool _AreGridCellsEmpty(int32 column, int32 row, + int32 columnCount, int32 rowCount); + + bool _ResizeGrid(int32 columnCount, int32 rowCount); + + ItemLayoutData* _LayoutDataForItem(BLayoutItem* item) const; + +private: + BLayoutItem*** fGrid; + int32 fColumnCount; + int32 fRowCount; + + RowInfoArray* fRowInfos; + RowInfoArray* fColumnInfos; + + int32 fMultiColumnItems; + int32 fMultiRowItems; +}; + +#endif // _GRID_LAYOUT_H diff --git a/headers/os/interface/GridLayoutBuilder.h b/headers/os/interface/GridLayoutBuilder.h new file mode 100644 index 0000000000..9ccf040ca8 --- /dev/null +++ b/headers/os/interface/GridLayoutBuilder.h @@ -0,0 +1,38 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _GRID_LAYOUT_BUILDER_H +#define _GRID_LAYOUT_BUILDER_H + +#include + +class BGridLayoutBuilder { +public: + BGridLayoutBuilder( + float horizontalSpacing = 0.0f, + float verticalSpacing = 0.0f); + BGridLayoutBuilder(BGridLayout* layout); + BGridLayoutBuilder(BGridView* view); + + BGridLayout* GridLayout() const; + BView* View() const; + BGridLayoutBuilder& GetGridLayout(BGridLayout** _layout); + BGridLayoutBuilder& GetView(BView** _view); + + BGridLayoutBuilder& Add(BView* view, int32 column, int32 row, + int32 columnCount = 1, int32 rowCount = 1); + BGridLayoutBuilder& Add(BLayoutItem* item, int32 column, int32 row, + int32 columnCount = 1, int32 rowCount = 1); + + BGridLayoutBuilder& SetColumnWeight(int32 column, float weight); + BGridLayoutBuilder& SetRowWeight(int32 row, float weight); + + operator BGridLayout*(); + operator BView*(); + +private: + BGridLayout* fLayout; +}; + +#endif // _GRID_LAYOUT_BUILDER_H diff --git a/headers/os/interface/GridView.h b/headers/os/interface/GridView.h new file mode 100644 index 0000000000..9ffeee9b99 --- /dev/null +++ b/headers/os/interface/GridView.h @@ -0,0 +1,24 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _GRID_VIEW_H +#define _GRID_VIEW_H + +#include +#include + + +class BGridView : public BView { +public: + BGridView(float horizontalSpacing = 0.0f, + float verticalSpacing = 0.0f); + virtual ~BGridView(); + + virtual void SetLayout(BLayout* layout); + + BGridLayout* GridLayout() const; +}; + + +#endif // _GRID_VIEW_H diff --git a/headers/os/interface/GroupLayout.h b/headers/os/interface/GroupLayout.h new file mode 100644 index 0000000000..df6d08c552 --- /dev/null +++ b/headers/os/interface/GroupLayout.h @@ -0,0 +1,61 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _GROUP_LAYOUT_H +#define _GROUP_LAYOUT_H + +#include + +class BGroupLayout : public BTwoDimensionalLayout { +public: + BGroupLayout(enum orientation orientation, + float spacing = 0.0f); + virtual ~BGroupLayout(); + + float Spacing() const; + void SetSpacing(float spacing); + + orientation Orientation() const; + void SetOrientation(enum orientation orientation); + + float ItemWeight(int32 index) const; + void SetItemWeight(int32 index, float weight); + + virtual BLayoutItem* AddView(BView* child); + virtual BLayoutItem* AddView(int32 index, BView* child); + virtual BLayoutItem* AddView(BView* child, float weight); + virtual BLayoutItem* AddView(int32 index, BView* child, + float weight); + + virtual bool AddItem(BLayoutItem* item); + virtual bool AddItem(int32 index, BLayoutItem* item); + virtual bool AddItem(BLayoutItem* item, float weight); + virtual bool AddItem(int32 index, BLayoutItem* item, + float weight); + +protected: + virtual void ItemAdded(BLayoutItem* item); + virtual void ItemRemoved(BLayoutItem* item); + + virtual void PrepareItems(enum orientation orientation); + + virtual int32 InternalCountColumns(); + virtual int32 InternalCountRows(); + virtual void GetColumnRowConstraints( + enum orientation orientation, + int32 index, + ColumnRowConstraints* constraints); + virtual void GetItemDimensions(BLayoutItem* item, + Dimensions* dimensions); + +private: + struct ItemLayoutData; + + ItemLayoutData* _LayoutDataForItem(BLayoutItem* item) const; + + orientation fOrientation; + BList fVisibleItems; +}; + +#endif // _GROUP_LAYOUT_H diff --git a/headers/os/interface/GroupLayoutBuilder.h b/headers/os/interface/GroupLayoutBuilder.h new file mode 100644 index 0000000000..a12bfe4dc1 --- /dev/null +++ b/headers/os/interface/GroupLayoutBuilder.h @@ -0,0 +1,49 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _GROUP_LAYOUT_BUILDER_H +#define _GROUP_LAYOUT_BUILDER_H + +#include +#include +#include + +class BGroupLayoutBuilder { +public: + BGroupLayoutBuilder( + enum orientation orientation = B_HORIZONTAL, + float spacing = 0.0f); + BGroupLayoutBuilder(BGroupLayout* layout); + BGroupLayoutBuilder(BGroupView* view); + + BGroupLayout* RootLayout() const; + BGroupLayout* TopLayout() const; + BGroupLayoutBuilder& GetTopLayout(BGroupLayout** _layout); + BGroupLayoutBuilder& GetTopView(BView** _view); + + BGroupLayoutBuilder& Add(BView* view); + BGroupLayoutBuilder& Add(BView* view, float weight); + BGroupLayoutBuilder& Add(BLayoutItem* item); + BGroupLayoutBuilder& Add(BLayoutItem* item, float weight); + + BGroupLayoutBuilder& AddGroup(enum orientation orientation, + float spacing = 0.0f, float weight = 1.0f); + BGroupLayoutBuilder& End(); + + BGroupLayoutBuilder& AddGlue(float weight = 1.0f); + BGroupLayoutBuilder& AddStrut(float size); + + operator BGroupLayout*(); + operator BView*(); + +private: + bool _PushLayout(BGroupLayout* layout); + void _PopLayout(); + +private: + BGroupLayout* fRootLayout; + BList fLayoutStack; +}; + +#endif // _GROUP_LAYOUT_BUILDER_H diff --git a/headers/os/interface/GroupView.h b/headers/os/interface/GroupView.h new file mode 100644 index 0000000000..9c86ad82c8 --- /dev/null +++ b/headers/os/interface/GroupView.h @@ -0,0 +1,25 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _GROUP_VIEW_H +#define _GROUP_VIEW_H + +#include +#include + + +class BGroupView : public BView { +public: + BGroupView( + enum orientation orientation = B_HORIZONTAL, + float spacing = 0.0f); + virtual ~BGroupView(); + + virtual void SetLayout(BLayout* layout); + + BGroupLayout* GroupLayout() const; +}; + + +#endif // _GROUP_VIEW_H diff --git a/headers/os/interface/InterfaceDefs.h b/headers/os/interface/InterfaceDefs.h index a26feba50f..5a4edde3da 100644 --- a/headers/os/interface/InterfaceDefs.h +++ b/headers/os/interface/InterfaceDefs.h @@ -179,14 +179,24 @@ struct scroll_bar_info { enum alignment { B_ALIGN_LEFT, B_ALIGN_RIGHT, - B_ALIGN_CENTER + B_ALIGN_CENTER, + + B_ALIGN_HORIZONTAL_CENTER = B_ALIGN_CENTER, + + B_ALIGN_HORIZONTAL_UNSET = -1L, + B_ALIGN_USE_FULL_WIDTH = -2L, }; enum vertical_alignment { B_ALIGN_TOP = 0x10L, B_ALIGN_MIDDLE = 0x20, B_ALIGN_BOTTOM = 0x30, - B_ALIGN_NO_VERTICAL = -1L + + B_ALIGN_VERTICAL_CENTER = B_ALIGN_MIDDLE, + + B_ALIGN_VERTICAL_UNSET = -1L, + B_ALIGN_NO_VERTICAL = B_ALIGN_VERTICAL_UNSET, + B_ALIGN_USE_FULL_HEIGHT = -2L, }; /*----------------------------------------------------------------*/ diff --git a/headers/os/interface/Layout.h b/headers/os/interface/Layout.h new file mode 100644 index 0000000000..66f580afd5 --- /dev/null +++ b/headers/os/interface/Layout.h @@ -0,0 +1,67 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _LAYOUT_H +#define _LAYOUT_H + +#include +#include +#include + +class BLayoutItem; +class BView; + + +class BLayout { +public: + BLayout(); + virtual ~BLayout(); + + BView* View() const; + + virtual BLayoutItem* AddView(BView* child); + virtual BLayoutItem* AddView(int32 index, BView* child); + + virtual bool AddItem(BLayoutItem* item); + virtual bool AddItem(int32 index, BLayoutItem* item); + + virtual bool RemoveView(BView* child); + virtual bool RemoveItem(BLayoutItem* item); + virtual BLayoutItem* RemoveItem(int32 index); + + BLayoutItem* ItemAt(int32 index) const; + int32 CountItems() const; + int32 IndexOfItem(BLayoutItem* item) const; + int32 IndexOfView(BView* child) const; + + virtual BSize MinSize() = 0; + virtual BSize MaxSize() = 0; + virtual BSize PreferredSize() = 0; + virtual BAlignment Alignment() = 0; + + virtual bool HasHeightForWidth() = 0; + virtual void GetHeightForWidth(float width, float* min, + float* max, float* preferred) = 0; + + virtual void InvalidateLayout(); + + virtual void LayoutView() = 0; + +protected: +// TODO: Since memory allocations can fail, we should return a bool and +// undo the addition, if false. + virtual void ItemAdded(BLayoutItem* item); + virtual void ItemRemoved(BLayoutItem* item); + + +private: + friend class BView; + + void SetView(BView* view); + + BView* fView; + BList fItems; +}; + +#endif // _LAYOUT_H diff --git a/headers/os/interface/LayoutContext.h b/headers/os/interface/LayoutContext.h new file mode 100644 index 0000000000..8470a3baf5 --- /dev/null +++ b/headers/os/interface/LayoutContext.h @@ -0,0 +1,35 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _LAYOUT_CONTEXT_H +#define _LAYOUT_CONTEXT_H + +#include + +class BLayoutContext; + + +class BLayoutContextListener { +public: + BLayoutContextListener(); + virtual ~BLayoutContextListener(); + + virtual void LayoutContextLeft(BLayoutContext* context) = 0; +}; + + +class BLayoutContext { +public: + BLayoutContext(); + ~BLayoutContext(); + + void AddListener(BLayoutContextListener* listener); + void RemoveListener( + BLayoutContextListener* listener); + +private: + BList fListeners; +}; + +#endif // _LAYOUT_CONTEXT_H diff --git a/headers/os/interface/LayoutItem.h b/headers/os/interface/LayoutItem.h new file mode 100644 index 0000000000..fc838d1b63 --- /dev/null +++ b/headers/os/interface/LayoutItem.h @@ -0,0 +1,60 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _LAYOUT_ITEM_H +#define _LAYOUT_ITEM_H + +#include +#include +#include + +class BLayout; +class BView; + +class BLayoutItem { +public: + BLayoutItem(); + virtual ~BLayoutItem(); + + BLayout* Layout() const; + + virtual BSize MinSize() = 0; + virtual BSize MaxSize() = 0; + virtual BSize PreferredSize() = 0; + virtual BAlignment Alignment() = 0; + + virtual void SetExplicitMinSize(BSize size) = 0; + virtual void SetExplicitMaxSize(BSize size) = 0; + virtual void SetExplicitPreferredSize(BSize size) = 0; + virtual void SetExplicitAlignment(BAlignment alignment) = 0; + + virtual bool IsVisible() = 0; + virtual void SetVisible(bool visible) = 0; + + virtual BRect Frame() = 0; + virtual void SetFrame(BRect frame) = 0; + + virtual bool HasHeightForWidth(); + virtual void GetHeightForWidth(float width, float* min, + float* max, float* preferred); + + virtual BView* View(); + + virtual void InvalidateLayout(); + + void* LayoutData() const; + void SetLayoutData(void* data); + + void AlignInFrame(BRect frame); + +private: + friend class BLayout; + + void SetLayout(BLayout* layout); + + BLayout* fLayout; + void* fLayoutData; +}; + +#endif // _LAYOUT_ITEM_H diff --git a/headers/os/interface/LayoutUtils.h b/headers/os/interface/LayoutUtils.h new file mode 100644 index 0000000000..56bd4b87c2 --- /dev/null +++ b/headers/os/interface/LayoutUtils.h @@ -0,0 +1,35 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _LAYOUT_UTILS_H +#define _LAYOUT_UTILS_H + +#include +#include +#include + +class BView; + +class BLayoutUtils { +public: +// static float AddSizesFloat(float a, float b); +// static float AddSizesFloat(float a, float b, float c); + static float AddDistances(float a, float b); + static float AddDistances(float a, float b, float c); + static int32 AddSizesInt32(int32 a, int32 b); + static int32 AddSizesInt32(int32 a, int32 b, int32 c); +// static float SubtractSizesFloat(float a, float b); + static int32 SubtractSizesInt32(int32 a, int32 b); + static float SubtractDistances(float a, float b); + + static BSize ComposeSize(BSize size, BSize layoutSize); + static BAlignment ComposeAlignment(BAlignment alignment, + BAlignment layoutAlignment); + + static BRect AlignInFrame(BRect frame, BSize maxSize, + BAlignment alignment); + static void AlignInFrame(BView* view, BRect frame); +}; + +#endif // _LAYOUT_UTILS_H diff --git a/headers/os/interface/ListView.h b/headers/os/interface/ListView.h index b1ddeeb282..3ab9d01c91 100644 --- a/headers/os/interface/ListView.h +++ b/headers/os/interface/ListView.h @@ -126,6 +126,9 @@ class BListView : public BView, public BInvoker virtual void AllAttached(); virtual void AllDetached(); + virtual BSize MinSize(); + virtual BSize PreferredSize(); + protected: enum MiscCode { B_NO_OP, B_REPLACE_OP, B_MOVE_OP, B_SWAP_OP }; union MiscData { diff --git a/headers/os/interface/MenuBar.h b/headers/os/interface/MenuBar.h index 619faa8b49..e49f7ae3b9 100644 --- a/headers/os/interface/MenuBar.h +++ b/headers/os/interface/MenuBar.h @@ -36,82 +36,86 @@ class BMenuField; class BMenuBar : public BMenu { public: - BMenuBar( BRect frame, - const char *title, - uint32 resizeMask = - B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, - menu_layout layout = B_ITEMS_IN_ROW, - bool resizeToFit = true); - BMenuBar(BMessage *data); -virtual ~BMenuBar(); -static BArchivable *Instantiate(BMessage *data); -virtual status_t Archive(BMessage *data, bool deep = true) const; + BMenuBar( BRect frame, + const char *title, + uint32 resizeMask = + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, + menu_layout layout = B_ITEMS_IN_ROW, + bool resizeToFit = true); + BMenuBar(BMessage *data); + virtual ~BMenuBar(); + static BArchivable *Instantiate(BMessage *data); + virtual status_t Archive(BMessage *data, bool deep = true) const; -virtual void SetBorder(menu_bar_border border); - menu_bar_border Border() const; -virtual void Draw(BRect updateRect); -virtual void AttachedToWindow(); -virtual void DetachedFromWindow(); -virtual void MessageReceived(BMessage *msg); -virtual void MouseDown(BPoint where); -virtual void WindowActivated(bool state); -virtual void MouseUp(BPoint where); -virtual void FrameMoved(BPoint new_position); -virtual void FrameResized(float new_width, float new_height); + virtual void SetBorder(menu_bar_border border); + menu_bar_border Border() const; + virtual void Draw(BRect updateRect); + virtual void AttachedToWindow(); + virtual void DetachedFromWindow(); + virtual void MessageReceived(BMessage *msg); + virtual void MouseDown(BPoint where); + virtual void WindowActivated(bool state); + virtual void MouseUp(BPoint where); + virtual void FrameMoved(BPoint new_position); + virtual void FrameResized(float new_width, float new_height); -virtual void Show(); -virtual void Hide(); + virtual void Show(); + virtual void Hide(); -virtual BHandler *ResolveSpecifier(BMessage *msg, - int32 index, - BMessage *specifier, - int32 form, - const char *property); -virtual status_t GetSupportedSuites(BMessage *data); + virtual BHandler *ResolveSpecifier(BMessage *msg, + int32 index, + BMessage *specifier, + int32 form, + const char *property); + virtual status_t GetSupportedSuites(BMessage *data); -virtual void ResizeToPreferred(); -virtual void GetPreferredSize(float *width, float *height); -virtual void MakeFocus(bool state = true); -virtual void AllAttached(); -virtual void AllDetached(); + virtual void ResizeToPreferred(); + virtual void GetPreferredSize(float *width, float *height); + virtual void MakeFocus(bool state = true); + virtual void AllAttached(); + virtual void AllDetached(); + + // layout related + virtual BSize MaxSize(); + /*----- Private or reserved -----------------------------------------*/ -virtual status_t Perform(perform_code d, void *arg); + virtual status_t Perform(perform_code d, void *arg); private: -friend class BWindow; -friend class BMenuItem; -friend class BMenuField; -friend class BMenu; + friend class BWindow; + friend class BMenuItem; + friend class BMenuField; + friend class BMenu; -virtual void _ReservedMenuBar1(); -virtual void _ReservedMenuBar2(); -virtual void _ReservedMenuBar3(); -virtual void _ReservedMenuBar4(); + virtual void _ReservedMenuBar1(); + virtual void _ReservedMenuBar2(); + virtual void _ReservedMenuBar3(); + virtual void _ReservedMenuBar4(); - BMenuBar &operator=(const BMenuBar &); + BMenuBar &operator=(const BMenuBar &); - void StartMenuBar( int32 menuIndex, - bool sticky = true, - bool show_menu = false, - BRect *special_rect = NULL); -static long TrackTask(void *arg); - BMenuItem *Track( int32 *action, - int32 startIndex = -1, - bool showMenu = false); - void StealFocus(); - void RestoreFocus(); - void InitData(menu_layout layout); + void StartMenuBar( int32 menuIndex, + bool sticky = true, + bool show_menu = false, + BRect *special_rect = NULL); + static long TrackTask(void *arg); + BMenuItem *Track( int32 *action, + int32 startIndex = -1, + bool showMenu = false); + void StealFocus(); + void RestoreFocus(); + void InitData(menu_layout layout); - menu_bar_border fBorder; - thread_id fTrackingPID; - int32 fPrevFocusToken; - sem_id fMenuSem; - BRect* fLastBounds; - uint32 _reserved[2]; // was 3 + menu_bar_border fBorder; + thread_id fTrackingPID; + int32 fPrevFocusToken; + sem_id fMenuSem; + BRect* fLastBounds; + uint32 _reserved[2]; // was 3 - bool fTracking; + bool fTracking; }; /*-------------------------------------------------------------*/ diff --git a/headers/os/interface/MenuField.h b/headers/os/interface/MenuField.h index 505a44347c..ad9d5473e6 100644 --- a/headers/os/interface/MenuField.h +++ b/headers/os/interface/MenuField.h @@ -1,13 +1,7 @@ -/******************************************************************************* -/ -/ File: MenuField.h -/ -/ Description: BMenuField displays a labeled pop-up menu. -/ -/ Copyright 1994-98, Be Incorporated, All Rights Reserved -/ -*******************************************************************************/ - +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ #ifndef _MENU_FIELD_H #define _MENU_FIELD_H @@ -18,108 +12,118 @@ class BMenuBar; -/*----------------------------------------------------------------*/ -/*----- BMenuField class -----------------------------------------*/ +class BMenuField : public BView { + public: + BMenuField(BRect frame, const char* name, + const char* label, BMenu* menu, + uint32 resize = B_FOLLOW_LEFT|B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + BMenuField(BRect frame, const char* name, + const char* label, BMenu* menu, + bool fixed_size, + uint32 resize = B_FOLLOW_LEFT|B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + BMenuField(const char* name, + const char* label, BMenu* menu, + BMessage* message, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + BMenuField(const char* label, + BMenu* menu, BMessage* message); + BMenuField(BMessage* data); + virtual ~BMenuField(); -class BMenuField : public BView -{ -public: - BMenuField( BRect frame, - const char *name, - const char *label, - BMenu *menu, - uint32 resize = B_FOLLOW_LEFT|B_FOLLOW_TOP, - uint32 flags = B_WILL_DRAW | B_NAVIGABLE); - BMenuField( BRect frame, - const char *name, - const char *label, - BMenu *menu, - bool fixed_size, - uint32 resize = B_FOLLOW_LEFT|B_FOLLOW_TOP, - uint32 flags = B_WILL_DRAW | B_NAVIGABLE); - BMenuField(BMessage *data); -virtual ~BMenuField(); -static BArchivable *Instantiate(BMessage *data); -virtual status_t Archive(BMessage *data, bool deep = true) const; + static BArchivable* Instantiate(BMessage* archive); + virtual status_t Archive(BMessage* archive, bool deep = true) const; -virtual void Draw(BRect update); -virtual void AttachedToWindow(); -virtual void AllAttached(); -virtual void MouseDown(BPoint where); -virtual void KeyDown(const char *bytes, int32 numBytes); -virtual void MakeFocus(bool state); -virtual void MessageReceived(BMessage *msg); -virtual void WindowActivated(bool state); -virtual void MouseUp(BPoint pt); -virtual void MouseMoved(BPoint pt, uint32 code, const BMessage *msg); -virtual void DetachedFromWindow(); -virtual void AllDetached(); -virtual void FrameMoved(BPoint new_position); -virtual void FrameResized(float new_width, float new_height); + virtual void Draw(BRect update); + virtual void AttachedToWindow(); + virtual void AllAttached(); + virtual void MouseDown(BPoint where); + virtual void KeyDown(const char* bytes, int32 numBytes); + virtual void MakeFocus(bool state); + virtual void MessageReceived(BMessage* message); + virtual void WindowActivated(bool state); + virtual void MouseUp(BPoint pt); + virtual void MouseMoved(BPoint pt, uint32 code, + const BMessage* dragMessage); + virtual void DetachedFromWindow(); + virtual void AllDetached(); + virtual void FrameMoved(BPoint new_position); + virtual void FrameResized(float new_width, float new_height); - BMenu *Menu() const; - BMenuBar *MenuBar() const; - BMenuItem *MenuItem() const; + BMenu* Menu() const; + BMenuBar* MenuBar() const; + BMenuItem* MenuItem() const; -virtual void SetLabel(const char *label); - const char *Label() const; + virtual void SetLabel(const char* label); + const char* Label() const; -virtual void SetEnabled(bool on); - bool IsEnabled() const; + virtual void SetEnabled(bool on); + bool IsEnabled() const; -virtual void SetAlignment(alignment label); - alignment Alignment() const; -virtual void SetDivider(float dividing_line); - float Divider() const; + virtual void SetAlignment(alignment label); + alignment Alignment() const; + virtual void SetDivider(float dividing_line); + float Divider() const; - void ShowPopUpMarker(); - void HidePopUpMarker(); + void ShowPopUpMarker(); + void HidePopUpMarker(); -virtual BHandler *ResolveSpecifier(BMessage *msg, - int32 index, - BMessage *specifier, - int32 form, - const char *property); -virtual status_t GetSupportedSuites(BMessage *data); + virtual BHandler* ResolveSpecifier(BMessage* message, + int32 index, BMessage* specifier, + int32 form, const char* property); + virtual status_t GetSupportedSuites(BMessage* data); -virtual void ResizeToPreferred(); -virtual void GetPreferredSize(float *width, float *height); + virtual void ResizeToPreferred(); + virtual void GetPreferredSize(float* width, float* height); + + BLayoutItem* CreateLabelLayoutItem(); + BLayoutItem* CreateMenuBarLayoutItem(); + + + /*----- Private or reserved -----------------------------------------*/ + virtual status_t Perform(perform_code d, void* arg); + + private: + class LabelLayoutItem; + class MenuBarLayoutItem; + + friend class _BMCMenuBar_; + friend class LabelLayoutItem; + friend class MenuBarLayoutItem; + + virtual void _ReservedMenuField1(); + virtual void _ReservedMenuField2(); + virtual void _ReservedMenuField3(); + + BMenuField &operator=(const BMenuField&); -/*----- Private or reserved -----------------------------------------*/ -virtual status_t Perform(perform_code d, void *arg); + void InitObject(const char* label); + void InitObject2(); + void DrawLabel(BRect bounds, BRect update); + static void InitMenu(BMenu* menu); + static long MenuTask(void* arg); + void _UpdateFrame(); + void _InitMenuBar(BMenu* menu, + BRect frame, bool fixedSize); -private: -friend class _BMCMenuBar_; + char* fLabel; + BMenu* fMenu; + BMenuBar* fMenuBar; + alignment fAlign; + float fDivider; + float fStringWidth; + bool fEnabled; + bool fSelected; + bool fTransition; + bool fFixedSizeMB; + thread_id fMenuTaskID; -virtual void _ReservedMenuField1(); -virtual void _ReservedMenuField2(); -virtual void _ReservedMenuField3(); + BLayoutItem* fLabelLayoutItem; + BLayoutItem* fMenuBarLayoutItem; - BMenuField &operator=(const BMenuField &); - - - void InitObject(const char *label); - void InitObject2(); - void DrawLabel(BRect bounds, BRect update); -static void InitMenu(BMenu *menu); -static long MenuTask(void *arg); - - char *fLabel; - BMenu *fMenu; - BMenuBar *fMenuBar; - alignment fAlign; - float fDivider; - float fStringWidth; - bool fEnabled; - bool fSelected; - bool fTransition; - bool fFixedSizeMB; - thread_id fMenuTaskID; - uint32 _reserved[3]; + uint32 _reserved[1]; }; -/*-------------------------------------------------------------*/ -/*-------------------------------------------------------------*/ - -#endif /* _MENU_FIELD_H */ +#endif // _MENU_FIELD_H diff --git a/headers/os/interface/RadioButton.h b/headers/os/interface/RadioButton.h index 13cd145e83..6611c5d586 100644 --- a/headers/os/interface/RadioButton.h +++ b/headers/os/interface/RadioButton.h @@ -54,6 +54,12 @@ public: BMessage *message, uint32 resizMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + BRadioButton(const char *name, + const char *label, + BMessage *message, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + BRadioButton(const char *label, + BMessage *message); BRadioButton(BMessage *archive); virtual ~BRadioButton(); @@ -91,6 +97,9 @@ virtual status_t GetSupportedSuites(BMessage *message); virtual status_t Perform(perform_code d, void *arg); +virtual BSize MaxSize(); + + private: friend status_t _init_interface_kit_(); diff --git a/headers/os/interface/ScrollView.h b/headers/os/interface/ScrollView.h index 26ae19e510..4d414e6d27 100644 --- a/headers/os/interface/ScrollView.h +++ b/headers/os/interface/ScrollView.h @@ -60,6 +60,9 @@ class BScrollView : public BView { virtual void MakeFocus(bool state = true); virtual status_t GetSupportedSuites(BMessage *data); + virtual BSize MinSize(); + virtual BSize PreferredSize(); + // private or reserved methods are following virtual status_t Perform(perform_code d, void *arg); diff --git a/headers/os/interface/Size.h b/headers/os/interface/Size.h new file mode 100644 index 0000000000..6697c4bab4 --- /dev/null +++ b/headers/os/interface/Size.h @@ -0,0 +1,158 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _SIZE_H +#define _SIZE_H + +#include + +#include +#include + +enum { + B_SIZE_UNSET = -1, + B_SIZE_UNLIMITED = 1024 * 1024 * 1024, +}; + +class BSize { +public: + float width; + float height; + + inline BSize(); + inline BSize(const BSize& other); + inline BSize(float width, float height); + inline BSize(const BRect& rect); + + inline float Width() const; + inline float Height() const; + + inline void SetWidth(float width); + inline void SetHeight(float height); + + inline int32 IntegerWidth() const; + inline int32 IntegerHeight() const; + + inline bool IsWidthSet() const; + inline bool IsHeightSet() const; + + inline bool operator==(const BSize& other) const; + inline bool operator!=(const BSize& other) const; + + inline BSize& operator=(const BSize& other); +}; + + +// constructor +inline +BSize::BSize() + : width(B_SIZE_UNSET), + height(B_SIZE_UNSET) +{ +} + +// copy constructor +inline +BSize::BSize(const BSize& other) + : width(other.width), + height(other.height) +{ +} + +// constructor +inline +BSize::BSize(float width, float height) + : width(width), + height(height) +{ +} + +// constructor +inline +BSize::BSize(const BRect& rect) + : width(rect.Width()), + height(rect.Height()) +{ +} + +// Width +inline float +BSize::Width() const +{ + return width; +} + +// Height +inline float +BSize::Height() const +{ + return height; +} + +// SetWidth +inline void +BSize::SetWidth(float width) +{ + this->width = width; +} + +// SetHeight +inline void +BSize::SetHeight(float height) +{ + this->height = height; +} + +// IntegerWidth +inline int32 +BSize::IntegerWidth() const +{ + return (int32)width; +} + +// IntegerHeight +inline int32 +BSize::IntegerHeight() const +{ + return (int32)height; +} + +// IsWidthSet +inline bool +BSize::IsWidthSet() const +{ + return width != B_SIZE_UNSET; +} + +// IsHeightSet +inline bool +BSize::IsHeightSet() const +{ + return height != B_SIZE_UNSET; +} + +// == +inline bool +BSize::operator==(const BSize& other) const +{ + return (width == other.width && height == other.height); +} + +// != +inline bool +BSize::operator!=(const BSize& other) const +{ + return !(*this == other); +} + +// = +inline BSize& +BSize::operator=(const BSize& other) +{ + width = other.width; + height = other.height; + return *this; +} + +#endif // _SIZE_H diff --git a/headers/os/interface/SpaceLayoutItem.h b/headers/os/interface/SpaceLayoutItem.h new file mode 100644 index 0000000000..2c5234d805 --- /dev/null +++ b/headers/os/interface/SpaceLayoutItem.h @@ -0,0 +1,46 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _SPACE_LAYOUT_ITEM_H +#define _SPACE_LAYOUT_ITEM_H + +#include + + +class BSpaceLayoutItem : public BLayoutItem { +public: + BSpaceLayoutItem(BSize minSize, BSize maxSize, + BSize preferredSize, BAlignment alignment); + virtual ~BSpaceLayoutItem(); + + static BSpaceLayoutItem* CreateGlue(); + static BSpaceLayoutItem* CreateHorizontalStrut(float width); + static BSpaceLayoutItem* CreateVerticalStrut(float height); + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + virtual BAlignment Alignment(); + + virtual void SetExplicitMinSize(BSize size); + virtual void SetExplicitMaxSize(BSize size); + virtual void SetExplicitPreferredSize(BSize size); + virtual void SetExplicitAlignment(BAlignment alignment); + + virtual bool IsVisible(); + virtual void SetVisible(bool visible); + + virtual BRect Frame(); + virtual void SetFrame(BRect frame); + +private: + BRect fFrame; + BSize fMinSize; + BSize fMaxSize; + BSize fPreferredSize; + BAlignment fAlignment; + bool fVisible; +}; + +#endif // _SPACE_LAYOUT_ITEM_H diff --git a/headers/os/interface/SplitLayoutBuilder.h b/headers/os/interface/SplitLayoutBuilder.h new file mode 100644 index 0000000000..d88e33d44c --- /dev/null +++ b/headers/os/interface/SplitLayoutBuilder.h @@ -0,0 +1,33 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _SPLIT_LAYOUT_BUILDER_H +#define _SPLIT_LAYOUT_BUILDER_H + +#include + +class BSplitLayoutBuilder { +public: + BSplitLayoutBuilder( + enum orientation orientation = B_HORIZONTAL, + float spacing = 0.0f); + BSplitLayoutBuilder(BSplitView* view); + + BSplitView* SplitView() const; + BSplitLayoutBuilder& GetSplitView(BSplitView** view); + + BSplitLayoutBuilder& Add(BView* view); + BSplitLayoutBuilder& Add(BView* view, float weight); + BSplitLayoutBuilder& Add(BLayoutItem* item); + BSplitLayoutBuilder& Add(BLayoutItem* item, float weight); + + BSplitLayoutBuilder& SetCollapsible(bool collapsible); + + operator BSplitView*(); + +private: + BSplitView* fView; +}; + +#endif // _SPLIT_LAYOUT_BUILDER_H diff --git a/headers/os/interface/SplitView.h b/headers/os/interface/SplitView.h new file mode 100644 index 0000000000..5d29ffb83b --- /dev/null +++ b/headers/os/interface/SplitView.h @@ -0,0 +1,69 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _SPLIT_VIEW_H +#define _SPLIT_VIEW_H + +#include + +class BSplitLayout; + + +class BSplitView : public BView { +public: + BSplitView( + enum orientation orientation = B_HORIZONTAL, + float spacing = 0.0f); + virtual ~BSplitView(); + + float Spacing() const; + void SetSpacing(float spacing); + + orientation Orientation() const; + void SetOrientation(enum orientation orientation); + + float SplitterSize() const; + void SetSplitterSize(float size); + + + void SetCollapsible(bool collapsible); + void SetCollapsible(int32 index, bool collapsible); + void SetCollapsible(int32 first, int32 last, + bool collapsible); + +// void AddChild(BView* child); + void AddChild(BView* child, BView* sibling = NULL); + bool AddChild(BView* child, float weight); + bool AddChild(int32 index, BView* child, + float weight); + + bool AddChild(BLayoutItem* child); + bool AddChild(BLayoutItem* child, float weight); + bool AddChild(int32 index, BLayoutItem* child, + float weight); + + virtual void Draw(BRect updateRect); + virtual void MouseDown(BPoint where); + virtual void MouseUp(BPoint where); + virtual void MouseMoved(BPoint where, uint32 transit, + const BMessage* message); + + + virtual void SetLayout(BLayout* layout); + // overridden to avoid use + +protected: + virtual void DrawSplitter(BRect frame, + enum orientation orientation, bool pressed); + +private: + static void _DrawDefaultSplitter(BView* view, BRect frame, + enum orientation orientation, bool pressed); + +private: + BSplitLayout* fSplitLayout; +}; + + +#endif // _SPLIT_VIEW_H diff --git a/headers/os/interface/StringView.h b/headers/os/interface/StringView.h index c32a0cef13..a2d8933c92 100644 --- a/headers/os/interface/StringView.h +++ b/headers/os/interface/StringView.h @@ -53,6 +53,8 @@ class BStringView : public BView{ virtual void AllDetached(); virtual status_t GetSupportedSuites(BMessage* data); + virtual BSize MaxSize(); + private: virtual status_t Perform(perform_code d, void* arg); virtual void _ReservedStringView1(); diff --git a/headers/os/interface/TextControl.h b/headers/os/interface/TextControl.h index c68f6699a9..86755d149c 100644 --- a/headers/os/interface/TextControl.h +++ b/headers/os/interface/TextControl.h @@ -9,6 +9,7 @@ #include #include +class BLayoutItem; class _BTextInput_; @@ -19,6 +20,13 @@ class BTextControl : public BControl { BMessage* message, uint32 resizeMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + BTextControl(const char* name, + const char* label, const char* initialText, + BMessage* message, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + BTextControl(const char* label, + const char* initialText, + BMessage* message); virtual ~BTextControl(); BTextControl(BMessage* archive); @@ -68,8 +76,16 @@ class BTextControl : public BControl { virtual status_t GetSupportedSuites(BMessage* data); virtual void SetFlags(uint32 flags); + BLayoutItem* CreateLabelLayoutItem(); + BLayoutItem* CreateTextViewLayoutItem(); + private: + class LabelLayoutItem; + class TextViewLayoutItem; + friend class _BTextInput_; + friend class LabelLayoutItem; + friend class TextViewLayoutItem; virtual status_t Perform(perform_code d, void* arg); @@ -84,6 +100,8 @@ class BTextControl : public BControl { void _UpdateTextViewColors(bool enabled); void _InitData(const char* label, const char* initialText, BMessage* archive = NULL); + void _ValidateLayout(); + void _UpdateFrame(); private: _BTextInput_* fText; @@ -93,8 +111,10 @@ class BTextControl : public BControl { float fDivider; float fPreviousWidth; float fPreviousHeight; + BLayoutItem* fLabelLayoutItem; + BLayoutItem* fTextViewLayoutItem; - uint32 _reserved[6]; + uint32 _reserved[4]; bool fClean; bool fSkipSetFlags; diff --git a/headers/os/interface/TwoDimensionalLayout.h b/headers/os/interface/TwoDimensionalLayout.h new file mode 100644 index 0000000000..75c963996d --- /dev/null +++ b/headers/os/interface/TwoDimensionalLayout.h @@ -0,0 +1,93 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _TWO_DIMENSIONAL_LAYOUT_H +#define _TWO_DIMENSIONAL_LAYOUT_H + +#include + +class BLayoutContext; + + +class BTwoDimensionalLayout : public BLayout { +public: + BTwoDimensionalLayout(); + virtual ~BTwoDimensionalLayout(); + + void SetInsets(float left, float top, float right, + float bottom); + void GetInsets(float* left, float* top, float* right, + float* bottom); + + void AlignLayoutWith(BTwoDimensionalLayout* other, + enum orientation orientation); + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + virtual BAlignment Alignment(); + + virtual bool HasHeightForWidth(); + virtual void GetHeightForWidth(float width, float* min, + float* max, float* preferred); + + virtual void InvalidateLayout(); + + virtual void LayoutView(); + +protected: + struct ColumnRowConstraints { + float weight; + float min; + float max; + }; + + struct Dimensions { + int32 x; + int32 y; + int32 width; + int32 height; + }; + + BSize AddInsets(BSize size); + void AddInsets(float* minHeight, float* maxHeight, + float* preferredHeight); + BSize SubtractInsets(BSize size); + + virtual void PrepareItems(enum orientation orientation); + virtual bool HasMultiColumnItems(); + virtual bool HasMultiRowItems(); + + virtual int32 InternalCountColumns() = 0; + virtual int32 InternalCountRows() = 0; + virtual void GetColumnRowConstraints( + enum orientation orientation, + int32 index, + ColumnRowConstraints* constraints) = 0; + virtual void GetItemDimensions(BLayoutItem* item, + Dimensions* dimensions) = 0; + +private: + class CompoundLayouter; + class LocalLayouter; + class VerticalCompoundLayouter; + + friend class LocalLayouter; + + void _ValidateMinMax(); + BLayoutContext* _CurrentLayoutContext(); + +protected: + float fLeftInset; + float fRightInset; + float fTopInset; + float fBottomInset; + float fHSpacing; + float fVSpacing; + +private: + LocalLayouter* fLocalLayouter; +}; + +#endif // _TWO_DIMENSIONAL_LAYOUT_H diff --git a/headers/os/interface/View.h b/headers/os/interface/View.h index 1a014bc527..e7c8a62333 100644 --- a/headers/os/interface/View.h +++ b/headers/os/interface/View.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005, Haiku. + * Copyright 2001-2006, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -9,11 +9,13 @@ #define _VIEW_H +#include #include #include #include #include #include +#include // mouse button @@ -74,6 +76,8 @@ const uint32 B_SUBPIXEL_PRECISE = 0x01000000UL; /* 24 */ const uint32 B_DRAW_ON_CHILDREN = 0x00800000UL; /* 23 */ const uint32 B_INPUT_METHOD_AWARE = 0x00400000UL; /* 23 */ const uint32 _B_RESERVED7_ = 0x00200000UL; /* 22 */ +const uint32 B_SUPPORTS_LAYOUT = 0x00100000UL; /* 21 */ +const uint32 B_INVALIDATE_AFTER_LAYOUT = 0x00080000UL; /* 20 */ #define _RESIZE_MASK_ ~(B_FULL_UPDATE_ON_RESIZE | _B_RESERVED1_ | B_WILL_DRAW \ | B_PULSE_NEEDED | B_NAVIGABLE_JUMP | B_FRAME_EVENTS | B_NAVIGABLE \ @@ -104,6 +108,9 @@ inline uint32 _rule_(uint32 r1, uint32 r2, uint32 r3, uint32 r4) class BBitmap; class BCursor; +class BLayout; +class BLayoutContext; +class BLayoutItem; class BMessage; class BPicture; class BPolygon; @@ -125,6 +132,8 @@ namespace BPrivate { class BView : public BHandler { public: + BView(const char* name, uint32 flags, + BLayout* layout = NULL); BView(BRect frame, const char* name, uint32 resizeMask, uint32 flags); virtual ~BView(); @@ -141,6 +150,7 @@ public: virtual void MessageReceived(BMessage* msg); void AddChild(BView* child, BView* before = NULL); + bool AddChild(BLayoutItem* child); bool RemoveChild(BView* child); int32 CountChildren() const; BView* ChildAt(int32 index) const; @@ -490,31 +500,64 @@ public: bool IsPrinting() const; void SetScale(float scale) const; + float Scale() const; + // new for Haiku -// Private or reserved --------------------------------------------------------- virtual status_t Perform(perform_code d, void* arg); virtual void DrawAfterChildren(BRect r); - float Scale() const; - // new for Haiku + + // layout related + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + virtual BAlignment Alignment(); + + void SetExplicitMinSize(BSize size); + void SetExplicitMaxSize(BSize size); + void SetExplicitPreferredSize(BSize size); + void SetExplicitAlignment(BAlignment alignment); + + BSize ExplicitMinSize() const; + BSize ExplicitMaxSize() const; + BSize ExplicitPreferredSize() const; + BAlignment ExplicitAlignment() const; + + virtual bool HasHeightForWidth(); + virtual void GetHeightForWidth(float width, float* min, + float* max, float* preferred); + + virtual void SetLayout(BLayout* layout); + BLayout* GetLayout() const; + + void InvalidateLayout(bool descendants = false); + void EnableLayoutInvalidation(); + void DisableLayoutInvalidation(); + + BLayoutContext* LayoutContext() const; + + void Layout(bool force); + void Relayout(); + +protected: + virtual void DoLayout(); private: - friend class BScrollBar; - friend class BWindow; + void _Layout(bool force, BLayoutContext* context); + +private: + struct LayoutData; + friend class BBitmap; + friend class BLayout; friend class BPrintJob; + friend class BScrollBar; friend class BShelf; friend class BTabView; + friend class BWindow; - virtual void _ReservedView2(); - virtual void _ReservedView3(); - virtual void _ReservedView4(); - virtual void _ReservedView5(); - virtual void _ReservedView6(); - virtual void _ReservedView7(); - virtual void _ReservedView8(); - virtual void _ReservedView9(); virtual void _ReservedView10(); virtual void _ReservedView11(); virtual void _ReservedView12(); @@ -571,6 +614,9 @@ private: bool _AddChildToList(BView* child, BView* before = NULL); bool _RemoveChildFromList(BView* child); + bool _AddChild(BView *child, BView *before); + bool _RemoveSelf(); + // Debugging methods void PrintToStream(); void PrintTree(); @@ -601,7 +647,10 @@ private: BShelf* fShelf; uint32 fEventMask; uint32 fEventOptions; - uint32 _reserved[9]; + + LayoutData* fLayoutData; + + uint32 _reserved[8]; }; diff --git a/headers/os/interface/Window.h b/headers/os/interface/Window.h index 9f65bac427..c497fc8d13 100644 --- a/headers/os/interface/Window.h +++ b/headers/os/interface/Window.h @@ -81,6 +81,7 @@ enum { B_ASYNCHRONOUS_CONTROLS = 0x00080000, B_QUIT_ON_WINDOW_CLOSE = 0x00100000, B_SAME_POSITION_IN_ALL_WORKSPACES = 0x00200000, + B_AUTO_UPDATE_SIZE_LIMITS = 0x00400000, }; #define B_CURRENT_WORKSPACE 0 @@ -257,6 +258,11 @@ public: virtual bool QuitRequested(); virtual thread_id Run(); + virtual void SetLayout(BLayout* layout); + BLayout* GetLayout() const; + + void InvalidateLayout(bool descendants = false); + private: typedef BLooper inherited; struct unpack_cookie; diff --git a/headers/os/support/List.h b/headers/os/support/List.h index 52affec9e5..714459a13c 100644 --- a/headers/os/support/List.h +++ b/headers/os/support/List.h @@ -43,8 +43,8 @@ public: /* Adding and removing items. */ bool AddItem(void *item, int32 index); bool AddItem(void *item); - bool AddList(BList *list, int32 index); - bool AddList(BList *list); + bool AddList(const BList *list, int32 index); + bool AddList(const BList *list); bool RemoveItem(void *item); void *RemoveItem(int32 index); bool RemoveItems(int32 index, int32 count); diff --git a/headers/private/storage/mime/database_support.h b/headers/private/storage/mime/database_support.h index 557b8ab15a..3b81f93477 100644 --- a/headers/private/storage/mime/database_support.h +++ b/headers/private/storage/mime/database_support.h @@ -28,6 +28,7 @@ extern const std::string kApplicationDatabaseDir; // Attribute Prefixes extern const char *kMiniIconAttrPrefix; extern const char *kLargeIconAttrPrefix; +extern const char *kIconAttrPrefix; // Attribute names extern const char *kFileTypeAttr; @@ -39,6 +40,7 @@ extern const char *kLongDescriptionAttr; extern const char *kFileExtensionsAttr; extern const char *kMiniIconAttr; extern const char *kLargeIconAttr; +extern const char *kIconAttr; extern const char *kPreferredAppAttr; extern const char *kSnifferRuleAttr; extern const char *kSupportedTypesAttr; @@ -53,6 +55,7 @@ extern const int32 kLongDescriptionType; extern const int32 kFileExtensionsType; extern const int32 kMiniIconType; extern const int32 kLargeIconType; +extern const int32 kIconType; extern const int32 kPreferredAppType; extern const int32 kSnifferRuleType; extern const int32 kSupportedTypesType; diff --git a/src/kits/Jamfile b/src/kits/Jamfile index 193595fe2e..ffb0df60e8 100644 --- a/src/kits/Jamfile +++ b/src/kits/Jamfile @@ -33,6 +33,11 @@ SharedLibrary libbe.so : storage_diskdevice_kit.o support_kit.o + libqoca.so + + libicon.a + libagg.a + libroot.so # make sure it links against our libroot.so $(TARGET_LIBSTDC++) ; @@ -64,6 +69,11 @@ SharedLibrary libbe_haiku.so : storage_kit.o support_kit.o + libqoca.so + + libicon.a + libagg.a + libbeadapter.so net $(TARGET_LIBSTDC++) diff --git a/src/kits/app/DesktopLink.cpp b/src/kits/app/DesktopLink.cpp index f828cafefe..29205fa73d 100644 --- a/src/kits/app/DesktopLink.cpp +++ b/src/kits/app/DesktopLink.cpp @@ -7,6 +7,8 @@ */ +#include + #include #include diff --git a/src/kits/game/DirectWindow.cpp b/src/kits/game/DirectWindow.cpp index 066b5fbeb7..8a4d03eff3 100644 --- a/src/kits/game/DirectWindow.cpp +++ b/src/kits/game/DirectWindow.cpp @@ -275,8 +275,9 @@ BDirectWindow::SetFullScreen(bool enable) fLink->Attach(enable); if (fLink->FlushWithReply(status) == B_OK - && status == B_OK) + && status == B_OK) { fIsFullScreen = enable; + } Unlock(); } return status; @@ -303,6 +304,8 @@ BDirectWindow::SupportsWindowMode(screen_id id) // TODO: Apparently, the above is false for the vesa driver, // but enabling it doesn't do any harm... maybe we should just return always true. // At least, I can't see why window mode shouldn't be supported. + // additional NOTE: it probably depends on wether hardware cursor is supported or + // not return true; } diff --git a/src/kits/interface/AbstractLayoutItem.cpp b/src/kits/interface/AbstractLayoutItem.cpp new file mode 100644 index 0000000000..9801d6aca1 --- /dev/null +++ b/src/kits/interface/AbstractLayoutItem.cpp @@ -0,0 +1,107 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include + + +// constructor +BAbstractLayoutItem::BAbstractLayoutItem() + : fMinSize(), + fMaxSize(), + fPreferredSize(), + fAlignment() +{ +} + +// destructor +BAbstractLayoutItem::~BAbstractLayoutItem() +{ +} + +// MinSize +BSize +BAbstractLayoutItem::MinSize() +{ + return BLayoutUtils::ComposeSize(fMinSize, BaseMinSize()); +} + +// MaxSize +BSize +BAbstractLayoutItem::MaxSize() +{ + return BLayoutUtils::ComposeSize(fMaxSize, BaseMaxSize()); +} + +// PreferredSize +BSize +BAbstractLayoutItem::PreferredSize() +{ + return BLayoutUtils::ComposeSize(fMaxSize, BaseMaxSize()); +} + +// Alignment +BAlignment +BAbstractLayoutItem::Alignment() +{ + return BLayoutUtils::ComposeAlignment(fAlignment, BaseAlignment()); +} + +// SetExplicitMinSize +void +BAbstractLayoutItem::SetExplicitMinSize(BSize size) +{ + fMinSize = size; +} + +// SetExplicitMaxSize +void +BAbstractLayoutItem::SetExplicitMaxSize(BSize size) +{ + fMaxSize = size; +} + +// SetExplicitPreferredSize +void +BAbstractLayoutItem::SetExplicitPreferredSize(BSize size) +{ + fPreferredSize = size; +} + +// SetExplicitAlignment +void +BAbstractLayoutItem::SetExplicitAlignment(BAlignment alignment) +{ + fAlignment = alignment; +} + +// BaseMinSize +BSize +BAbstractLayoutItem::BaseMinSize() +{ + return BSize(0, 0); +} + +// BaseMaxSize +BSize +BAbstractLayoutItem::BaseMaxSize() +{ + return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); +} + +// BasePreferredSize +BSize +BAbstractLayoutItem::BasePreferredSize() +{ + return BSize(0, 0); +} + +// BaseAlignment +BAlignment +BAbstractLayoutItem::BaseAlignment() +{ + return BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER); +} diff --git a/src/kits/interface/Alignment.cpp b/src/kits/interface/Alignment.cpp new file mode 100644 index 0000000000..73470a809f --- /dev/null +++ b/src/kits/interface/Alignment.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +// RelativeHorizontal +float +BAlignment::RelativeHorizontal() const +{ + switch (horizontal) { + case B_ALIGN_LEFT: + return 0; + case B_ALIGN_RIGHT: + return 1; + case B_ALIGN_HORIZONTAL_CENTER: + return 0.5f; + + default: + return (float)horizontal; + } +} + +// RelativeVertical +float +BAlignment::RelativeVertical() const +{ + switch (vertical) { + case B_ALIGN_TOP: + return 0; + case B_ALIGN_BOTTOM: + return 1; + case B_ALIGN_VERTICAL_CENTER: + return 0.5f; + + default: + return (float)vertical; + } +} diff --git a/src/kits/interface/Button.cpp b/src/kits/interface/Button.cpp index 46580f00a9..7091357169 100644 --- a/src/kits/interface/Button.cpp +++ b/src/kits/interface/Button.cpp @@ -12,7 +12,9 @@ #include + #include +#include #include #include @@ -31,6 +33,35 @@ BButton::BButton(BRect frame, const char *name, const char *label, BMessage *mes } +BButton::BButton(const char* name, const char* label, BMessage *message, + uint32 flags) + : BControl(BRect(0, 0, -1, -1), name, label, message, B_FOLLOW_NONE, + flags | B_WILL_DRAW | B_SUPPORTS_LAYOUT), + fDrawAsDefault(false) +{ + // Resize to minimum height if needed + font_height fh; + GetFontHeight(&fh); + float minHeight = 12.0f + (float)ceil(fh.ascent + fh.descent); + if (Bounds().Height() < minHeight) + ResizeTo(Bounds().Width(), minHeight); +} + + +BButton::BButton(const char* label, BMessage *message) + : BControl(BRect(0, 0, -1, -1), NULL, label, message, B_FOLLOW_NONE, + B_WILL_DRAW | B_NAVIGABLE | B_SUPPORTS_LAYOUT), + fDrawAsDefault(false) +{ + // Resize to minimum height if needed + font_height fh; + GetFontHeight(&fh); + float minHeight = 12.0f + (float)ceil(fh.ascent + fh.descent); + if (Bounds().Height() < minHeight) + ResizeTo(Bounds().Width(), minHeight); +} + + BButton::~BButton() { } @@ -690,6 +721,16 @@ BButton::Perform(perform_code d, void *arg) } +BSize +BButton::MaxSize() +{ + float width, height; + GetPreferredSize(&width, &height); + + return BLayoutUtils::ComposeSize(ExplicitMaxSize(), BSize(width, height)); +} + + void BButton::_ReservedButton1() {} void BButton::_ReservedButton2() {} void BButton::_ReservedButton3() {} diff --git a/src/kits/interface/CardLayout.cpp b/src/kits/interface/CardLayout.cpp new file mode 100644 index 0000000000..574665012a --- /dev/null +++ b/src/kits/interface/CardLayout.cpp @@ -0,0 +1,236 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include +#include + +// constructor +BCardLayout::BCardLayout() + : BLayout(), + fMin(0, 0), + fMax(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED), + fPreferred(0, 0), + fVisibleItem(NULL), + fMinMaxValid(false) +{ +} + +// destructor +BCardLayout::~BCardLayout() +{ +} + +// VisibleItem +BLayoutItem* +BCardLayout::VisibleItem() const +{ + return fVisibleItem; +} + +// VisibleIndex +int32 +BCardLayout::VisibleIndex() const +{ + return IndexOfItem(fVisibleItem); +} + +// SetVisibleItem +void +BCardLayout::SetVisibleItem(int32 index) +{ + SetVisibleItem(ItemAt(index)); +} + +// SetVisibleItem +void +BCardLayout::SetVisibleItem(BLayoutItem* item) +{ + if (item == fVisibleItem) + return; + + if (item != NULL && IndexOfItem(item) < 0) + return; + + if (fVisibleItem != NULL) + fVisibleItem->SetVisible(false); + + fVisibleItem = item; + + if (fVisibleItem != NULL) { + fVisibleItem->SetVisible(true); + + LayoutView(); + } +} + +// MinSize +BSize +BCardLayout::MinSize() +{ + _ValidateMinMax(); + return fMin; +} + +// MaxSize +BSize +BCardLayout::MaxSize() +{ + _ValidateMinMax(); + return fMax; +} + +// PreferredSize +BSize +BCardLayout::PreferredSize() +{ + _ValidateMinMax(); + return fPreferred; +} + +// Alignment +BAlignment +BCardLayout::Alignment() +{ + return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); +} + +// HasHeightForWidth +bool +BCardLayout::HasHeightForWidth() +{ + int32 count = CountItems(); + for (int32 i = 0; i < count; i++) { + if (ItemAt(i)->HasHeightForWidth()) + return true; + } + + return false; +} + +// GetHeightForWidth +void +BCardLayout::GetHeightForWidth(float width, float* min, float* max, + float* preferred) +{ + _ValidateMinMax(); + + // init with useful values + float minHeight = fMin.height; + float maxHeight = fMax.height; + float preferredHeight = fPreferred.height; + + // apply the items' constraints + int32 count = CountItems(); + for (int32 i = 0; i < count; i++) { + BLayoutItem* item = ItemAt(i); + if (item->HasHeightForWidth()) { + float itemMinHeight; + float itemMaxHeight; + float itemPreferredHeight; + item->GetHeightForWidth(width, &itemMinHeight, &itemMaxHeight, + &itemPreferredHeight); + minHeight = max_c(minHeight, itemMinHeight); + maxHeight = min_c(maxHeight, itemMaxHeight); + preferredHeight = min_c(preferredHeight, itemPreferredHeight); + } + } + + // adjust max and preferred, if necessary + maxHeight = max_c(maxHeight, minHeight); + preferredHeight = max_c(preferredHeight, minHeight); + preferredHeight = min_c(preferredHeight, maxHeight); + + if (min) + *min = minHeight; + if (max) + *max = maxHeight; + if (preferred) + *preferred = preferredHeight; +} + +// InvalidateLayout +void +BCardLayout::InvalidateLayout() +{ + BLayout::InvalidateLayout(); + + fMinMaxValid = false; +} + +// LayoutView +void +BCardLayout::LayoutView() +{ + _ValidateMinMax(); + + BSize size = BSize(View()->Bounds()); + size.width = max_c(size.width, fMin.width); + size.height = max_c(size.height, fMin.height); + + if (fVisibleItem != NULL) + fVisibleItem->AlignInFrame(BRect(0, 0, size.width, size.height)); +} + +// ItemAdded +void +BCardLayout::ItemAdded(BLayoutItem* item) +{ + item->SetVisible(false); +} + +// ItemRemoved +void +BCardLayout::ItemRemoved(BLayoutItem* item) +{ + if (fVisibleItem == item) { + BLayoutItem* newVisibleItem = NULL; + SetVisibleItem(newVisibleItem); + } +} + +// _ValidateMinMax +void +BCardLayout::_ValidateMinMax() +{ + if (fMinMaxValid) + return; + + fMin.width = 0; + fMin.height = 0; + fMax.width = B_SIZE_UNLIMITED; + fMax.height = B_SIZE_UNLIMITED; + fPreferred.width = 0; + fPreferred.height = 0; + + int32 itemCount = CountItems(); + for (int32 i = 0; i < itemCount; i++) { + BLayoutItem* item = ItemAt(i); + + BSize min = item->MinSize(); + BSize max = item->MaxSize(); + BSize preferred = item->PreferredSize(); + + fMin.width = max_c(fMin.width, min.width); + fMin.height = max_c(fMin.height, min.height); + + fMax.width = min_c(fMax.width, max.width); + fMax.height = min_c(fMax.height, max.height); + + fPreferred.width = max_c(fPreferred.width, preferred.width); + fPreferred.height = max_c(fPreferred.height, preferred.height); + } + + fMax.width = max_c(fMax.width, fMin.width); + fMax.height = max_c(fMax.height, fMin.height); + + fPreferred.width = max_c(fPreferred.width, fMin.width); + fPreferred.height = max_c(fPreferred.height, fMin.height); + fPreferred.width = min_c(fPreferred.width, fMax.width); + fPreferred.height = min_c(fPreferred.height, fMax.height); + + fMinMaxValid = true; +} diff --git a/src/kits/interface/ColorControl.cpp b/src/kits/interface/ColorControl.cpp index 14eaf58077..762dc821c6 100644 --- a/src/kits/interface/ColorControl.cpp +++ b/src/kits/interface/ColorControl.cpp @@ -200,6 +200,15 @@ BColorControl::Archive(BMessage *archive, bool deep) const } +void +BColorControl::SetLayout(BLayout* layout) +{ + // We need to implement this method, since we have another SetLayout() + // method and C++ has this special method hiding "feature". + BControl::SetLayout(layout); +} + + void BColorControl::SetValue(int32 value) { diff --git a/src/kits/interface/Control.cpp b/src/kits/interface/Control.cpp index d0b76580dd..1c4185516f 100644 --- a/src/kits/interface/Control.cpp +++ b/src/kits/interface/Control.cpp @@ -283,6 +283,7 @@ BControl::SetLabel(const char *label) free(fLabel); fLabel = label ? strdup(label) : NULL; + InvalidateLayout(); Invalidate(); } diff --git a/src/kits/interface/GridLayout.cpp b/src/kits/interface/GridLayout.cpp new file mode 100644 index 0000000000..d85d56dd8d --- /dev/null +++ b/src/kits/interface/GridLayout.cpp @@ -0,0 +1,586 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include +#include + +#include +#include + +#include "ViewLayoutItem.h" + + +enum { + MAX_COLUMN_ROW_COUNT = 1024, +}; + +// a placeholder we put in our grid array to make a cell occupied +static BLayoutItem* const OCCUPIED_GRID_CELL = (BLayoutItem*)0x1; + + +// ItemLayoutData +struct BGridLayout::ItemLayoutData { + Dimensions dimensions; + + ItemLayoutData() + { + dimensions.x = 0; + dimensions.y = 0; + dimensions.width = 1; + dimensions.height = 1; + } +}; + +// RowInfoArray +class BGridLayout::RowInfoArray { +public: + + RowInfoArray() + { + } + + ~RowInfoArray() + { + for (int32 i = 0; Info* info = (Info*)fInfos.ItemAt(i); i++) + delete info; + } + + int32 Count() const + { + return fInfos.CountItems(); + } + + float Weight(int32 index) const + { + if (Info* info = _InfoAt(index)) + return info->weight; + return 1; + } + + void SetWeight(int32 index, float weight) + { + if (Info* info = _InfoAt(index, true)) + info->weight = weight; + } + + float MinSize(int32 index) const + { + if (Info* info = _InfoAt(index)) + return info->minSize; + return -1; + } + + void SetMinSize(int32 index, float size) + { + if (Info* info = _InfoAt(index, true)) + info->minSize = size; + } + + float MaxSize(int32 index) const + { + if (Info* info = _InfoAt(index)) + return info->maxSize; + return B_SIZE_UNLIMITED; + } + + void SetMaxSize(int32 index, float size) + { + if (Info* info = _InfoAt(index, true)) + info->maxSize = size; + } + +private: + struct Info { + float weight; + float minSize; + float maxSize; + }; + + Info* _InfoAt(int32 index) const + { + return (Info*)fInfos.ItemAt(index); + } + + Info* _InfoAt(int32 index, bool resize) + { + if (index < 0 || index >= MAX_COLUMN_ROW_COUNT) + return NULL; + + // resize, if necessary and desired + int32 count = Count(); + if (index >= count) { + if (!resize) + return NULL; + + for (int32 i = count; i <= index; i++) { + Info* info = new Info; + info->weight = 1; + info->minSize = 0; + info->maxSize = B_SIZE_UNLIMITED; + } + } + + return _InfoAt(index); + } + + BList fInfos; +}; + + +// constructor +BGridLayout::BGridLayout(float horizontal, float vertical) + : fGrid(NULL), + fColumnCount(0), + fRowCount(0), + fRowInfos(new RowInfoArray), + fColumnInfos(new RowInfoArray), + fMultiColumnItems(0), + fMultiRowItems(0) +{ + SetSpacing(horizontal, vertical); +} + +// destructor +BGridLayout::~BGridLayout() +{ + delete fRowInfos; + delete fColumnInfos; +} + +// HorizontalSpacing +float +BGridLayout::HorizontalSpacing() const +{ + return fHSpacing; +} + +// VerticalSpacing +float +BGridLayout::VerticalSpacing() const +{ + return fVSpacing; +} + +// SetHorizontalSpacing +void +BGridLayout::SetHorizontalSpacing(float spacing) +{ + if (spacing != fHSpacing) { + fHSpacing = spacing; + + InvalidateLayout(); + } +} + +// SetVerticalSpacing +void +BGridLayout::SetVerticalSpacing(float spacing) +{ + if (spacing != fVSpacing) { + fVSpacing = spacing; + + InvalidateLayout(); + } +} + +// SetSpacing +void +BGridLayout::SetSpacing(float horizontal, float vertical) +{ + if (horizontal != fHSpacing || vertical != fVSpacing) { + fHSpacing = horizontal; + fVSpacing = vertical; + + InvalidateLayout(); + } +} + +// ColumnWeight +float +BGridLayout::ColumnWeight(int32 column) const +{ + return fColumnInfos->Weight(column); +} + +// SetColumnWeight +void +BGridLayout::SetColumnWeight(int32 column, float weight) +{ + fColumnInfos->SetWeight(column, weight); +} + +// MinColumnWidth +float +BGridLayout::MinColumnWidth(int32 column) const +{ + return fColumnInfos->MinSize(column); +} + +// SetMinColumnWidth +void +BGridLayout::SetMinColumnWidth(int32 column, float width) +{ + fColumnInfos->SetMinSize(column, width); +} + +// MaxColumnWidth +float +BGridLayout::MaxColumnWidth(int32 column) const +{ + return fColumnInfos->MaxSize(column); +} + +// SetMaxColumnWidth +void +BGridLayout::SetMaxColumnWidth(int32 column, float width) +{ + fColumnInfos->SetMaxSize(column, width); +} + +// RowWeight +float +BGridLayout::RowWeight(int32 row) const +{ + return fRowInfos->Weight(row); +} + +// SetRowWeight +void +BGridLayout::SetRowWeight(int32 row, float weight) +{ + fRowInfos->SetWeight(row, weight); +} + +// MinRowHeight +float +BGridLayout::MinRowHeight(int row) const +{ + return fRowInfos->MinSize(row); +} + +// SetMinRowHeight +void +BGridLayout::SetMinRowHeight(int32 row, float height) +{ + fRowInfos->SetMinSize(row, height); +} + +// MaxRowHeight +float +BGridLayout::MaxRowHeight(int32 row) const +{ + return fRowInfos->MaxSize(row); +} + +// SetMaxRowHeight +void +BGridLayout::SetMaxRowHeight(int32 row, float height) +{ + fRowInfos->SetMaxSize(row, height); +} + +// AddView +BLayoutItem* +BGridLayout::AddView(BView* child) +{ + return BTwoDimensionalLayout::AddView(child); +} + +// AddView +BLayoutItem* +BGridLayout::AddView(int32 index, BView* child) +{ + return BTwoDimensionalLayout::AddView(index, child); +} + +// AddView +BLayoutItem* +BGridLayout::AddView(BView* child, int32 column, int32 row, int32 columnCount, + int32 rowCount) +{ + if (!child) + return NULL; + + BLayoutItem* item = new BViewLayoutItem(child); + if (!AddItem(item, column, row, columnCount, rowCount)) { + delete item; + return NULL; + } + + return item; +} + +// AddItem +bool +BGridLayout::AddItem(BLayoutItem* item) +{ + // find a free spot + for (int32 row = 0; row < fRowCount; row++) { + for (int32 column = 0; column < fColumnCount; column++) { + if (_IsGridCellEmpty(row, column)) + return AddItem(item, column, row, 1, 1); + } + } + + // no free spot, start a new column + return AddItem(item, fColumnCount, 0, 1, 1); +} + +// AddItem +bool +BGridLayout::AddItem(int32 index, BLayoutItem* item) +{ + return AddItem(index, item); +} + +// AddItem +bool +BGridLayout::AddItem(BLayoutItem* item, int32 column, int32 row, + int32 columnCount, int32 rowCount) +{ + if (!_AreGridCellsEmpty(column, row, columnCount, rowCount)) + return false; + + bool success = BTwoDimensionalLayout::AddItem(-1, item); + if (!success) + return false; + + // set item dimensions + if (ItemLayoutData* data = _LayoutDataForItem(item)) { + data->dimensions.x = column; + data->dimensions.y = row; + data->dimensions.width = columnCount; + data->dimensions.height = rowCount; + } + + // resize the grid, if necessary + int32 newColumnCount = max_c(fColumnCount, column + columnCount); + int32 newRowCount = max_c(fRowCount, row + rowCount); + if (newColumnCount > fColumnCount || newRowCount > fRowCount) { + if (!_ResizeGrid(newColumnCount, newRowCount)) { + RemoveItem(item); + return false; + } + } + + // enter the item in the grid + for (int32 x = 0; x < columnCount; x++) { + for (int32 y = 0; y < rowCount; y++) { + if (x == 0 && y == 0) + fGrid[column + x][row + y] = item; + else + fGrid[column + x][row + y] = OCCUPIED_GRID_CELL; + } + } + + if (columnCount > 1) + fMultiColumnItems++; + if (rowCount > 1) + fMultiRowItems++; + + return success; +} + +// ItemAdded +void +BGridLayout::ItemAdded(BLayoutItem* item) +{ + item->SetLayoutData(new ItemLayoutData); +} + +// ItemRemoved +void +BGridLayout::ItemRemoved(BLayoutItem* item) +{ + ItemLayoutData* data = _LayoutDataForItem(item); +// TODO: Once ItemAdded() returns a bool, we can remove this check. + if (!data) + return; + + Dimensions itemDimensions = data->dimensions; + item->SetLayoutData(NULL); + delete data; + + if (itemDimensions.width > 1) + fMultiColumnItems--; + if (itemDimensions.height > 1) + fMultiRowItems--; + + // remove the item from the grid + for (int x = 0; x < itemDimensions.width; x++) { + for (int y = 0; y < itemDimensions.height; y++) + fGrid[itemDimensions.x + x][itemDimensions.y + y] = NULL; + } + + // check whether we can shrink the grid + if (itemDimensions.x + itemDimensions.width == fColumnCount + || itemDimensions.y + itemDimensions.height == fRowCount) { + int32 columnCount = fColumnCount; + int32 rowCount = fRowCount; + + // check for empty columns + bool empty = false; + for (; columnCount > 0; columnCount--) { + for (int32 row = 0; empty && row < rowCount; row++) + empty &= (fGrid[columnCount - 1][row] == NULL); + + if (!empty) + break; + } + + // check for empty rows + empty = false; + for (; rowCount > 0; rowCount--) { + for (int32 column = 0; empty && column < columnCount; column++) + empty &= (fGrid[column][rowCount - 1] == NULL); + + if (!empty) + break; + } + + // resize the grid + if (columnCount != fColumnCount || rowCount != fRowCount) + _ResizeGrid(columnCount, rowCount); + } +} + +// HasMultiColumnItems +bool +BGridLayout::HasMultiColumnItems() +{ + return (fMultiColumnItems > 0); +} + +// HasMultiRowItems +bool +BGridLayout::HasMultiRowItems() +{ + return (fMultiRowItems > 0); +} + +// InternalCountColumns +int32 +BGridLayout::InternalCountColumns() +{ + return fColumnCount; +} + +// InternalCountRows +int32 +BGridLayout::InternalCountRows() +{ + return fRowCount; +} + +// GetColumnRowConstraints +void +BGridLayout::GetColumnRowConstraints(enum orientation orientation, int32 index, + ColumnRowConstraints* constraints) +{ + if (orientation == B_HORIZONTAL) { + constraints->min = MinColumnWidth(index); + constraints->max = MaxColumnWidth(index); + constraints->weight = ColumnWeight(index); + } else { + constraints->min = MinRowHeight(index); + constraints->max = MaxRowHeight(index); + constraints->weight = RowWeight(index); + } +} + +// GetItemDimensions +void +BGridLayout::GetItemDimensions(BLayoutItem* item, Dimensions* dimensions) +{ + if (ItemLayoutData* data = _LayoutDataForItem(item)) + *dimensions = data->dimensions; +} + +// _IsGridCellEmpty +bool +BGridLayout::_IsGridCellEmpty(int32 column, int32 row) +{ + if (column < 0 || row < 0) + return false; + if (column >= fColumnCount || row >= fRowCount) + return true; + + return (fGrid[column][row] == NULL); +} + +// _AreGridCellsEmpty +bool +BGridLayout::_AreGridCellsEmpty(int32 column, int32 row, int32 columnCount, + int32 rowCount) +{ + if (column < 0 || row < 0) + return false; + int32 toColumn = min_c(column + columnCount, fColumnCount); + int32 toRow = min_c(row + rowCount, fRowCount); + + for (int32 x = column; x < toColumn; x++) { + for (int32 y = row; y < toRow; y++) { + if (fGrid[x][y] != NULL) + return false; + } + } + + return true; +} + +// _ResizeGrid +bool +BGridLayout::_ResizeGrid(int32 columnCount, int32 rowCount) +{ + if (columnCount == fColumnCount && rowCount == fRowCount) + return true; + + int32 rowsToKeep = min_c(rowCount, fRowCount); + + // allocate new grid + BLayoutItem*** grid = new(nothrow) BLayoutItem**[columnCount]; + if (!grid) + return false; + memset(grid, 0, sizeof(BLayoutItem**) * columnCount); + + bool success = true; + for (int32 i = 0; i < columnCount; i++) { + BLayoutItem** column = new(nothrow) BLayoutItem*[rowCount]; + if (!column) { + success = false; + break; + } + grid[i] = column; + + memset(column, 0, sizeof(BLayoutItem*) * rowCount); + if (i < fColumnCount && rowsToKeep > 0) + memcpy(column, fGrid[i], sizeof(BLayoutItem*) * rowsToKeep); + } + + // if everything went fine, set the new grid + if (success) { + swap(grid, fGrid); + swap(columnCount, fColumnCount); + swap(rowCount, fRowCount); + } + + // delete the old, respectively on error the partially created grid + for (int32 i = 0; i < columnCount; i++) + delete grid[i]; + delete[] grid; + + return success; +} + +// _LayoutDataForItem +BGridLayout::ItemLayoutData* +BGridLayout::_LayoutDataForItem(BLayoutItem* item) const +{ + if (!item) + return NULL; + return (ItemLayoutData*)item->LayoutData(); +} diff --git a/src/kits/interface/GridLayoutBuilder.cpp b/src/kits/interface/GridLayoutBuilder.cpp new file mode 100644 index 0000000000..1a8f69e8c7 --- /dev/null +++ b/src/kits/interface/GridLayoutBuilder.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include + +#include + + +using std::nothrow; + + +// constructor +BGridLayoutBuilder::BGridLayoutBuilder(float horizontalSpacing, + float verticalSpacing) + : fLayout((new BGridView(horizontalSpacing, verticalSpacing)) + ->GridLayout()) +{ +} + +// constructor +BGridLayoutBuilder::BGridLayoutBuilder(BGridLayout* layout) + : fLayout(layout) +{ +} + + +// constructor +BGridLayoutBuilder::BGridLayoutBuilder(BGridView* view) + : fLayout(view->GridLayout()) +{ +} + +// GridLayout +BGridLayout* +BGridLayoutBuilder::GridLayout() const +{ + return fLayout; +} + +// View +BView* +BGridLayoutBuilder::View() const +{ + return fLayout->View(); +} + +// GetGridLayout +BGridLayoutBuilder& +BGridLayoutBuilder::GetGridLayout(BGridLayout** _layout) +{ + *_layout = fLayout; + return *this; +} + +// GetView +BGridLayoutBuilder& +BGridLayoutBuilder::GetView(BView** _view) +{ + *_view = fLayout->View(); + return *this; +} + +// Add +BGridLayoutBuilder& +BGridLayoutBuilder::Add(BView* view, int32 column, int32 row, + int32 columnCount, int32 rowCount) +{ + fLayout->AddView(view, column, row, columnCount, rowCount); + return *this; +} + +// Add +BGridLayoutBuilder& +BGridLayoutBuilder::Add(BLayoutItem* item, int32 column, int32 row, + int32 columnCount, int32 rowCount) +{ + fLayout->AddItem(item, column, row, columnCount, rowCount); + return *this; +} + +// SetColumnWeight +BGridLayoutBuilder& +BGridLayoutBuilder::SetColumnWeight(int32 column, float weight) +{ + fLayout->SetColumnWeight(column, weight); + return *this; +} + +// SetRowWeight +BGridLayoutBuilder& +BGridLayoutBuilder::SetRowWeight(int32 row, float weight) +{ + fLayout->SetRowWeight(row, weight); + return *this; +} + +// cast operator BGridLayout* +BGridLayoutBuilder::operator BGridLayout*() +{ + return fLayout; +} + +// cast operator BView* +BGridLayoutBuilder::operator BView*() +{ + return fLayout->View(); +} diff --git a/src/kits/interface/GridView.cpp b/src/kits/interface/GridView.cpp new file mode 100644 index 0000000000..3a96ff1978 --- /dev/null +++ b/src/kits/interface/GridView.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + + +// constructor +BGridView::BGridView(float horizontalSpacing, float verticalSpacing) + : BView(NULL, 0, new BGridLayout(horizontalSpacing, verticalSpacing)) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} + +// destructor +BGridView::~BGridView() +{ +} + +// SetLayout +void +BGridView::SetLayout(BLayout* layout) +{ + // only BGridLayouts are allowed + if (!dynamic_cast(layout)) + return; + + BView::SetLayout(layout); +} + +// GridLayout +BGridLayout* +BGridView::GridLayout() const +{ + return dynamic_cast(GetLayout()); +} diff --git a/src/kits/interface/GroupLayout.cpp b/src/kits/interface/GroupLayout.cpp new file mode 100644 index 0000000000..5a25779a22 --- /dev/null +++ b/src/kits/interface/GroupLayout.cpp @@ -0,0 +1,249 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include + + +// ItemLayoutData +struct BGroupLayout::ItemLayoutData { + float weight; + + ItemLayoutData() + : weight(1) + { + } +}; + +// constructor +BGroupLayout::BGroupLayout(enum orientation orientation, float spacing) + : BTwoDimensionalLayout(), + fOrientation(orientation) +{ + SetSpacing(spacing); +} + +// destructor +BGroupLayout::~BGroupLayout() +{ +} + +// Spacing +float +BGroupLayout::Spacing() const +{ + return fHSpacing; +} + +// SetSpacing +void +BGroupLayout::SetSpacing(float spacing) +{ + if (spacing != fHSpacing) { + fHSpacing = spacing; + fVSpacing = spacing; + InvalidateLayout(); + } +} + +// Orientation +orientation +BGroupLayout::Orientation() const +{ + return fOrientation; +} + +// SetOrientation +void +BGroupLayout::SetOrientation(enum orientation orientation) +{ + if (orientation != fOrientation) { + fOrientation = orientation; + + InvalidateLayout(); + } +} + +// ItemWeight +float +BGroupLayout::ItemWeight(int32 index) const +{ + if (index < 0 || index >= CountItems()) + return 0; + + ItemLayoutData* data = _LayoutDataForItem(ItemAt(index)); + return (data ? data->weight : 0); +} + +// SetItemWeight +void +BGroupLayout::SetItemWeight(int32 index, float weight) +{ + if (index < 0 || index >= CountItems()) + return; + + if (ItemLayoutData* data = _LayoutDataForItem(ItemAt(index))) + data->weight = weight; + + InvalidateLayout(); +} + +// AddView +BLayoutItem* +BGroupLayout::AddView(BView* child) +{ + return BTwoDimensionalLayout::AddView(child); +} + +// AddView +BLayoutItem* +BGroupLayout::AddView(int32 index, BView* child) +{ + return BTwoDimensionalLayout::AddView(index, child); +} + +// AddView +BLayoutItem* +BGroupLayout::AddView(BView* child, float weight) +{ + return AddView(-1, child, weight); +} + +// AddView +BLayoutItem* +BGroupLayout::AddView(int32 index, BView* child, float weight) +{ + BLayoutItem* item = AddView(index, child); + if (ItemLayoutData* data = _LayoutDataForItem(item)) + data->weight = weight; + + return item; +} + +// AddItem +bool +BGroupLayout::AddItem(BLayoutItem* item) +{ + return BTwoDimensionalLayout::AddItem(item); +} + +// AddItem +bool +BGroupLayout::AddItem(int32 index, BLayoutItem* item) +{ + return BTwoDimensionalLayout::AddItem(index, item); +} + +// AddItem +bool +BGroupLayout::AddItem(BLayoutItem* item, float weight) +{ + return AddItem(-1, item, weight); +} + +// AddItem +bool +BGroupLayout::AddItem(int32 index, BLayoutItem* item, float weight) +{ + bool success = AddItem(index, item); + if (success) { + if (ItemLayoutData* data = _LayoutDataForItem(item)) + data->weight = weight; + } + + return success; +} + +// ItemAdded +void +BGroupLayout::ItemAdded(BLayoutItem* item) +{ + item->SetLayoutData(new ItemLayoutData); +} + +// ItemRemoved +void +BGroupLayout::ItemRemoved(BLayoutItem* item) +{ + if (ItemLayoutData* data = _LayoutDataForItem(item)) { + item->SetLayoutData(NULL); + delete data; + } +} + +// PrepareItems +void +BGroupLayout::PrepareItems(enum orientation orientation) +{ + // filter the visible items + fVisibleItems.MakeEmpty(); + int32 itemCount = CountItems(); + for (int i = 0; i < itemCount; i++) { + BLayoutItem* item = ItemAt(i); + if (item->IsVisible()) + fVisibleItems.AddItem(item); + } +} + +// InternalCountColumns +int32 +BGroupLayout::InternalCountColumns() +{ + return (fOrientation == B_HORIZONTAL ? fVisibleItems.CountItems() : 1); +} + +// InternalCountRows +int32 +BGroupLayout::InternalCountRows() +{ + return (fOrientation == B_VERTICAL ? fVisibleItems.CountItems() : 1); +} + +// GetColumnRowConstraints +void +BGroupLayout::GetColumnRowConstraints(enum orientation orientation, int32 index, + ColumnRowConstraints* constraints) +{ + if (index >= 0 && index < fVisibleItems.CountItems()) { + BLayoutItem* item = (BLayoutItem*)fVisibleItems.ItemAt(index); + constraints->min = -1; + constraints->max = B_SIZE_UNLIMITED; + if (ItemLayoutData* data = _LayoutDataForItem(item)) + constraints->weight = data->weight; + else + constraints->weight = 1; + } +} + +// ItemDimensions +void +BGroupLayout::GetItemDimensions(BLayoutItem* item, Dimensions* dimensions) +{ + int32 index = fVisibleItems.IndexOf(item); + if (index < 0) + return; + + if (fOrientation == B_HORIZONTAL) { + dimensions->x = index; + dimensions->y = 0; + dimensions->width = 1; + dimensions->height = 1; + } else { + dimensions->x = 0; + dimensions->y = index; + dimensions->width = 1; + dimensions->height = 1; + } +} + +// _LayoutDataForItem +BGroupLayout::ItemLayoutData* +BGroupLayout::_LayoutDataForItem(BLayoutItem* item) const +{ + if (!item) + return NULL; + return (ItemLayoutData*)item->LayoutData(); +} diff --git a/src/kits/interface/GroupLayoutBuilder.cpp b/src/kits/interface/GroupLayoutBuilder.cpp new file mode 100644 index 0000000000..089aedc484 --- /dev/null +++ b/src/kits/interface/GroupLayoutBuilder.cpp @@ -0,0 +1,187 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include + +#include + + +using std::nothrow; + + +// constructor +BGroupLayoutBuilder::BGroupLayoutBuilder(enum orientation orientation, + float spacing) + : fRootLayout((new BGroupView(orientation, spacing))->GroupLayout()) +{ + _PushLayout(fRootLayout); +} + +// constructor +BGroupLayoutBuilder::BGroupLayoutBuilder(BGroupLayout* layout) + : fRootLayout(layout) +{ + _PushLayout(fRootLayout); +} + + +// constructor +BGroupLayoutBuilder::BGroupLayoutBuilder(BGroupView* view) + : fRootLayout(view->GroupLayout()) +{ + _PushLayout(fRootLayout); +} + +// RootLayout +BGroupLayout* +BGroupLayoutBuilder::RootLayout() const +{ + return fRootLayout; +} + +// TopLayout +BGroupLayout* +BGroupLayoutBuilder::TopLayout() const +{ + int32 count = fLayoutStack.CountItems(); + return (count > 0 + ? (BGroupLayout*)fLayoutStack.ItemAt(count - 1) : NULL); +} + +// GetTopLayout +BGroupLayoutBuilder& +BGroupLayoutBuilder::GetTopLayout(BGroupLayout** _layout) +{ + *_layout = TopLayout(); + return *this; +} + +// GetTopView +BGroupLayoutBuilder& +BGroupLayoutBuilder::GetTopView(BView** _view) +{ + if (BGroupLayout* layout = TopLayout()) + *_view = layout->View(); + else + *_view = NULL; + + return *this; +} + +// Add +BGroupLayoutBuilder& +BGroupLayoutBuilder::Add(BView* view) +{ + if (BGroupLayout* layout = TopLayout()) + layout->AddView(view); + return *this; +} + +// Add +BGroupLayoutBuilder& +BGroupLayoutBuilder::Add(BView* view, float weight) +{ + if (BGroupLayout* layout = TopLayout()) + layout->AddView(view, weight); + return *this; +} + +// Add +BGroupLayoutBuilder& +BGroupLayoutBuilder::Add(BLayoutItem* item) +{ + if (BGroupLayout* layout = TopLayout()) + layout->AddItem(item); + return *this; +} + +// Add +BGroupLayoutBuilder& +BGroupLayoutBuilder::Add(BLayoutItem* item, float weight) +{ + if (BGroupLayout* layout = TopLayout()) + layout->AddItem(item, weight); + return *this; +} + +// AddGroup +BGroupLayoutBuilder& +BGroupLayoutBuilder::AddGroup(enum orientation orientation, + float spacing = 0.0f, float weight = 1.0f) +{ + if (BGroupLayout* layout = TopLayout()) { + BGroupView* group = new(nothrow) BGroupView(orientation, spacing); + if (group) { + if (layout->AddView(group, weight)) + _PushLayout(group->GroupLayout()); + else + delete group; + } + } + + return *this; +} + +// End +BGroupLayoutBuilder& +BGroupLayoutBuilder::End() +{ + _PopLayout(); + return *this; +} + +// AddGlue +BGroupLayoutBuilder& +BGroupLayoutBuilder::AddGlue(float weight = 1.0f) +{ + if (BGroupLayout* layout = TopLayout()) + layout->AddItem(BSpaceLayoutItem::CreateGlue(), weight); + + return *this; +} + +// AddStrut +BGroupLayoutBuilder& +BGroupLayoutBuilder::AddStrut(float size) +{ + if (BGroupLayout* layout = TopLayout()) { + if (layout->Orientation() == B_HORIZONTAL) + layout->AddItem(BSpaceLayoutItem::CreateHorizontalStrut(size)); + else + layout->AddItem(BSpaceLayoutItem::CreateVerticalStrut(size)); + } + + return *this; +} + +// cast operator BGroupLayout* +BGroupLayoutBuilder::operator BGroupLayout*() +{ + return fRootLayout; +} + +// cast operator BView* +BGroupLayoutBuilder::operator BView*() +{ + return fRootLayout->View(); +} + +// _PushLayout +bool +BGroupLayoutBuilder::_PushLayout(BGroupLayout* layout) +{ + return fLayoutStack.AddItem(layout); +} + +// _PopLayout +void +BGroupLayoutBuilder::_PopLayout() +{ + int32 count = fLayoutStack.CountItems(); + if (count > 0) + fLayoutStack.RemoveItem(count - 1); +} diff --git a/src/kits/interface/GroupView.cpp b/src/kits/interface/GroupView.cpp new file mode 100644 index 0000000000..a76d519e46 --- /dev/null +++ b/src/kits/interface/GroupView.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + + +// constructor +BGroupView::BGroupView(enum orientation orientation, float spacing) + : BView(NULL, 0, new BGroupLayout(orientation, spacing)) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} + +// destructor +BGroupView::~BGroupView() +{ +} + +// SetLayout +void +BGroupView::SetLayout(BLayout* layout) +{ + // only BGroupLayouts are allowed + if (!dynamic_cast(layout)) + return; + + BView::SetLayout(layout); +} + +// GroupLayout +BGroupLayout* +BGroupView::GroupLayout() const +{ + return dynamic_cast(GetLayout()); +} diff --git a/src/kits/interface/Jamfile b/src/kits/interface/Jamfile index cdd837d812..24905b67ff 100644 --- a/src/kits/interface/Jamfile +++ b/src/kits/interface/Jamfile @@ -27,14 +27,23 @@ SetSubDirSupportedPlatforms haiku libbe_test ; UsePrivateHeaders app input interface shared tracker ; +# qoca headers +SubDirSysHdrs $(SUBDIR) ; +SubDirHdrs [ FDirName $(SUBDIR) qoca ] ; + + SEARCH_SOURCE += [ FDirName $(SUBDIR) BTextView ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) layouter ] ; MergeObject interface_kit.o : + AbstractLayoutItem.cpp Alert.cpp + Alignment.cpp Bitmap.cpp BMCPrivate.cpp Box.cpp Button.cpp + CardLayout.cpp ChannelControl.cpp ChannelSlider.cpp CheckBox.cpp @@ -48,8 +57,18 @@ MergeObject interface_kit.o : Dragger.cpp Font.cpp GraphicsDefs.cpp + GridLayout.cpp + GridLayoutBuilder.cpp + GridView.cpp + GroupLayout.cpp + GroupLayoutBuilder.cpp + GroupView.cpp Input.cpp InterfaceDefs.cpp + Layout.cpp + LayoutContext.cpp + LayoutItem.cpp + LayoutUtils.cpp ListItem.cpp ListView.cpp Menu.cpp @@ -77,14 +96,21 @@ MergeObject interface_kit.o : SeparatorItem.cpp Shape.cpp Shelf.cpp + Size.cpp Slider.cpp + SpaceLayoutItem.cpp + SplitLayout.cpp + SplitLayoutBuilder.cpp + SplitView.cpp StatusBar.cpp StringView.cpp TabView.cpp TextControl.cpp TextInput.cpp TPicture.cpp + TwoDimensionalLayout.cpp View.cpp + ViewLayoutItem.cpp Window.cpp ZombieReplicantView.cpp @@ -96,4 +122,12 @@ MergeObject interface_kit.o : TextView.cpp UndoBuffer.cpp WidthBuffer.cpp + + # layouter + ConstraintSolverLayouter.cpp + Layouter.cpp + OneElementLayouter.cpp + SimpleLayouter.cpp ; + +SubInclude HAIKU_TOP src kits interface qoca ; diff --git a/src/kits/interface/Layout.cpp b/src/kits/interface/Layout.cpp new file mode 100644 index 0000000000..29e6bdff82 --- /dev/null +++ b/src/kits/interface/Layout.cpp @@ -0,0 +1,204 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include + +#include + +#include "ViewLayoutItem.h" + +using std::nothrow; + + +// constructor +BLayout::BLayout() + : fView(NULL), + fItems(20) +{ +} + +// destructor +BLayout::~BLayout() +{ + // this deletes all items + SetView(NULL); +} + +// View +BView* +BLayout::View() const +{ + return fView; +} + +// AddView +BLayoutItem* +BLayout::AddView(BView* child) +{ + return AddView(-1, child); +} + +// AddView +BLayoutItem* +BLayout::AddView(int32 index, BView* child) +{ + if (BViewLayoutItem* item = new(nothrow) BViewLayoutItem(child)) { + if (AddItem(index, item)) + return item; + delete item; + } + return NULL; +} + +// AddItem +bool +BLayout::AddItem(BLayoutItem* item) +{ + return AddItem(-1, item); +} + +// AddItem +bool +BLayout::AddItem(int32 index, BLayoutItem* item) +{ + if (!fView || !item || fItems.HasItem(item)) + return false; + + // if the item refers to a BView, we make sure, it is added to the parent + // view + BView* view = item->View(); + if (view && view->fParent != fView && !fView->_AddChild(view, NULL)) + return false; + + // validate the index + if (index < 0 || index > fItems.CountItems()) + index = fItems.CountItems(); + + fItems.AddItem(item, index); + ItemAdded(item); + item->SetLayout(this); + InvalidateLayout(); + + return true; +} + +// RemoveView +bool +BLayout::RemoveView(BView* child) +{ + int32 index = IndexOfView(child); + if (index >= 0) { + if (BLayoutItem* item = RemoveItem(index)) { + delete item; + return true; + } + } + + return false; +} + +// RemoveItem +bool +BLayout::RemoveItem(BLayoutItem* item) +{ + int32 index = IndexOfItem(item); + return (index >= 0 ? RemoveItem(index) : false); +} + +// RemoveItem +BLayoutItem* +BLayout::RemoveItem(int32 index) +{ + if (index < 0 || index >= fItems.CountItems()) + return NULL; + + BLayoutItem* item = (BLayoutItem*)fItems.RemoveItem(index); + + // if the item refers to a BView, we make sure, it is removed from the + // parent view + BView* view = item->View(); + if (view && view->fParent == fView) + view->_RemoveSelf(); + + item->SetLayout(NULL); + ItemRemoved(item); + InvalidateLayout(); + + return item; +} + +// ItemAt +BLayoutItem* +BLayout::ItemAt(int32 index) const +{ + return (BLayoutItem*)fItems.ItemAt(index); +} + +// CountItems +int32 +BLayout::CountItems() const +{ + return fItems.CountItems(); +} + +// IndexOfItem +int32 +BLayout::IndexOfItem(BLayoutItem* item) const +{ + return fItems.IndexOf(item); +} + +// IndexOfView +int32 +BLayout::IndexOfView(BView* child) const +{ + int itemCount = fItems.CountItems(); + for (int32 i = 0; i < itemCount; i++) { + BLayoutItem* item = (BLayoutItem*)fItems.ItemAt(i); + if (dynamic_cast(item) && item->View() == child) + return i; + } + + return -1; +} + +// InvalidateLayout +void +BLayout::InvalidateLayout() +{ + if (fView) + fView->InvalidateLayout(); +} + +// ItemAdded +void +BLayout::ItemAdded(BLayoutItem* item) +{ +} + +// ItemRemoved +void +BLayout::ItemRemoved(BLayoutItem* item) +{ +} + +// SetView +void +BLayout::SetView(BView* view) +{ + if (view != fView) { + fView = NULL; + + // remove and delete all items + for (int32 i = CountItems() - 1; i >= 0; i--) + delete RemoveItem(i); + + fView = view; + + InvalidateLayout(); + } +} diff --git a/src/kits/interface/LayoutContext.cpp b/src/kits/interface/LayoutContext.cpp new file mode 100644 index 0000000000..cae4d922fc --- /dev/null +++ b/src/kits/interface/LayoutContext.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + + +// constructor +BLayoutContextListener::BLayoutContextListener() +{ +} + +// destructor +BLayoutContextListener::~BLayoutContextListener() +{ +} + + +// #pragma mark - + + +// constructor +BLayoutContext::BLayoutContext() +{ +} + +// destructor +BLayoutContext::~BLayoutContext() +{ + // notify the listeners + for (int32 i = 0; + BLayoutContextListener* listener + = (BLayoutContextListener*)fListeners.ItemAt(i); + i++) { + listener->LayoutContextLeft(this); + } +} + +// AddListener +void +BLayoutContext::AddListener(BLayoutContextListener* listener) +{ + if (listener) + fListeners.AddItem(listener); +} + +// RemoveListener +void +BLayoutContext::RemoveListener(BLayoutContextListener* listener) +{ + if (listener) + fListeners.RemoveItem(listener); +} diff --git a/src/kits/interface/LayoutItem.cpp b/src/kits/interface/LayoutItem.cpp new file mode 100644 index 0000000000..14c059ccf4 --- /dev/null +++ b/src/kits/interface/LayoutItem.cpp @@ -0,0 +1,109 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include +#include + + +// constructor +BLayoutItem::BLayoutItem() + : fLayout(NULL), + fLayoutData(NULL) +{ +} + +// destructor +BLayoutItem::~BLayoutItem() +{ +} + +// Layout +BLayout* +BLayoutItem::Layout() const +{ + return fLayout; +} + +// HasHeightForWidth +bool +BLayoutItem::HasHeightForWidth() +{ + // no "height for width" by default + return false; +} + +// GetHeightForWidth +void +BLayoutItem::GetHeightForWidth(float width, float* min, float* max, + float* preferred) +{ + // no "height for width" by default +} + +// View +BView* +BLayoutItem::View() +{ + return NULL; +} + +// InvalidateLayout +void +BLayoutItem::InvalidateLayout() +{ + if (fLayout) + fLayout->InvalidateLayout(); +} + +// LayoutData +void* +BLayoutItem::LayoutData() const +{ + return fLayoutData; +} + +// SetLayoutData +void +BLayoutItem::SetLayoutData(void* data) +{ + fLayoutData = data; +} + +// AlignInFrame +void +BLayoutItem::AlignInFrame(BRect frame) +{ + BSize maxSize = MaxSize(); + BAlignment alignment = Alignment(); + + if (HasHeightForWidth()) { + // The item has height for width, so we do the horizontal alignment + // ourselves and restrict the height max constraint respectively. + if (maxSize.width < frame.Width() + && alignment.horizontal != B_ALIGN_USE_FULL_WIDTH) { + frame.left += (int)((frame.Width() - maxSize.width) + * alignment.horizontal); + frame.right = frame.left + maxSize.width; + } + alignment.horizontal = B_ALIGN_USE_FULL_WIDTH; + + float minHeight; + GetHeightForWidth(frame.Width(), &minHeight, NULL, NULL); + + frame.bottom = frame.top + max_c(frame.Height(), minHeight); + maxSize.height = minHeight; + } + + SetFrame(BLayoutUtils::AlignInFrame(frame, maxSize, alignment)); +} + +// SetLayout +void +BLayoutItem::SetLayout(BLayout* layout) +{ + fLayout = layout; +} diff --git a/src/kits/interface/LayoutUtils.cpp b/src/kits/interface/LayoutUtils.cpp new file mode 100644 index 0000000000..a6d87529b8 --- /dev/null +++ b/src/kits/interface/LayoutUtils.cpp @@ -0,0 +1,167 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + + +// // AddSizesFloat +// float +// BLayoutUtils::AddSizesFloat(float a, float b) +// { +// float sum = a + b + 1; +// if (sum >= B_SIZE_UNLIMITED) +// return B_SIZE_UNLIMITED; +// +// return sum; +// } +// +// // AddSizesFloat +// float +// BLayoutUtils::AddSizesFloat(float a, float b, float c) +// { +// return AddSizesFloat(AddSizesFloat(a, b), c); +// } + +// AddSizesInt32 +int32 +BLayoutUtils::AddSizesInt32(int32 a, int32 b) +{ + if (a >= B_SIZE_UNLIMITED - b) + return B_SIZE_UNLIMITED; + return a + b; +} + +// AddSizesInt32 +int32 +BLayoutUtils::AddSizesInt32(int32 a, int32 b, int32 c) +{ + return AddSizesInt32(AddSizesInt32(a, b), c); +} + +// AddDistances +float +BLayoutUtils::AddDistances(float a, float b) +{ + float sum = a + b + 1; + if (sum >= B_SIZE_UNLIMITED) + return B_SIZE_UNLIMITED; + + return sum; +} + +// AddDistances +float +BLayoutUtils::AddDistances(float a, float b, float c) +{ + return AddDistances(AddDistances(a, b), c); +} + +// // SubtractSizesFloat +// float +// BLayoutUtils::SubtractSizesFloat(float a, float b) +// { +// if (a < b) +// return -1; +// return a - b - 1; +// } + +// SubtractSizesInt32 +int32 +BLayoutUtils::SubtractSizesInt32(int32 a, int32 b) +{ + if (a < b) + return 0; + return a - b; +} + +// SubtractDistances +float +BLayoutUtils::SubtractDistances(float a, float b) +{ + if (a < b) + return -1; + return a - b - 1; +} + +// ComposeSize +BSize +BLayoutUtils::ComposeSize(BSize size, BSize layoutSize) +{ + if (!size.IsWidthSet()) + size.width = layoutSize.width; + if (!size.IsHeightSet()) + size.height = layoutSize.height; + + return size; +} + +// ComposeAlignment +BAlignment +BLayoutUtils::ComposeAlignment(BAlignment alignment, BAlignment layoutAlignment) +{ + if (!alignment.IsHorizontalSet()) + alignment.horizontal = layoutAlignment.horizontal; + if (!alignment.IsVerticalSet()) + alignment.vertical = layoutAlignment.vertical; + + return alignment; +} + +// AlignInFrame +BRect +BLayoutUtils::AlignInFrame(BRect frame, BSize maxSize, BAlignment alignment) +{ + // align according to the given alignment + if (maxSize.width < frame.Width() + && alignment.horizontal != B_ALIGN_USE_FULL_WIDTH) { + frame.left += (int)((frame.Width() - maxSize.width) + * alignment.RelativeHorizontal()); + frame.right = frame.left + maxSize.width; + } + if (maxSize.height < frame.Height() + && alignment.vertical != B_ALIGN_USE_FULL_HEIGHT) { + frame.top += (int)((frame.Height() - maxSize.height) + * alignment.RelativeVertical()); + frame.bottom = frame.top + maxSize.height; + } + + return frame; +} + +// AlignInFrame +void +BLayoutUtils::AlignInFrame(BView* view, BRect frame) +{ +// TODO:... +// BSize maxSize = view->MaxSize(); +// BAlignment alignment = view->Alignment(); +// +// if (view->HasHeightForWidth()) { +// // The view has height for width, so we do the horizontal alignment +// // ourselves and restrict the height max constraint respectively. +// +// if (maxSize.width < frame.width +// && alignment.horizontal != B_ALIGN_USE_FULL_WIDTH) { +// frame.x += (int)((frame.width - maxSize.width) +// * alignment.RelativeHorizontal()); +// frame.width = maxSize.width; +// } +// alignment.horizontal = BAlignment.B_ALIGN_USE_FULL_WIDTH; +// +// float minHeight; +// float maxHeight; +// float preferredHeight; +// view->GetHeightForWidth(frame.width, &minHeight, &maxHeight, +// &preferredHeight); +// +// frame.height = max_c(frame.height, info.min); +// maxSize.height = minHeight; +// } +// +// frame = AlignInFrame(frame, maxSize, alignment); +// view->SetLocation(frame.x, frame.y); +// view->SetSize(frame.getSize()); +} + diff --git a/src/kits/interface/ListView.cpp b/src/kits/interface/ListView.cpp index 1de8563c18..c49999aff4 100644 --- a/src/kits/interface/ListView.cpp +++ b/src/kits/interface/ListView.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -1092,6 +1093,24 @@ BListView::AllDetached() BView::AllDetached(); } +BSize +BListView::MinSize() +{ + // We need a stable min size: the BView implementation uses + // GetPreferredSize(), which by default just returns the current size. + return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(10, 10)); +} + + +BSize +BListView::PreferredSize() +{ + // We need a stable preferred size: the BView implementation uses + // GetPreferredSize(), which by default just returns the current size. + return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), BSize(100, 50)); +} + + // DoMiscellaneous bool BListView::DoMiscellaneous(MiscCode code, MiscData *data) diff --git a/src/kits/interface/MenuBar.cpp b/src/kits/interface/MenuBar.cpp index 95e4dc73e7..9c25160e42 100644 --- a/src/kits/interface/MenuBar.cpp +++ b/src/kits/interface/MenuBar.cpp @@ -7,9 +7,11 @@ * Stefano Ceccherini (burton666@libero.it) */ +#include + #include #include -#include +#include #include #include @@ -297,6 +299,21 @@ BMenuBar::Perform(perform_code d, void *arg) } +BSize +BMenuBar::MaxSize() +{ + // TODO: cache the result + float width, height; + GetPreferredSize(&width, &height); + + return BLayoutUtils::ComposeSize(ExplicitMaxSize(), + BSize(B_SIZE_UNLIMITED, height)); +} + + +// #pragma mark - + + void BMenuBar::_ReservedMenuBar1() {} void BMenuBar::_ReservedMenuBar2() {} void BMenuBar::_ReservedMenuBar3() {} diff --git a/src/kits/interface/MenuField.cpp b/src/kits/interface/MenuField.cpp index 4fa556ee30..b91590d682 100644 --- a/src/kits/interface/MenuField.cpp +++ b/src/kits/interface/MenuField.cpp @@ -5,11 +5,14 @@ * Authors: * Marc Flerackers (mflerackers@androme.be) * Stephan Aßmus + * Ingo Weinhold */ #include #include +#include +#include #include #include #include @@ -17,6 +20,55 @@ #include +class BMenuField::LabelLayoutItem : public BAbstractLayoutItem { +public: + LabelLayoutItem(BMenuField* parent); + + virtual bool IsVisible(); + virtual void SetVisible(bool visible); + + virtual BRect Frame(); + virtual void SetFrame(BRect frame); + + virtual BView* View(); + + virtual BSize BaseMinSize(); + virtual BSize BaseMaxSize(); + virtual BSize BasePreferredSize(); + virtual BAlignment BaseAlignment(); + +private: + BMenuField* fParent; + BRect fFrame; +}; + + +class BMenuField::MenuBarLayoutItem : public BAbstractLayoutItem { +public: + MenuBarLayoutItem(BMenuField* parent); + + virtual bool IsVisible(); + virtual void SetVisible(bool visible); + + virtual BRect Frame(); + virtual void SetFrame(BRect frame); + + virtual BView* View(); + + virtual BSize BaseMinSize(); + virtual BSize BaseMaxSize(); + virtual BSize BasePreferredSize(); + virtual BAlignment BaseAlignment(); + +private: + BMenuField* fParent; + BRect fFrame; +}; + + +// #pragma mark - + + static float kVMargin = 2.0f; @@ -25,19 +77,9 @@ BMenuField::BMenuField(BRect frame, const char *name, const char *label, : BView(frame, name, resize, flags) { InitObject(label); - SetFont(be_plain_font); - fMenu = menu; - InitMenu(menu); frame.OffsetTo(B_ORIGIN); - fMenuBar = new _BMCMenuBar_(BRect(frame.left + fDivider + 1, - frame.top + kVMargin, frame.right, frame.bottom - kVMargin), - false, this); - - AddChild(fMenuBar); - fMenuBar->AddItem(menu); - - fMenuBar->SetFont(be_plain_font); + _InitMenuBar(menu, frame, false); InitObject2(); } @@ -48,21 +90,37 @@ BMenuField::BMenuField(BRect frame, const char *name, const char *label, : BView(frame, name, resize, flags) { InitObject(label); - SetFont(be_plain_font); - fMenu = menu; - InitMenu(menu); fFixedSizeMB = fixedSize; frame.OffsetTo(B_ORIGIN); - fMenuBar = new _BMCMenuBar_(BRect(frame.left + fDivider + 1, - frame.top + kVMargin, frame.right, frame.bottom - kVMargin), - fixedSize, this); + _InitMenuBar(menu, frame, fixedSize); - AddChild(fMenuBar); - fMenuBar->AddItem(menu); + InitObject2(); +} - fMenuBar->SetFont(be_plain_font); + +BMenuField::BMenuField(const char* name, const char* label, BMenu* menu, + BMessage* message, uint32 flags) + : BView(BRect(0, 0, -1, -1), name, B_FOLLOW_NONE, + flags | B_FRAME_EVENTS | B_SUPPORTS_LAYOUT) +{ + InitObject(label); + + _InitMenuBar(menu, BRect(0, 0, 100, 15), false); + + InitObject2(); +} + + +BMenuField::BMenuField(const char* label, + BMenu* menu, BMessage* message) + : BView(BRect(0, 0, -1, -1), NULL, B_FOLLOW_NONE, + B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS | B_SUPPORTS_LAYOUT) +{ + InitObject(label); + + _InitMenuBar(menu, BRect(0, 0, 100, 15), false); InitObject2(); } @@ -371,6 +429,8 @@ BMenuField::SetLabel(const char *label) if (fLabel) fStringWidth = StringWidth(fLabel); } + + InvalidateLayout(); } @@ -430,8 +490,23 @@ BMenuField::SetDivider(float divider) fDivider = divider; - MenuBar()->MoveBy(-dx, 0.0f); - MenuBar()->ResizeBy(dx, 0.0f); + BRect dirty(fMenuBar->Frame()); + + fMenuBar->MoveTo(fDivider + 1, kVMargin); + + if (fFixedSizeMB) { + fMenuBar->ResizeTo(Bounds().Width() - fDivider + 1 - 2, + dirty.Height()); + } + + dirty = dirty | fMenuBar->Frame(); + + dirty.left -= 1; + dirty.top -= 1; + dirty.right += 2; + dirty.bottom += 2; + + Invalidate(dirty); } @@ -525,6 +600,24 @@ BMenuField::GetPreferredSize(float *_width, float *_height) } +BLayoutItem* +BMenuField::CreateLabelLayoutItem() +{ + if (!fLabelLayoutItem) + fLabelLayoutItem = new LabelLayoutItem(this); + return fLabelLayoutItem; +} + + +BLayoutItem* +BMenuField::CreateMenuBarLayoutItem() +{ + if (!fMenuBarLayoutItem) + fMenuBarLayoutItem = new MenuBarLayoutItem(this); + return fMenuBarLayoutItem; +} + + status_t BMenuField::Perform(perform_code d, void *arg) { @@ -557,6 +650,8 @@ BMenuField::InitObject(const char *label) fTransition = false; fFixedSizeMB = false; fMenuTaskID = -1; + fLabelLayoutItem = NULL; + fMenuBarLayoutItem = NULL; SetLabel(label); @@ -662,3 +757,206 @@ BMenuField::MenuTask(void *arg) return 0; } + +void +BMenuField::_UpdateFrame() +{ + if (fLabelLayoutItem && fMenuBarLayoutItem) { + BRect labelFrame = fLabelLayoutItem->Frame(); + BRect menuFrame = fMenuBarLayoutItem->Frame(); + MoveTo(labelFrame.left, labelFrame.top); + ResizeTo(menuFrame.left + menuFrame.Width() - labelFrame.left, + menuFrame.top + menuFrame.Height() - labelFrame.top); + SetDivider(menuFrame.left - labelFrame.left); + } +} + + +void +BMenuField::_InitMenuBar(BMenu* menu, BRect frame, bool fixedSize) +{ + fMenu = menu; + InitMenu(menu); + + fMenuBar = new _BMCMenuBar_(BRect(frame.left + fDivider + 1, + frame.top + kVMargin, frame.right, frame.bottom - kVMargin), + fixedSize, this); + + AddChild(fMenuBar); + fMenuBar->AddItem(menu); + + fMenuBar->SetFont(be_plain_font); +} + + +// #pragma mark - + + +BMenuField::LabelLayoutItem::LabelLayoutItem(BMenuField* parent) + : fParent(parent), + fFrame() +{ +} + + +bool +BMenuField::LabelLayoutItem::IsVisible() +{ + return !fParent->IsHidden(fParent); +} + + +void +BMenuField::LabelLayoutItem::SetVisible(bool visible) +{ + // not allowed +} + + +BRect +BMenuField::LabelLayoutItem::Frame() +{ + return fFrame; +} + + +void +BMenuField::LabelLayoutItem::SetFrame(BRect frame) +{ + fFrame = frame; + fParent->_UpdateFrame(); +} + + +BView* +BMenuField::LabelLayoutItem::View() +{ + return fParent; +} + + +BSize +BMenuField::LabelLayoutItem::BaseMinSize() +{ +// TODO: Cache the info. Might be too expensive for this call. + const char* label = fParent->Label(); + if (!label) + return BSize(-1, -1); + + BSize size; + fParent->GetPreferredSize(NULL, &size.height); + + size.width = fParent->StringWidth(label) + 2 * 3 - 1; + + return size; +} + + +BSize +BMenuField::LabelLayoutItem::BaseMaxSize() +{ + return BaseMinSize(); +} + + +BSize +BMenuField::LabelLayoutItem::BasePreferredSize() +{ + return BaseMinSize(); +} + + +BAlignment +BMenuField::LabelLayoutItem::BaseAlignment() +{ + return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); +} + + +// #pragma mark - + + +BMenuField::MenuBarLayoutItem::MenuBarLayoutItem(BMenuField* parent) + : fParent(parent), + fFrame() +{ +} + + +bool +BMenuField::MenuBarLayoutItem::IsVisible() +{ + return !fParent->IsHidden(fParent); +} + + +void +BMenuField::MenuBarLayoutItem::SetVisible(bool visible) +{ + // not allowed +} + + +BRect +BMenuField::MenuBarLayoutItem::Frame() +{ + return fFrame; +} + + +void +BMenuField::MenuBarLayoutItem::SetFrame(BRect frame) +{ + fFrame = frame; + fParent->_UpdateFrame(); +} + + +BView* +BMenuField::MenuBarLayoutItem::View() +{ + return fParent; +} + + +BSize +BMenuField::MenuBarLayoutItem::BaseMinSize() +{ +// TODO: Cache the info. Might be too expensive for this call. + BSize size; + fParent->fMenuBar->GetPreferredSize(&size.width, &size.height); + + // BMenuField draws additional lines around BMenuBar, + // one line on left and top side, two on right and bottom + size.width += 3; + size.height += 3; + + return size; +} + + +BSize +BMenuField::MenuBarLayoutItem::BaseMaxSize() +{ + BSize size(BaseMinSize()); + size.width = B_SIZE_UNLIMITED; + return size; +} + + +BSize +BMenuField::MenuBarLayoutItem::BasePreferredSize() +{ + BSize size(BaseMinSize()); + // puh, no idea... + size.width = 100; + return size; +} + + +BAlignment +BMenuField::MenuBarLayoutItem::BaseAlignment() +{ + return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); +} + diff --git a/src/kits/interface/RadioButton.cpp b/src/kits/interface/RadioButton.cpp index 8cfb7dcb88..b3523442e2 100644 --- a/src/kits/interface/RadioButton.cpp +++ b/src/kits/interface/RadioButton.cpp @@ -13,10 +13,11 @@ "multiple choice" control. */ +#include #include #include -#include +#include #include @@ -35,6 +36,35 @@ BRadioButton::BRadioButton(BRect frame, const char *name, const char *label, } +BRadioButton::BRadioButton(const char *name, const char *label, + BMessage *message, uint32 flags) + : BControl(BRect(0, 0, -1, -1), name, label, message, B_FOLLOW_NONE, + flags | B_SUPPORTS_LAYOUT), + fOutlined(false) +{ + // Resize to minimum height if needed + font_height fontHeight; + GetFontHeight(&fontHeight); + float minHeight = ceilf(6.0f + fontHeight.ascent + fontHeight.descent); + if (Bounds().Height() < minHeight) + ResizeTo(Bounds().Width(), minHeight); +} + + +BRadioButton::BRadioButton(const char *label, BMessage *message) + : BControl(BRect(0, 0, -1, -1), NULL, label, message, B_FOLLOW_NONE, + B_WILL_DRAW | B_NAVIGABLE | B_SUPPORTS_LAYOUT), + fOutlined(false) +{ + // Resize to minimum height if needed + font_height fontHeight; + GetFontHeight(&fontHeight); + float minHeight = ceilf(6.0f + fontHeight.ascent + fontHeight.descent); + if (Bounds().Height() < minHeight) + ResizeTo(Bounds().Width(), minHeight); +} + + BRadioButton::BRadioButton(BMessage *archive) : BControl(archive), fOutlined(false) @@ -466,6 +496,19 @@ BRadioButton::Perform(perform_code d, void *arg) } +BSize +BRadioButton::MaxSize() +{ + float width, height; + GetPreferredSize(&width, &height); + + return BLayoutUtils::ComposeSize(ExplicitMaxSize(), + BSize(B_SIZE_UNLIMITED, height)); +} + + + + void BRadioButton::_ReservedRadioButton1() {} void BRadioButton::_ReservedRadioButton2() {} diff --git a/src/kits/interface/ScrollView.cpp b/src/kits/interface/ScrollView.cpp index a8153dd570..6318571fa4 100644 --- a/src/kits/interface/ScrollView.cpp +++ b/src/kits/interface/ScrollView.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include @@ -594,6 +595,44 @@ BScrollView::GetSupportedSuites(BMessage *data) } +BSize +BScrollView::MinSize() +{ +// TODO: This is not yet correct. + BSize size = (fTarget ? fTarget->MinSize() : BSize(-1, -1)); + + if (fVerticalScrollBar) + size.width += B_V_SCROLL_BAR_WIDTH; + if (fHorizontalScrollBar) + size.height += B_H_SCROLL_BAR_HEIGHT; + + float borderSize = BorderSize(fBorder); + size.width += 2 * borderSize; + size.height += 2 * borderSize; + + return BLayoutUtils::ComposeSize(ExplicitMinSize(), size); +} + + +BSize +BScrollView::PreferredSize() +{ +// TODO: This is not yet correct. + BSize size = (fTarget ? fTarget->PreferredSize() : BSize(-1, -1)); + + if (fVerticalScrollBar) + size.width += B_V_SCROLL_BAR_WIDTH; + if (fHorizontalScrollBar) + size.height += B_H_SCROLL_BAR_HEIGHT; + + float borderSize = BorderSize(fBorder); + size.width += 2 * borderSize; + size.height += 2 * borderSize; + + return BLayoutUtils::ComposeSize(ExplicitMinSize(), size); +} + + status_t BScrollView::Perform(perform_code d, void *arg) { diff --git a/src/kits/interface/Size.cpp b/src/kits/interface/Size.cpp new file mode 100644 index 0000000000..bbd1628acf --- /dev/null +++ b/src/kits/interface/Size.cpp @@ -0,0 +1,8 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +// completely implemented inline diff --git a/src/kits/interface/SpaceLayoutItem.cpp b/src/kits/interface/SpaceLayoutItem.cpp new file mode 100644 index 0000000000..3d2e0c758c --- /dev/null +++ b/src/kits/interface/SpaceLayoutItem.cpp @@ -0,0 +1,158 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + + +// constructor +BSpaceLayoutItem::BSpaceLayoutItem(BSize minSize, BSize maxSize, + BSize preferredSize, BAlignment alignment) + : fFrame(), + fMinSize(minSize), + fMaxSize(maxSize), + fPreferredSize(preferredSize), + fAlignment(alignment), + fVisible(true) +{ +} + +// destructor +BSpaceLayoutItem::~BSpaceLayoutItem() +{ +} + +// CreateGlue +BSpaceLayoutItem* +BSpaceLayoutItem::CreateGlue() { + return new BSpaceLayoutItem( + BSize(-1, -1), + BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED), + BSize(-1, -1), + BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)); +} + +// CreateHorizontalStrut +BSpaceLayoutItem* +BSpaceLayoutItem::CreateHorizontalStrut(float width) { + return new BSpaceLayoutItem( + BSize(width, -1), + BSize(width, B_SIZE_UNLIMITED), + BSize(width, -1), + BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)); +} + +// CreateVerticalStrut +BSpaceLayoutItem* +BSpaceLayoutItem::CreateVerticalStrut(float height) { + return new BSpaceLayoutItem( + BSize(-1, height), + BSize(B_SIZE_UNLIMITED, height), + BSize(-1, height), + BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)); +} + +// MinSize +BSize +BSpaceLayoutItem::MinSize() +{ + return fMinSize; +} + +// MaxSize +BSize +BSpaceLayoutItem::MaxSize() +{ + return fMaxSize; +} + +// PreferredSize +BSize +BSpaceLayoutItem::PreferredSize() +{ + return fPreferredSize; +} + +// Alignment +BAlignment +BSpaceLayoutItem::Alignment() +{ + return fAlignment; +} + +// SetExplicitMinSize +void +BSpaceLayoutItem::SetExplicitMinSize(BSize size) +{ + if (size.IsWidthSet()) + fMinSize.width = size.width; + if (size.IsHeightSet()) + fMinSize.height = size.height; + + InvalidateLayout(); +} + +// SetExplicitMaxSize +void +BSpaceLayoutItem::SetExplicitMaxSize(BSize size) +{ + if (size.IsWidthSet()) + fMaxSize.width = size.width; + if (size.IsHeightSet()) + fMaxSize.height = size.height; + + InvalidateLayout(); +} + +// SetExplicitPreferredSize +void +BSpaceLayoutItem::SetExplicitPreferredSize(BSize size) +{ + if (size.IsWidthSet()) + fPreferredSize.width = size.width; + if (size.IsHeightSet()) + fPreferredSize.height = size.height; + + InvalidateLayout(); +} + +// SetExplicitAlignment +void +BSpaceLayoutItem::SetExplicitAlignment(BAlignment alignment) +{ + if (alignment.IsHorizontalSet()) + fAlignment.horizontal = alignment.horizontal; + if (alignment.IsVerticalSet()) + fAlignment.vertical = alignment.vertical; + + InvalidateLayout(); +} + +// IsVisible +bool +BSpaceLayoutItem::IsVisible() +{ + return fVisible; +} + +// SetVisible +void +BSpaceLayoutItem::SetVisible(bool visible) +{ + fVisible = visible; +} + +// Frame +BRect +BSpaceLayoutItem::Frame() +{ + return fFrame; +} + +// SetFrame +void +BSpaceLayoutItem::SetFrame(BRect frame) +{ + fFrame = frame; +} diff --git a/src/kits/interface/SplitLayout.cpp b/src/kits/interface/SplitLayout.cpp new file mode 100644 index 0000000000..d62d5d23f7 --- /dev/null +++ b/src/kits/interface/SplitLayout.cpp @@ -0,0 +1,1264 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include + +#include +#include +#include + +#include "OneElementLayouter.h" +#include "SimpleLayouter.h" + +// ItemLayoutInfo +class BSplitLayout::ItemLayoutInfo { +public: + float weight; + BRect layoutFrame; + BSize min; + BSize max; + bool isVisible; + bool isCollapsible; + + ItemLayoutInfo() + : weight(1.0f), + layoutFrame(0, 0, -1, -1), + min(), + max(), + isVisible(true), + isCollapsible(true) + { + } +}; + +// ValueRange +class BSplitLayout::ValueRange { +public: + int32 sumValue; // including spacing + int32 previousMin; + int32 previousMax; + int32 previousSize; + int32 nextMin; + int32 nextMax; + int32 nextSize; +}; + +// SplitterItem +class BSplitLayout::SplitterItem : public BLayoutItem { +public: + SplitterItem(BSplitLayout* layout) + : fLayout(layout), + fFrame() + { + } + + virtual BSize MinSize() + { + if (fLayout->Orientation() == B_HORIZONTAL) + return BSize(fLayout->SplitterSize() - 1, -1); + else + return BSize(-1, fLayout->SplitterSize() - 1); + } + + virtual BSize MaxSize() + { + if (fLayout->Orientation() == B_HORIZONTAL) + return BSize(fLayout->SplitterSize() - 1, B_SIZE_UNLIMITED); + else + return BSize(B_SIZE_UNLIMITED, fLayout->SplitterSize() - 1); + } + + virtual BSize PreferredSize() + { + return MinSize(); + } + + virtual BAlignment Alignment() + { + return BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER); + } + + virtual void SetExplicitMinSize(BSize size) + { + // not allowed + } + + virtual void SetExplicitMaxSize(BSize size) + { + // not allowed + } + + virtual void SetExplicitPreferredSize(BSize size) + { + // not allowed + } + + virtual void SetExplicitAlignment(BAlignment alignment) + { + // not allowed + } + + virtual bool IsVisible() + { + return true; + } + + virtual void SetVisible(bool visible) + { + // not allowed + } + + + virtual BRect Frame() + { + return fFrame; + } + + virtual void SetFrame(BRect frame) + { + fFrame = frame; + } + +private: + BSplitLayout* fLayout; + BRect fFrame; +}; + + +// #pragma mark - + + +// constructor +BSplitLayout::BSplitLayout(enum orientation orientation, + float spacing) + : fOrientation(orientation), + fLeftInset(0), + fRightInset(0), + fTopInset(0), + fBottomInset(0), + fSplitterSize(3), + fSpacing(spacing), + + fSplitterItems(), + fVisibleItems(), + fMin(), + fMax(), + fPreferred(), + + fHorizontalLayouter(NULL), + fVerticalLayouter(NULL), + fHorizontalLayoutInfo(NULL), + fVerticalLayoutInfo(NULL), + + fHeightForWidthItems(), + fHeightForWidthVerticalLayouter(NULL), + fHeightForWidthHorizontalLayoutInfo(NULL), + + fLayoutValid(false), + + fCachedHeightForWidthWidth(-2), + fHeightForWidthVerticalLayouterWidth(-2), + fCachedMinHeightForWidth(-1), + fCachedMaxHeightForWidth(-1), + fCachedPreferredHeightForWidth(-1), + + fDraggingStartPoint(), + fDraggingStartValue(0), + fDraggingCurrentValue(0), + fDraggingSplitterIndex(-1) +{ +} + +// destructor +BSplitLayout::~BSplitLayout() +{ +} + +// SetInsets +void +BSplitLayout::SetInsets(float left, float top, float right, float bottom) +{ + fLeftInset = left; + fTopInset = top; + fRightInset = right; + fBottomInset = bottom; + + InvalidateLayout(); +} + +// GetInsets +void +BSplitLayout::GetInsets(float* left, float* top, float* right, float* bottom) +{ + if (left) + *left = fLeftInset; + if (top) + *top = fTopInset; + if (right) + *right = fRightInset; + if (bottom) + *bottom = fBottomInset; +} + +// Spacing +float +BSplitLayout::Spacing() const +{ + return fSpacing; +} + +// SetSpacing +void +BSplitLayout::SetSpacing(float spacing) +{ + if (spacing != fSpacing) { + fSpacing = spacing; + + InvalidateLayout(); + } +} + +// Orientation +orientation +BSplitLayout::Orientation() const +{ + return fOrientation; +} + +// SetOrientation +void +BSplitLayout::SetOrientation(enum orientation orientation) +{ + if (orientation != fOrientation) { + fOrientation = orientation; + + InvalidateLayout(); + } +} + +// SplitterSize +float +BSplitLayout::SplitterSize() const +{ + return fSplitterSize; +} + +// SetSplitterSize +void +BSplitLayout::SetSplitterSize(float size) +{ + if (size != fSplitterSize) { + fSplitterSize = size; + + InvalidateLayout(); + } +} + +// AddView +BLayoutItem* +BSplitLayout::AddView(BView* child) +{ + return BLayout::AddView(child); +} + +// AddView +BLayoutItem* +BSplitLayout::AddView(int32 index, BView* child) +{ + return BLayout::AddView(index, child); +} + +// AddView +BLayoutItem* +BSplitLayout::AddView(BView* child, float weight) +{ + return AddView(-1, child, weight); +} + +// AddView +BLayoutItem* +BSplitLayout::AddView(int32 index, BView* child, float weight) +{ + BLayoutItem* item = AddView(index, child); + if (item) + SetItemWeight(item, weight); + + return item; +} + +// AddItem +bool +BSplitLayout::AddItem(BLayoutItem* item) +{ + return BLayout::AddItem(item); +} + +// AddItem +bool +BSplitLayout::AddItem(int32 index, BLayoutItem* item) +{ + return BLayout::AddItem(index, item); +} + +// AddItem +bool +BSplitLayout::AddItem(BLayoutItem* item, float weight) +{ + return AddItem(-1, item, weight); +} + +// AddItem +bool +BSplitLayout::AddItem(int32 index, BLayoutItem* item, float weight) +{ + bool success = AddItem(index, item); + if (success) + SetItemWeight(item, weight); + + return success; +} + +// ItemWeight +float +BSplitLayout::ItemWeight(int32 index) const +{ + if (index < 0 || index >= CountItems()) + return 0; + + return ItemWeight(ItemAt(index)); +} + +// ItemWeight +float +BSplitLayout::ItemWeight(BLayoutItem* item) const +{ + if (ItemLayoutInfo* info = _ItemLayoutInfo(item)) + return info->weight; + return 0; +} + +// SetItemWeight +void +BSplitLayout::SetItemWeight(int32 index, float weight, bool invalidateLayout) +{ + if (index < 0 || index >= CountItems()) + return; + + BLayoutItem* item = ItemAt(index); + SetItemWeight(item, weight); + + if (fHorizontalLayouter) { + int32 visibleIndex = fVisibleItems.IndexOf(item); + if (visibleIndex >= 0) { + if (fOrientation == B_HORIZONTAL) + fHorizontalLayouter->SetWeight(visibleIndex, weight); + else + fVerticalLayouter->SetWeight(visibleIndex, weight); + } + } + + if (invalidateLayout) + InvalidateLayout(); +} + +// SetItemWeight +void +BSplitLayout::SetItemWeight(BLayoutItem* item, float weight) +{ + if (ItemLayoutInfo* info = _ItemLayoutInfo(item)) + info->weight = weight; +} + +// SetCollapsible +void +BSplitLayout::SetCollapsible(bool collapsible) +{ + SetCollapsible(0, CountItems() - 1, collapsible); +} + +// SetCollapsible +void +BSplitLayout::SetCollapsible(int32 index, bool collapsible) +{ + SetCollapsible(index, index, collapsible); +} + +// SetCollapsible +void +BSplitLayout::SetCollapsible(int32 first, int32 last, bool collapsible) +{ + if (first < 0) + first = 0; + if (last < 0 || last > CountItems()) + last = CountItems() - 1; + + for (int32 i = first; i <= last; i++) + _ItemLayoutInfo(ItemAt(i))->isCollapsible = collapsible; +} + +// MinSize +BSize +BSplitLayout::MinSize() +{ + _ValidateMinMax(); + + return _AddInsets(fMin); +} + +// MaxSize +BSize +BSplitLayout::MaxSize() +{ + _ValidateMinMax(); + + return _AddInsets(fMax); +} + +// PreferredSize +BSize +BSplitLayout::PreferredSize() +{ + _ValidateMinMax(); + + return _AddInsets(fPreferred); +} + +// Alignment +BAlignment +BSplitLayout::Alignment() +{ + return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); +} + +// HasHeightForWidth +bool +BSplitLayout::HasHeightForWidth() +{ + _ValidateMinMax(); + + return !fHeightForWidthItems.IsEmpty(); +} + +// GetHeightForWidth +void +BSplitLayout::GetHeightForWidth(float width, float* min, float* max, + float* preferred) +{ + if (!HasHeightForWidth()) + return; + + float innerWidth = _SubtractInsets(BSize(width, 0)).width; + _InternalGetHeightForWidth(innerWidth, false, min, max, preferred); + _AddInsets(min, max, preferred); +} + +// InvalidateLayout +void +BSplitLayout::InvalidateLayout() +{ + _InvalidateLayout(true); +} + +// LayoutView +void +BSplitLayout::LayoutView() +{ + _ValidateMinMax(); + + // layout the elements + BSize size = _SubtractInsets(BSize(View()->Bounds())); + fHorizontalLayouter->Layout(fHorizontalLayoutInfo, size.width); + + Layouter* verticalLayouter; + if (HasHeightForWidth()) { + float minHeight, maxHeight, preferredHeight; + _InternalGetHeightForWidth(size.width, true, &minHeight, &maxHeight, + &preferredHeight); + size.height = max_c(size.height, minHeight); + verticalLayouter = fHeightForWidthVerticalLayouter; + } else + verticalLayouter = fVerticalLayouter; + + verticalLayouter->Layout(fVerticalLayoutInfo, size.height); + + float xOffset = fLeftInset; + float yOffset = fTopInset; + float splitterWidth = 0; // pixel counts, no distances + float splitterHeight = 0; // + float xSpacing = 0; + float ySpacing = 0; + if (fOrientation == B_HORIZONTAL) { + splitterWidth = fSplitterSize; + splitterHeight = size.height + 1; + xSpacing = fSpacing; + } else { + splitterWidth = size.width + 1; + splitterHeight = fSplitterSize; + ySpacing = fSpacing; + } + + int itemCount = CountItems(); + for (int i = 0; i < itemCount; i++) { + // layout the splitter + if (i > 0) { + SplitterItem* splitterItem = _SplitterItemAt(i - 1); + + _LayoutItem(splitterItem, BRect(xOffset, yOffset, + xOffset + splitterWidth - 1, yOffset + splitterHeight - 1), + true); + + if (fOrientation == B_HORIZONTAL) + xOffset += splitterWidth + xSpacing; + else + yOffset += splitterHeight + ySpacing; + } + + // layout the item + BLayoutItem* item = ItemAt(i); + int32 visibleIndex = fVisibleItems.IndexOf(item); + if (visibleIndex < 0) { + _LayoutItem(item, BRect(), false); + continue; + } + + // get the dimensions of the item + float width = fHorizontalLayoutInfo->ElementSize(visibleIndex); + float height = fVerticalLayoutInfo->ElementSize(visibleIndex); + + // place the component + _LayoutItem(item, BRect(xOffset, yOffset, xOffset + width, + yOffset + height), true); + + if (fOrientation == B_HORIZONTAL) + xOffset += width + xSpacing + 1; + else + yOffset += height + ySpacing + 1; + } + + fLayoutValid = true; +} + +// SplitterItemFrame +BRect +BSplitLayout::SplitterItemFrame(int32 index) const +{ + if (SplitterItem* item = _SplitterItemAt(index)) + return item->Frame(); + return BRect(); +} + +// StartDraggingSplitter +bool +BSplitLayout::StartDraggingSplitter(BPoint point) +{ + StopDraggingSplitter(); + + // Layout must be valid. Bail out, if it isn't. + if (!fLayoutValid) + return false; + + // Things shouldn't be draggable, if we have a >= max layout. + BSize size = _SubtractInsets(BSize(View()->Frame())); + if (fOrientation == B_HORIZONTAL && size.width >= fMax.width + || fOrientation == B_VERTICAL && size.height >= fMax.height) { + return false; + } + + int32 splitterCount = fSplitterItems.CountItems(); + for (int32 i = 0; i < splitterCount; i++) { + SplitterItem* splitItem = _SplitterItemAt(i); + BRect frame = splitItem->Frame(); + if (frame.Contains(point)) { + fDraggingStartPoint = View()->ConvertToScreen(point); + fDraggingStartValue = _SplitterValue(i); + fDraggingCurrentValue = fDraggingStartValue; + fDraggingSplitterIndex = i; + + return true; + } + } + + return false; +} + +// DragSplitter +bool +BSplitLayout::DragSplitter(BPoint point) +{ + if (fDraggingSplitterIndex < 0) + return false; + + point = View()->ConvertToScreen(point); + + int32 valueDiff; + if (fOrientation == B_HORIZONTAL) + valueDiff = int32(point.x - fDraggingStartPoint.x); + else + valueDiff = int32(point.y - fDraggingStartPoint.y); + + return _SetSplitterValue(fDraggingSplitterIndex, + fDraggingStartValue + valueDiff); +} + +// StopDraggingSplitter +bool +BSplitLayout::StopDraggingSplitter() +{ + if (fDraggingSplitterIndex < 0) + return false; + + // update the item weights + _UpdateSplitterWeights(); + + fDraggingSplitterIndex = -1; + + return true; +} + +// DraggedSplitter +int32 +BSplitLayout::DraggedSplitter() const +{ + return fDraggingSplitterIndex; +} + +// ItemAdded +void +BSplitLayout::ItemAdded(BLayoutItem* item) +{ + if (CountItems() > 1) { + SplitterItem* splitterItem = new SplitterItem(this); + SetItemWeight(splitterItem, 0); + fSplitterItems.AddItem(splitterItem); + } + + SetItemWeight(item, 1); +} + +// ItemRemoved +void +BSplitLayout::ItemRemoved(BLayoutItem* item) +{ + if (fSplitterItems.CountItems() > 0) { + SplitterItem* splitterItem = (SplitterItem*)fSplitterItems.RemoveItem( + fSplitterItems.CountItems() - 1); + delete (ItemLayoutInfo*)splitterItem->LayoutData(); + delete splitterItem; + } + + delete (ItemLayoutInfo*)item->LayoutData(); + item->SetLayoutData(NULL); +} + +// _InvalidateLayout +void +BSplitLayout::_InvalidateLayout(bool invalidateView) +{ + if (invalidateView) + BLayout::InvalidateLayout(); + + delete fHorizontalLayouter; + delete fVerticalLayouter; + delete fHorizontalLayoutInfo; + delete fVerticalLayoutInfo; + + fHorizontalLayouter = NULL; + fVerticalLayouter = NULL; + fHorizontalLayoutInfo = NULL; + fVerticalLayoutInfo = NULL; + + _InvalidateCachedHeightForWidth(); + + fLayoutValid = false; +} + +// _InvalidateCachedHeightForWidth +void +BSplitLayout::_InvalidateCachedHeightForWidth() +{ + delete fHeightForWidthVerticalLayouter; + delete fHeightForWidthHorizontalLayoutInfo; + + fHeightForWidthVerticalLayouter = NULL; + fHeightForWidthHorizontalLayoutInfo = NULL; + + fCachedHeightForWidthWidth = -2; + fHeightForWidthVerticalLayouterWidth = -2; +} + +// _SplitterItemAt +BSplitLayout::SplitterItem* +BSplitLayout::_SplitterItemAt(int32 index) const +{ + return (SplitterItem*)fSplitterItems.ItemAt(index); +} + +// _GetSplitterValueRange +void +BSplitLayout::_GetSplitterValueRange(int32 index, ValueRange& range) +{ + ItemLayoutInfo* previousInfo = _ItemLayoutInfo(ItemAt(index)); + ItemLayoutInfo* nextInfo = _ItemLayoutInfo(ItemAt(index + 1)); + if (fOrientation == B_HORIZONTAL) { + range.previousMin = (int32)previousInfo->min.width + 1; + range.previousMax = (int32)previousInfo->max.width + 1; + range.previousSize = previousInfo->layoutFrame.IntegerWidth() + 1; + range.nextMin = (int32)nextInfo->min.width + 1; + range.nextMax = (int32)nextInfo->max.width + 1; + range.nextSize = nextInfo->layoutFrame.IntegerWidth() + 1; + } else { + range.previousMin = (int32)previousInfo->min.height + 1; + range.previousMax = (int32)previousInfo->max.height + 1; + range.previousSize = previousInfo->layoutFrame.IntegerHeight() + 1; + range.nextMin = (int32)nextInfo->min.height + 1; + range.nextMax = (int32)nextInfo->max.height + 1; + range.nextSize = (int32)nextInfo->layoutFrame.IntegerHeight() + 1; + } + + range.sumValue = range.previousSize + range.nextSize; + if (previousInfo->isVisible) + range.sumValue += (int32)fSpacing; + if (nextInfo->isVisible) + range.sumValue += (int32)fSpacing; +} + +// _SplitterValue +int32 +BSplitLayout::_SplitterValue(int32 index) const +{ + ItemLayoutInfo* info = _ItemLayoutInfo(ItemAt(index)); + if (info && info->isVisible) { + if (fOrientation == B_HORIZONTAL) + return info->layoutFrame.IntegerWidth() + 1 + (int32)fSpacing; + else + return info->layoutFrame.IntegerHeight() + 1 + (int32)fSpacing; + } else + return 0; +} + +// _LayoutItem +void +BSplitLayout::_LayoutItem(BLayoutItem* item, BRect frame, bool visible) +{ + // update the layout frame + ItemLayoutInfo* info = _ItemLayoutInfo(item); + info->isVisible = visible; + if (visible) + info->layoutFrame = frame; + else + info->layoutFrame = BRect(0, 0, -1, -1); + + // update min/max + info->min = item->MinSize(); + info->max = item->MaxSize(); + + if (item->HasHeightForWidth()) { + BSize size = _SubtractInsets(BSize(View()->Frame())); + float minHeight, maxHeight; + item->GetHeightForWidth(size.width, &minHeight, &maxHeight, NULL); + info->min.height = max_c(info->min.height, minHeight); + info->max.height = min_c(info->max.height, maxHeight); + } + + // layout the item + if (visible) + item->AlignInFrame(frame); +} + +// _LayoutItem +void +BSplitLayout::_LayoutItem(BLayoutItem* item, ItemLayoutInfo* info) +{ + // update the visibility of the item + bool isVisible = item->IsVisible(); + bool visibilityChanged = (info->isVisible != isVisible); + if (visibilityChanged) + item->SetVisible(info->isVisible); + + // nothing more to do, if the item is not visible + if (!info->isVisible) + return; + + item->AlignInFrame(info->layoutFrame); + + // if the item became visible, we need to update its internal layout + if (visibilityChanged) { + if (BView* itemView = item->View()) + itemView->Layout(false); + } +} + +// _SetSplitterValue +bool +BSplitLayout::_SetSplitterValue(int32 index, int32 value) +{ + // if both items are collapsed, nothing can be dragged + BLayoutItem* previousItem = ItemAt(index); + BLayoutItem* nextItem = ItemAt(index + 1); + ItemLayoutInfo* previousInfo = _ItemLayoutInfo(previousItem); + ItemLayoutInfo* nextInfo = _ItemLayoutInfo(nextItem); + ItemLayoutInfo* splitterInfo = _ItemLayoutInfo(_SplitterItemAt(index)); + bool previousVisible = previousInfo->isVisible; + bool nextVisible = nextInfo->isVisible; + if (!previousVisible && !nextVisible) + return false; + + ValueRange range; + _GetSplitterValueRange(index, range); + + value = max_c(min_c(value, range.sumValue), -(int32)fSpacing); + + int32 previousSize = value - (int32)fSpacing; + int32 nextSize = range.sumValue - value - (int32)fSpacing; + + // Note: While this collapsed-check is mathmatically correct (i.e. we + // collapse an item, if it would become smaller than half its minimum + // size), we might want to change it, since for the user it looks like + // collapsing happens earlier. The reason being that the only visual mark + // the user has is the mouse cursor which indeed hasn't crossed the middle + // of the item yet. + bool previousCollapsed = (previousSize <= range.previousMin / 2) + && previousInfo->isCollapsible; + bool nextCollapsed = (nextSize <= range.nextMin / 2) + && nextInfo->isCollapsible; + if (previousCollapsed && nextCollapsed) { + // we cannot collapse both items; we have to decide for one + if (previousSize < nextSize) { + // collapse previous + nextCollapsed = false; + nextSize = range.sumValue - (int32)fSpacing; + } else { + // collapse next + previousCollapsed = false; + previousSize = range.sumValue - (int32)fSpacing; + } + } + + if (previousCollapsed || nextCollapsed) { + // one collapsed item -- check whether that violates the constraints + // of the other one + int32 availableSpace = range.sumValue - (int32)fSpacing; + if (previousCollapsed) { + if (availableSpace < range.nextMin + || availableSpace > range.nextMax) { + // we cannot collapse the previous item + previousCollapsed = false; + } + } else { + if (availableSpace < range.previousMin + || availableSpace > range.previousMax) { + // we cannot collapse the next item + nextCollapsed = false; + } + } + } + + if (!(previousCollapsed || nextCollapsed)) { + // no collapsed item -- check whether there is a close solution + previousSize = value - (int32)fSpacing; + nextSize = range.sumValue - value - (int32)fSpacing; + + if (range.previousMin + range.nextMin + 2 * fSpacing > range.sumValue) { + // we don't have enough space to uncollapse both items + int32 availableSpace = range.sumValue - (int32)fSpacing; + if (previousSize < nextSize && availableSpace >= range.nextMin + && availableSpace <= range.nextMax + && previousInfo->isCollapsible) { + previousCollapsed = true; + } else if (availableSpace >= range.previousMin + && availableSpace <= range.previousMax + && nextInfo->isCollapsible) { + nextCollapsed = true; + } else if (availableSpace >= range.nextMin + && availableSpace <= range.nextMax + && previousInfo->isCollapsible) { + previousCollapsed = true; + } else { + if (previousSize < nextSize && previousInfo->isCollapsible) { + previousCollapsed = true; + } else if (nextInfo->isCollapsible) { + nextCollapsed = true; + } else { + // Neither item is collapsible although there's not enough + // space: Give them both their minimum size. + previousSize = range.previousMin; + nextSize = range.nextMin; + } + } + + } else { + // there is enough space for both items + // make sure the min constraints are satisfied + if (previousSize < range.previousMin) { + previousSize = range.previousMin; + nextSize = range.sumValue - previousSize - 2 * (int32)fSpacing; + } else if (nextSize < range.nextMin) { + nextSize = range.nextMin; + previousSize = range.sumValue - nextSize - 2 * (int32)fSpacing; + } + + // if we can, also satisfy the max constraints + if (range.previousMax + range.nextMax + 2 * (int32)fSpacing + >= range.sumValue) { + if (previousSize > range.previousMax) { + previousSize = range.previousMax; + nextSize = range.sumValue - previousSize + - 2 * (int32)fSpacing; + } else if (nextSize > range.nextMax) { + nextSize = range.nextMax; + previousSize = range.sumValue - nextSize + - 2 * (int32)fSpacing; + } + } + } + } + + // compute the size for one collapsed item; for none collapsed item we + // already have correct values + if (previousCollapsed || nextCollapsed) { + int32 availableSpace = range.sumValue - (int32)fSpacing; + if (previousCollapsed) { + previousSize = 0; + nextSize = availableSpace; + } else { + previousSize = availableSpace; + nextSize = 0; + } + } + + int32 newValue = previousSize + (previousCollapsed ? 0 : (int32)fSpacing); + if (newValue == fDraggingCurrentValue) { + // nothing changed + return false; + } + + // something changed: we need to recompute the layout + int32 baseOffset = -fDraggingCurrentValue; + // offset to the current splitter position + int32 splitterOffset = baseOffset + newValue; + int32 nextOffset = splitterOffset + (int32)fSplitterSize + (int32)fSpacing; + + BRect splitterFrame(splitterInfo->layoutFrame); + if (fOrientation == B_HORIZONTAL) { + // horizontal layout + // previous item + float left = splitterFrame.left + baseOffset; + previousInfo->layoutFrame.Set( + left, + splitterFrame.top, + left + previousSize - 1, + splitterFrame.bottom); + + // next item + left = splitterFrame.left + nextOffset; + nextInfo->layoutFrame.Set( + left, + splitterFrame.top, + left + nextSize - 1, + splitterFrame.bottom); + + // splitter + splitterInfo->layoutFrame.left += splitterOffset; + splitterInfo->layoutFrame.right += splitterOffset; + } else { + // vertical layout + // previous item + float top = splitterFrame.top + baseOffset; + previousInfo->layoutFrame.Set( + splitterFrame.left, + top, + splitterFrame.right, + top + previousSize - 1); + + // next item + top = splitterFrame.top + nextOffset; + nextInfo->layoutFrame.Set( + splitterFrame.left, + top, + splitterFrame.right, + top + nextSize - 1); + + // splitter + splitterInfo->layoutFrame.top += splitterOffset; + splitterInfo->layoutFrame.bottom += splitterOffset; + } + + previousInfo->isVisible = !previousCollapsed; + nextInfo->isVisible = !nextCollapsed; + + bool heightForWidth = (fOrientation == B_HORIZONTAL && HasHeightForWidth()); + + // If the item visibility is to be changed, we need to update the splitter + // values now, since the visibility change will cause an invalidation. + if (previousVisible != previousInfo->isVisible + || nextVisible != nextInfo->isVisible || heightForWidth) { + _UpdateSplitterWeights(); + } + + // If we have height for width items, we need to invalidate the previous + // and the next item. Actually we would only need to invalidate height for + // width items, but since non height for width items might be aligned with + // height for width items, we need to trigger a layout that creates a + // context that spans all aligned items. + // We invalidate already here, so that changing the items' size won't cause + // an immediate relayout. + if (heightForWidth) { + previousItem->InvalidateLayout(); + nextItem->InvalidateLayout(); + } + + // do the layout + _LayoutItem(previousItem, previousInfo); + _LayoutItem(_SplitterItemAt(index), splitterInfo); + _LayoutItem(nextItem, nextInfo); + + fDraggingCurrentValue = newValue; + + return true; +} + +// _ItemLayoutInfo +BSplitLayout::ItemLayoutInfo* +BSplitLayout::_ItemLayoutInfo(BLayoutItem* item) const +{ + ItemLayoutInfo* info = (ItemLayoutInfo*)item->LayoutData(); + if (!info) { + info = new ItemLayoutInfo(); + item->SetLayoutData(info); + } + + return info; +} + +// _UpdateSplitterWeights +void +BSplitLayout::_UpdateSplitterWeights() +{ + int32 count = CountItems(); + for (int32 i = 0; i < count; i++) { + float weight; + if (fOrientation == B_HORIZONTAL) + weight = _ItemLayoutInfo(ItemAt(i))->layoutFrame.Width() + 1; + else + weight = _ItemLayoutInfo(ItemAt(i))->layoutFrame.Height() + 1; + + SetItemWeight(i, weight, false); + } + + // Just updating the splitter weights is fine in principle. The next + // LayoutView() will use the correct values. But, if our orientation is + // vertical, the cached height for width info needs to be flushed, or the + // obsolete cached values will be used. + if (fOrientation == B_VERTICAL) + _InvalidateCachedHeightForWidth(); +} + +// _ValidateMinMax +void +BSplitLayout::_ValidateMinMax() +{ + if (fHorizontalLayouter != NULL) + return; + + fLayoutValid = false; + + fVisibleItems.MakeEmpty(); + fHeightForWidthItems.MakeEmpty(); + + _InvalidateCachedHeightForWidth(); + + // filter the visible items + int32 itemCount = CountItems(); + for (int32 i = 0; i < itemCount; i++) { + BLayoutItem* item = ItemAt(i); + if (item->IsVisible()) + fVisibleItems.AddItem(item); + + // Add "height for width" items even, if they aren't visible. Otherwise + // we may get our parent into trouble, since we could change from + // "height for width" to "not height for width". + if (item->HasHeightForWidth()) + fHeightForWidthItems.AddItem(item); + } + itemCount = fVisibleItems.CountItems(); + + // create the layouters + Layouter* itemLayouter = new SimpleLayouter(itemCount, 0); + + if (fOrientation == B_HORIZONTAL) { + fHorizontalLayouter = itemLayouter; + fVerticalLayouter = new OneElementLayouter(); + } else { + fHorizontalLayouter = new OneElementLayouter(); + fVerticalLayouter = itemLayouter; + } + + // tell the layouters about our constraints + if (itemCount > 0) { + for (int32 i = 0; i < itemCount; i++) { + BLayoutItem* item = (BLayoutItem*)fVisibleItems.ItemAt(i); + BSize min = item->MinSize(); + BSize max = item->MaxSize(); + BSize preferred = item->PreferredSize(); + + fHorizontalLayouter->AddConstraints(i, 1, min.width, max.width, + preferred.width); + fVerticalLayouter->AddConstraints(i, 1, min.height, max.height, + preferred.height); + + float weight = ItemWeight(item); + fHorizontalLayouter->SetWeight(i, weight); + fVerticalLayouter->SetWeight(i, weight); + } + } + + fMin.width = fHorizontalLayouter->MinSize(); + fMin.height = fVerticalLayouter->MinSize(); + fMax.width = fHorizontalLayouter->MaxSize(); + fMax.height = fVerticalLayouter->MaxSize(); + fPreferred.width = fHorizontalLayouter->PreferredSize(); + fPreferred.height = fVerticalLayouter->PreferredSize(); + + fHorizontalLayoutInfo = fHorizontalLayouter->CreateLayoutInfo(); + if (fHeightForWidthItems.IsEmpty()) + fVerticalLayoutInfo = fVerticalLayouter->CreateLayoutInfo(); +} + +// _InternalGetHeightForWidth +void +BSplitLayout::_InternalGetHeightForWidth(float width, bool realLayout, + float* minHeight, float* maxHeight, float* preferredHeight) +{ + if (realLayout && fHeightForWidthVerticalLayouterWidth != width + || !realLayout && fCachedHeightForWidthWidth != width) { + // The general strategy is to clone the vertical layouter, which only + // knows the general min/max constraints, do a horizontal layout for the + // given width, and add the children's height for width constraints to + // the cloned vertical layouter. If this method is invoked internally, + // we keep the cloned vertical layouter, for it will be used for doing + // the layout. Otherwise we just drop it after we've got the height for + // width info. + + // clone the vertical layouter and get the horizontal layout info to be used + LayoutInfo* horizontalLayoutInfo = NULL; + Layouter* verticalLayouter = fVerticalLayouter->CloneLayouter(); + if (realLayout) { + horizontalLayoutInfo = fHorizontalLayoutInfo; + delete fHeightForWidthVerticalLayouter; + fHeightForWidthVerticalLayouter = verticalLayouter; + delete fVerticalLayoutInfo; + fVerticalLayoutInfo = verticalLayouter->CreateLayoutInfo(); + fHeightForWidthVerticalLayouterWidth = width; + } else { + if (fHeightForWidthHorizontalLayoutInfo == NULL) { + delete fHeightForWidthHorizontalLayoutInfo; + fHeightForWidthHorizontalLayoutInfo + = fHorizontalLayouter->CreateLayoutInfo(); + } + horizontalLayoutInfo = fHeightForWidthHorizontalLayoutInfo; + } + + // do the horizontal layout (already done when doing this for the real + // layout) + if (!realLayout) + fHorizontalLayouter->Layout(horizontalLayoutInfo, width); + + // add the children's height for width constraints + int32 count = fHeightForWidthItems.CountItems(); + for (int32 i = 0; i < count; i++) { + BLayoutItem* item = (BLayoutItem*)fHeightForWidthItems.ItemAt(i); + int32 index = fVisibleItems.IndexOf(item); + if (index >= 0) { + float itemMinHeight, itemMaxHeight, itemPreferredHeight; + item->GetHeightForWidth( + horizontalLayoutInfo->ElementSize(index), + &itemMinHeight, &itemMaxHeight, &itemPreferredHeight); + verticalLayouter->AddConstraints(index, 1, itemMinHeight, + itemMaxHeight, itemPreferredHeight); + } + } + + // get the height for width info + fCachedHeightForWidthWidth = width; + fCachedMinHeightForWidth = verticalLayouter->MinSize(); + fCachedMaxHeightForWidth = verticalLayouter->MaxSize(); + fCachedPreferredHeightForWidth = verticalLayouter->PreferredSize(); + } + + if (minHeight) + *minHeight = fCachedMinHeightForWidth; + if (maxHeight) + *maxHeight = fCachedMaxHeightForWidth; + if (preferredHeight) + *preferredHeight = fCachedPreferredHeightForWidth; +} + +// _SplitterSpace +float +BSplitLayout::_SplitterSpace() const +{ + int32 splitters = fSplitterItems.CountItems(); + float space = 0; + if (splitters > 0) { + space = (fVisibleItems.CountItems() + splitters - 1) * fSpacing + + splitters * fSplitterSize; + } + + return space; +} + +// _AddInsets +BSize +BSplitLayout::_AddInsets(BSize size) +{ + size.width = BLayoutUtils::AddDistances(size.width, + fLeftInset + fRightInset - 1); + size.height = BLayoutUtils::AddDistances(size.height, + fTopInset + fBottomInset - 1); + + float spacing = _SplitterSpace(); + if (fOrientation == B_HORIZONTAL) + size.width = BLayoutUtils::AddDistances(size.width, spacing - 1); + else + size.height = BLayoutUtils::AddDistances(size.height, spacing - 1); + + return size; +} + +// _AddInsets +void +BSplitLayout::_AddInsets(float* minHeight, float* maxHeight, + float* preferredHeight) +{ + float insets = fTopInset + fBottomInset - 1; + if (fOrientation == B_VERTICAL) + insets += _SplitterSpace(); + if (minHeight) + *minHeight = BLayoutUtils::AddDistances(*minHeight, insets); + if (maxHeight) + *maxHeight = BLayoutUtils::AddDistances(*maxHeight, insets); + if (preferredHeight) + *preferredHeight = BLayoutUtils::AddDistances(*preferredHeight, insets); +} + +// _SubtractInsets +BSize +BSplitLayout::_SubtractInsets(BSize size) +{ + size.width = BLayoutUtils::SubtractDistances(size.width, + fLeftInset + fRightInset - 1); + size.height = BLayoutUtils::SubtractDistances(size.height, + fTopInset + fBottomInset - 1); + + float spacing = _SplitterSpace(); + if (fOrientation == B_HORIZONTAL) + size.width = BLayoutUtils::SubtractDistances(size.width, spacing - 1); + else + size.height = BLayoutUtils::SubtractDistances(size.height, spacing - 1); + + return size; +} diff --git a/src/kits/interface/SplitLayout.h b/src/kits/interface/SplitLayout.h new file mode 100644 index 0000000000..2cfb61d3ed --- /dev/null +++ b/src/kits/interface/SplitLayout.h @@ -0,0 +1,172 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _SPLIT_LAYOUT_H +#define _SPLIT_LAYOUT_H + +#include + +namespace BPrivate { +namespace Layout { + class Layouter; + class LayoutInfo; +} +} + +using BPrivate::Layout::Layouter; +using BPrivate::Layout::LayoutInfo; + + +class BSplitLayout : public BLayout { +public: + BSplitLayout(enum orientation orientation, + float spacing = 0.0f); + virtual ~BSplitLayout(); + + void SetInsets(float left, float top, float right, + float bottom); + void GetInsets(float* left, float* top, float* right, + float* bottom); + + float Spacing() const; + void SetSpacing(float spacing); + + orientation Orientation() const; + void SetOrientation(enum orientation orientation); + + float SplitterSize() const; + void SetSplitterSize(float size); + + virtual BLayoutItem* AddView(BView* child); + virtual BLayoutItem* AddView(int32 index, BView* child); + virtual BLayoutItem* AddView(BView* child, float weight); + virtual BLayoutItem* AddView(int32 index, BView* child, + float weight); + + virtual bool AddItem(BLayoutItem* item); + virtual bool AddItem(int32 index, BLayoutItem* item); + virtual bool AddItem(BLayoutItem* item, float weight); + virtual bool AddItem(int32 index, BLayoutItem* item, + float weight); + + + float ItemWeight(int32 index) const; + float ItemWeight(BLayoutItem* item) const; + void SetItemWeight(int32 index, float weight, + bool invalidateLayout); + void SetItemWeight(BLayoutItem* item, float weight); + + void SetCollapsible(bool collapsible); + void SetCollapsible(int32 index, bool collapsible); + void SetCollapsible(int32 first, int32 last, + bool collapsible); + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + virtual BAlignment Alignment(); + + virtual bool HasHeightForWidth(); + virtual void GetHeightForWidth(float width, float* min, + float* max, float* preferred); + + virtual void InvalidateLayout(); + + virtual void LayoutView(); + + // interface for BSplitView + BRect SplitterItemFrame(int32 index) const; + + bool StartDraggingSplitter(BPoint point); + bool DragSplitter(BPoint point); + bool StopDraggingSplitter(); + int32 DraggedSplitter() const; + +protected: + virtual void ItemAdded(BLayoutItem* item); + virtual void ItemRemoved(BLayoutItem* item); + +private: + class ItemLayoutInfo; + class ValueRange; + class SplitterItem; + + void _InvalidateLayout(bool invalidateView); + void _InvalidateCachedHeightForWidth(); + + SplitterItem* _SplitterItemAt(int32 index) const; + + void _GetSplitterValueRange(int32 index, + ValueRange& range); + int32 _SplitterValue(int32 index) const; + + void _LayoutItem(BLayoutItem* item, BRect frame, + bool visible); + void _LayoutItem(BLayoutItem* item, + ItemLayoutInfo* info); + + bool _SetSplitterValue(int32 index, int32 value); + + ItemLayoutInfo* _ItemLayoutInfo(BLayoutItem* item) const; + + + void _UpdateSplitterWeights(); + + void _ValidateMinMax(); + + void _InternalGetHeightForWidth(float width, + bool realLayout, float* minHeight, + float* maxHeight, float* preferredHeight); + + float _SplitterSpace() const; + + BSize _AddInsets(BSize size); + void _AddInsets(float* minHeight, float* maxHeight, + float* preferredHeight); + BSize _SubtractInsets(BSize size); + +private: + orientation fOrientation; + float fLeftInset; + float fRightInset; + float fTopInset; + float fBottomInset; + float fSplitterSize; + float fSpacing; + + BList fSplitterItems; + BList fVisibleItems; + + BSize fMin; + BSize fMax; + BSize fPreferred; + + Layouter* fHorizontalLayouter; + Layouter* fVerticalLayouter; + + LayoutInfo* fHorizontalLayoutInfo; + LayoutInfo* fVerticalLayoutInfo; + + BList fHeightForWidthItems; + // Incorporates the children's height for width constraints for a + // concrete width. Cloned lazily from fVerticalLayout when needed. + Layouter* fHeightForWidthVerticalLayouter; + LayoutInfo* fHeightForWidthHorizontalLayoutInfo; + // for computing height for width info + + bool fLayoutValid; + + float fCachedHeightForWidthWidth; + float fHeightForWidthVerticalLayouterWidth; + float fCachedMinHeightForWidth; + float fCachedMaxHeightForWidth; + float fCachedPreferredHeightForWidth; + + BPoint fDraggingStartPoint; + int32 fDraggingStartValue; + int32 fDraggingCurrentValue; + int32 fDraggingSplitterIndex; +}; + +#endif // _SPLIT_LAYOUT_H diff --git a/src/kits/interface/SplitLayoutBuilder.cpp b/src/kits/interface/SplitLayoutBuilder.cpp new file mode 100644 index 0000000000..52d7d3cfe1 --- /dev/null +++ b/src/kits/interface/SplitLayoutBuilder.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include + + +using std::nothrow; + + +// constructor +BSplitLayoutBuilder::BSplitLayoutBuilder(enum orientation orientation, + float spacing) + : fView(new BSplitView(orientation, spacing)) +{ +} + +// constructor +BSplitLayoutBuilder::BSplitLayoutBuilder(BSplitView* view) + : fView(view) +{ +} + +// SplitView +BSplitView* +BSplitLayoutBuilder::SplitView() const +{ + return fView; +} + +// GetSplitView +BSplitLayoutBuilder& +BSplitLayoutBuilder::GetSplitView(BSplitView** view) +{ + *view = fView; + return *this; +} + +// Add +BSplitLayoutBuilder& +BSplitLayoutBuilder::Add(BView* view) +{ + fView->AddChild(view); + return *this; +} + +// Add +BSplitLayoutBuilder& +BSplitLayoutBuilder::Add(BView* view, float weight) +{ + fView->AddChild(view, weight); + return *this; +} + +// Add +BSplitLayoutBuilder& +BSplitLayoutBuilder::Add(BLayoutItem* item) +{ + fView->AddChild(item); + return *this; +} + +// Add +BSplitLayoutBuilder& +BSplitLayoutBuilder::Add(BLayoutItem* item, float weight) +{ + fView->AddChild(item, weight); + return *this; +} + +// SetCollapsible +BSplitLayoutBuilder& +BSplitLayoutBuilder::SetCollapsible(bool collapsible) +{ + int32 count = fView->CountChildren(); + if (count > 0) + fView->SetCollapsible(count - 1, collapsible); + return *this; +} + +// cast operator BSplitView* +BSplitLayoutBuilder::operator BSplitView*() +{ + return fView; +} + diff --git a/src/kits/interface/SplitView.cpp b/src/kits/interface/SplitView.cpp new file mode 100644 index 0000000000..e0950cd9bd --- /dev/null +++ b/src/kits/interface/SplitView.cpp @@ -0,0 +1,195 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include "SplitLayout.h" + + +// constructor +BSplitView::BSplitView(enum orientation orientation, float spacing) + : BView(NULL, + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INVALIDATE_AFTER_LAYOUT, + fSplitLayout = new BSplitLayout(orientation, spacing)) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); +} + +// destructor +BSplitView::~BSplitView() +{ +} + +// Spacing +float +BSplitView::Spacing() const +{ + return fSplitLayout->Spacing(); +} + +// SetSpacing +void +BSplitView::SetSpacing(float spacing) +{ + fSplitLayout->SetSpacing(spacing); +} + +// Orientation +orientation +BSplitView::Orientation() const +{ + return fSplitLayout->Orientation(); +} + +// SetOrientation +void +BSplitView::SetOrientation(enum orientation orientation) +{ + fSplitLayout->SetOrientation(orientation); +} + +// SplitterSize +float +BSplitView::SplitterSize() const +{ + return fSplitLayout->SplitterSize(); +} + +// SetSplitterSize +void +BSplitView::SetSplitterSize(float size) +{ + fSplitLayout->SetSplitterSize(size); +} + +// SetCollapsible +void +BSplitView::SetCollapsible(bool collapsible) +{ + fSplitLayout->SetCollapsible(collapsible); +} + +// SetCollapsible +void +BSplitView::SetCollapsible(int32 index, bool collapsible) +{ + fSplitLayout->SetCollapsible(index, collapsible); +} + +// SetCollapsible +void +BSplitView::SetCollapsible(int32 first, int32 last, bool collapsible) +{ + fSplitLayout->SetCollapsible(first, last, collapsible); +} + +// AddChild +void +BSplitView::AddChild(BView* child, BView* sibling) +{ + BView::AddChild(child, sibling); +} + +// AddChild +bool +BSplitView::AddChild(BView* child, float weight) +{ + return fSplitLayout->AddView(child, weight); +} + +// AddChild +bool +BSplitView::AddChild(int32 index, BView* child, float weight) +{ + return fSplitLayout->AddView(index, child, weight); +} + +// AddChild +bool +BSplitView::AddChild(BLayoutItem* child) +{ + return fSplitLayout->AddItem(child); +} + +// AddChild +bool +BSplitView::AddChild(BLayoutItem* child, float weight) +{ + return fSplitLayout->AddItem(child, weight); +} + +// AddChild +bool +BSplitView::AddChild(int32 index, BLayoutItem* child, float weight) +{ + return fSplitLayout->AddItem(index, child, weight); +} + +// Draw +void +BSplitView::Draw(BRect updateRect) +{ + // draw the splitters + int32 draggedSplitterIndex = fSplitLayout->DraggedSplitter(); + int32 count = fSplitLayout->CountItems(); + for (int32 i = 0; i < count - 1; i++) { + BRect frame = fSplitLayout->SplitterItemFrame(i); + DrawSplitter(frame, Orientation(), draggedSplitterIndex == i); + } +} + +// MouseDown +void +BSplitView::MouseDown(BPoint where) +{ + SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); + + if (fSplitLayout->StartDraggingSplitter(where)) + Invalidate(); +} + +// MouseUp +void +BSplitView::MouseUp(BPoint where) +{ + if (fSplitLayout->StopDraggingSplitter()) { + Relayout(); + Invalidate(); + } +} + +// MouseMoved +void +BSplitView::MouseMoved(BPoint where, uint32 transit, const BMessage* message) +{ + int32 splitterIndex = fSplitLayout->DraggedSplitter(); + if (splitterIndex >= 0) { + BRect oldFrame = fSplitLayout->SplitterItemFrame(splitterIndex); + if (fSplitLayout->DragSplitter(where)) { + Invalidate(oldFrame); + Invalidate(fSplitLayout->SplitterItemFrame(splitterIndex)); + } + } +} + +// SetLayout +void +BSplitView::SetLayout(BLayout* layout) +{ + // not allowed +} + +// DrawSplitter +void +BSplitView::DrawSplitter(BRect frame, enum orientation orientation, + bool pressed) +{ + rgb_color black = { 0, 0, 0, 255 }; + rgb_color white = { 255, 255, 255, 255 }; + + SetHighColor(pressed ? white : black); + + FillRect(frame); +} diff --git a/src/kits/interface/StringView.cpp b/src/kits/interface/StringView.cpp index 13b6e4187b..8f7bfab73b 100644 --- a/src/kits/interface/StringView.cpp +++ b/src/kits/interface/StringView.cpp @@ -9,8 +9,10 @@ /** BStringView draw a non-editable text string */ -#include #include + +#include +#include #include #include @@ -265,6 +267,16 @@ BStringView::GetSupportedSuites(BMessage* message) } +BSize +BStringView::MaxSize() +{ + float width, height; + GetPreferredSize(&width, &height); + + return BLayoutUtils::ComposeSize(ExplicitMaxSize(), BSize(width, height)); +} + + status_t BStringView::Perform(perform_code d, void* arg) { diff --git a/src/kits/interface/TextControl.cpp b/src/kits/interface/TextControl.cpp index 94dacc9812..050cccb426 100644 --- a/src/kits/interface/TextControl.cpp +++ b/src/kits/interface/TextControl.cpp @@ -5,6 +5,7 @@ * Authors: * Frans van Nispen (xlr8@tref.nl) * Stephan Aßmus + * Ingo Weinhold */ /** BTextControl displays text that can act like a control. */ @@ -12,6 +13,8 @@ #include +#include +#include #include #include #include @@ -20,23 +23,83 @@ #include "TextInput.h" +class BTextControl::LabelLayoutItem : public BAbstractLayoutItem { +public: + LabelLayoutItem(BTextControl* parent); + + virtual bool IsVisible(); + virtual void SetVisible(bool visible); + + virtual BRect Frame(); + virtual void SetFrame(BRect frame); + + virtual BView* View(); + + virtual BSize BaseMinSize(); + virtual BSize BaseMaxSize(); + virtual BSize BasePreferredSize(); + virtual BAlignment BaseAlignment(); + +private: + BTextControl* fParent; + BRect fFrame; +}; + + +class BTextControl::TextViewLayoutItem : public BAbstractLayoutItem { +public: + TextViewLayoutItem(BTextControl* parent); + + virtual bool IsVisible(); + virtual void SetVisible(bool visible); + + virtual BRect Frame(); + virtual void SetFrame(BRect frame); + + virtual BView* View(); + + virtual BSize BaseMinSize(); + virtual BSize BaseMaxSize(); + virtual BSize BasePreferredSize(); + virtual BAlignment BaseAlignment(); + +private: + BTextControl* fParent; + BRect fFrame; +}; + + +// #pragma mark - + + BTextControl::BTextControl(BRect frame, const char *name, const char *label, const char *text, BMessage *message, uint32 mask, uint32 flags) : BControl(frame, name, label, message, mask, flags | B_FRAME_EVENTS) { _InitData(label, text); + _ValidateLayout(); +} - float height; - BTextControl::GetPreferredSize(NULL, &height); - ResizeTo(Bounds().Width(), height); +BTextControl::BTextControl(const char *name, const char *label, + const char *text, BMessage *message, + uint32 flags) + : BControl(BRect(0, 0, -1, -1), name, label, message, B_FOLLOW_NONE, + flags | B_FRAME_EVENTS | B_SUPPORTS_LAYOUT) +{ + _InitData(label, text); + _ValidateLayout(); +} - float lineHeight = ceil(fText->LineHeight(0)); - fText->ResizeTo(fText->Bounds().Width(), lineHeight); - fText->MoveTo(fText->Frame().left, (height - lineHeight) / 2); - fPreviousHeight = Bounds().Height(); +BTextControl::BTextControl(const char *label, + const char *text, BMessage *message) + : BControl(BRect(0, 0, -1, -1), NULL, label, message, B_FOLLOW_NONE, + B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS | B_SUPPORTS_LAYOUT) +{ + _InitData(label, text); + _ValidateLayout(); } @@ -566,6 +629,24 @@ BTextControl::Perform(perform_code d, void *arg) } +BLayoutItem* +BTextControl::CreateLabelLayoutItem() +{ + if (!fLabelLayoutItem) + fLabelLayoutItem = new LabelLayoutItem(this); + return fLabelLayoutItem; +} + + +BLayoutItem* +BTextControl::CreateTextViewLayoutItem() +{ + if (!fTextViewLayoutItem) + fTextViewLayoutItem = new TextViewLayoutItem(this); + return fTextViewLayoutItem; +} + + void BTextControl::_ReservedTextControl1() {} void BTextControl::_ReservedTextControl2() {} void BTextControl::_ReservedTextControl3() {} @@ -627,6 +708,8 @@ BTextControl::_InitData(const char* label, const char* initialText, fDivider = 0.0f; fPreviousWidth = bounds.Width(); fPreviousHeight = bounds.Height(); + fLabelLayoutItem = NULL; + fTextViewLayoutItem = NULL; fSkipSetFlags = false; int32 flags = 0; @@ -672,3 +755,204 @@ BTextControl::_InitData(const char* label, const char* initialText, fText->AlignTextRect(); } } + + +void +BTextControl::_ValidateLayout() +{ + float height; + BTextControl::GetPreferredSize(NULL, &height); + + ResizeTo(Bounds().Width(), height); + + float lineHeight = ceil(fText->LineHeight(0)); + fText->ResizeTo(fText->Bounds().Width(), lineHeight); + fText->MoveTo(fText->Frame().left, (height - lineHeight) / 2); + + fPreviousHeight = Bounds().Height(); +} + + +void +BTextControl::_UpdateFrame() +{ + if (fLabelLayoutItem && fTextViewLayoutItem) { + BRect labelFrame = fLabelLayoutItem->Frame(); + BRect textFrame = fTextViewLayoutItem->Frame(); + MoveTo(labelFrame.left, labelFrame.top); + ResizeTo(textFrame.left + textFrame.Width() - labelFrame.left, + textFrame.top + textFrame.Height() - labelFrame.top); + SetDivider(textFrame.left - labelFrame.left); + } +} + + +// #pragma mark - + + +BTextControl::LabelLayoutItem::LabelLayoutItem(BTextControl* parent) + : fParent(parent), + fFrame() +{ +} + + +bool +BTextControl::LabelLayoutItem::IsVisible() +{ + return !fParent->IsHidden(fParent); +} + + +void +BTextControl::LabelLayoutItem::SetVisible(bool visible) +{ + // not allowed +} + + +BRect +BTextControl::LabelLayoutItem::Frame() +{ + return fFrame; +} + + +void +BTextControl::LabelLayoutItem::SetFrame(BRect frame) +{ + fFrame = frame; + fParent->_UpdateFrame(); +} + + +BView* +BTextControl::LabelLayoutItem::View() +{ + return fParent; +} + + +BSize +BTextControl::LabelLayoutItem::BaseMinSize() +{ +// TODO: Cache the info. Might be too expensive for this call. + const char* label = fParent->Label(); + if (!label) + return BSize(-1, -1); + + BSize size; + fParent->GetPreferredSize(NULL, &size.height); + + size.width = fParent->StringWidth(label) + 2 * 3 - 1; + + return size; +} + + +BSize +BTextControl::LabelLayoutItem::BaseMaxSize() +{ + return BaseMinSize(); +} + + +BSize +BTextControl::LabelLayoutItem::BasePreferredSize() +{ + return BaseMinSize(); +} + + +BAlignment +BTextControl::LabelLayoutItem::BaseAlignment() +{ + return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); +} + + +// #pragma mark - + + +BTextControl::TextViewLayoutItem::TextViewLayoutItem(BTextControl* parent) + : fParent(parent), + fFrame() +{ +} + + +bool +BTextControl::TextViewLayoutItem::IsVisible() +{ + return !fParent->IsHidden(fParent); +} + + +void +BTextControl::TextViewLayoutItem::SetVisible(bool visible) +{ + // not allowed +} + + +BRect +BTextControl::TextViewLayoutItem::Frame() +{ + return fFrame; +} + + +void +BTextControl::TextViewLayoutItem::SetFrame(BRect frame) +{ + fFrame = frame; + fParent->_UpdateFrame(); +} + + +BView* +BTextControl::TextViewLayoutItem::View() +{ + return fParent; +} + + +BSize +BTextControl::TextViewLayoutItem::BaseMinSize() +{ +// TODO: Cache the info. Might be too expensive for this call. + BSize size; + fParent->GetPreferredSize(NULL, &size.height); + + // mmh, some arbitrary minimal width + size.width = 30; + + return size; +} + + +BSize +BTextControl::TextViewLayoutItem::BaseMaxSize() +{ + BSize size(BaseMinSize()); + size.width = B_SIZE_UNLIMITED; + return size; +} + + +BSize +BTextControl::TextViewLayoutItem::BasePreferredSize() +{ + BSize size(BaseMinSize()); + // puh, no idea... + size.width = 100; + return size; +} + + +BAlignment +BTextControl::TextViewLayoutItem::BaseAlignment() +{ + return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); +} + diff --git a/src/kits/interface/TwoDimensionalLayout.cpp b/src/kits/interface/TwoDimensionalLayout.cpp new file mode 100644 index 0000000000..f903d6535a --- /dev/null +++ b/src/kits/interface/TwoDimensionalLayout.cpp @@ -0,0 +1,1179 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "ConstraintSolverLayouter.h" +#include "OneElementLayouter.h" +#include "SimpleLayouter.h" + + +// Some words of explanation: +// +// This class is the base class for BLayouts that organize their items +// on a grid, with each item covering one or more grid cells (always a +// rectangular area). The derived classes only need to implement the +// hooks reporting the constraints for the items and additional constraints +// for the rows and columns. This class does all the layouting. +// +// The basic idea of the layout process is simple. The horizontal and the +// vertical dimensions are laid out independently and the items are set to the +// resulting locations and sizes. The "height for width" feature makes the +// height depend on the width, which makes things a bit more complicated. +// The horizontal dimension must be laid out first and and the results are +// fed into the vertical layout process. +// +// The AlignLayoutWith() feature, which allows to align layouts for different +// views with each other, causes the need for the three inner *Layouter classes. +// For each set of layouts aligned with each other with respect to one +// dimension that dimension must be laid out together. The class responsible +// is CompoundLayouter; one instance exists per such set. The derived class +// VerticalCompoundLayouter is a specialization for the vertical dimension +// which additionally takes care of the "height for width" feature. Per layout +// a single LocalLayouter exists, which comprises the required glue layout +// code and serves as a proxy for the layout, providing service methods +// needed by the CompoundLayouter. + +// TODO: Check for memory leaks! + + +// CompoundLayouter +class BTwoDimensionalLayout::CompoundLayouter { +public: + CompoundLayouter(enum orientation orientation); + virtual ~CompoundLayouter(); + + orientation Orientation(); + + virtual Layouter* GetLayouter(bool minMax); + + LayoutInfo* GetLayoutInfo(); + + void AddLocalLayouter(LocalLayouter* localLayouter); + void RemoveLocalLayouter( + LocalLayouter* localLayouter); + + void AbsorbCompoundLayouter(CompoundLayouter* other); + + virtual void InvalidateLayout(); + bool IsMinMaxValid(); + void ValidateMinMax(); + void Layout(float size, LocalLayouter* localLayouter, + BLayoutContext* context); + +protected: + virtual void DoLayout(float size, + LocalLayouter* localLayouter, + BLayoutContext* context); + + Layouter* fLayouter; + LayoutInfo* fLayoutInfo; + orientation fOrientation; + BList fLocalLayouters; + BLayoutContext* fLayoutContext; + float fLastLayoutSize; + + void _PrepareItems(); + + int32 _CountElements(); + bool _HasMultiElementItems(); + + void _AddConstraints(Layouter* layouter); + + float _Spacing(); +}; + +// VerticalCompoundLayouter +class BTwoDimensionalLayout::VerticalCompoundLayouter + : public CompoundLayouter, private BLayoutContextListener { +public: + VerticalCompoundLayouter(); + + virtual Layouter* GetLayouter(bool minMax); + + virtual void InvalidateLayout(); + + void InvalidateHeightForWidth(); + + void InternalGetHeightForWidth( + LocalLayouter* localLayouter, + BLayoutContext* context, + bool realLayout, float* minHeight, + float* maxHeight, float* preferredHeight); + +protected: + virtual void DoLayout(float size, + LocalLayouter* localLayouter, + BLayoutContext* context); + +private: + Layouter* fHeightForWidthLayouter; + float fCachedMinHeightForWidth; + float fCachedMaxHeightForWidth; + float fCachedPreferredHeightForWidth; + BLayoutContext* fHeightForWidthLayoutContext; + + bool _HasHeightForWidth(); + + bool _SetHeightForWidthLayoutContext( + BLayoutContext* context); + + // BLayoutContextListener + virtual void LayoutContextLeft(BLayoutContext* context); +}; + +// LocalLayouter +class BTwoDimensionalLayout::LocalLayouter : private BLayoutContextListener { +public: + LocalLayouter(BTwoDimensionalLayout* layout); + + // interface for the BTwoDimensionalLayout class + + BSize MinSize(); + BSize MaxSize(); + BSize PreferredSize(); + + void InvalidateLayout(); + void Layout(BSize size); + + BRect ItemFrame(Dimensions itemDimensions); + + void ValidateMinMax(); + + void DoHorizontalLayout(float width); + + void InternalGetHeightForWidth(float width, + float* minHeight, float* maxHeight, + float* preferredHeight); + + void AlignWith(LocalLayouter* other, + enum orientation orientation); + + + // interface for the compound layout context + + void PrepareItems( + CompoundLayouter* compoundLayouter); + int32 CountElements( + CompoundLayouter* compoundLayouter); + bool HasMultiElementItems( + CompoundLayouter* compoundLayouter); + + void AddConstraints( + CompoundLayouter* compoundLayouter, + Layouter* layouter); + + float Spacing(CompoundLayouter* compoundLayouter); + + bool HasHeightForWidth(); + + bool AddHeightForWidthConstraints( + VerticalCompoundLayouter* compoundLayouter, + Layouter* layouter, + BLayoutContext* context); + void SetHeightForWidthConstraintsAdded(bool added); + + void SetCompoundLayouter( + CompoundLayouter* compoundLayouter, + enum orientation orientation); + + void InternalInvalidateLayout( + CompoundLayouter* compoundLayouter); + + // implementation private +private: + BTwoDimensionalLayout* fLayout; + CompoundLayouter* fHLayouter; + VerticalCompoundLayouter* fVLayouter; + BList fHeightForWidthItems; + + // active layout context when doing last horizontal layout + BLayoutContext* fHorizontalLayoutContext; + float fHorizontalLayoutWidth; + bool fHeightForWidthConstraintsAdded; + + void _SetHorizontalLayoutContext( + BLayoutContext* context, float width); + + // BLayoutContextListener + virtual void LayoutContextLeft(BLayoutContext* context); +}; + + +// #pragma mark - + + +// constructor +BTwoDimensionalLayout::BTwoDimensionalLayout() + : fLeftInset(0), + fRightInset(0), + fTopInset(0), + fBottomInset(0), + fHSpacing(0), + fVSpacing(0), + fLocalLayouter(new LocalLayouter(this)) +{ +} + +// destructor +BTwoDimensionalLayout::~BTwoDimensionalLayout() +{ + delete fLocalLayouter; +} + +// SetInsets +void +BTwoDimensionalLayout::SetInsets(float left, float top, float right, + float bottom) +{ + fLeftInset = left; + fTopInset = top; + fRightInset = right; + fBottomInset = bottom; + + InvalidateLayout(); +} + +// GetInsets +void +BTwoDimensionalLayout::GetInsets(float* left, float* top, float* right, + float* bottom) +{ + if (left) + *left = fLeftInset; + if (top) + *top = fTopInset; + if (right) + *right = fRightInset; + if (bottom) + *bottom = fBottomInset; +} + +// AlignLayoutWith +void +BTwoDimensionalLayout::AlignLayoutWith(BTwoDimensionalLayout* other, + enum orientation orientation) +{ + if (!other || other == this) + return; + + fLocalLayouter->AlignWith(other->fLocalLayouter, orientation); + + InvalidateLayout(); +} + +// MinSize +BSize +BTwoDimensionalLayout::MinSize() +{ + _ValidateMinMax(); + return AddInsets(fLocalLayouter->MinSize()); +} + +// MaxSize +BSize +BTwoDimensionalLayout::MaxSize() +{ + _ValidateMinMax(); + return AddInsets(fLocalLayouter->MaxSize()); +} + +// PreferredSize +BSize +BTwoDimensionalLayout::PreferredSize() +{ + _ValidateMinMax(); + return AddInsets(fLocalLayouter->PreferredSize()); +} + +// Alignment +BAlignment +BTwoDimensionalLayout::Alignment() +{ + return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); +} + +// GetHeightForWidth +bool +BTwoDimensionalLayout::HasHeightForWidth() +{ + _ValidateMinMax(); + return fLocalLayouter->HasHeightForWidth(); +} + +// GetHeightForWidth +void +BTwoDimensionalLayout::GetHeightForWidth(float width, float* min, float* max, + float* preferred) +{ + if (!HasHeightForWidth()) + return; + + float outerSpacing = fLeftInset + fRightInset - 1; + fLocalLayouter->InternalGetHeightForWidth(BLayoutUtils::SubtractDistances( + width, outerSpacing), min, max, preferred); + AddInsets(min, max, preferred); +} + +// InvalidateLayout +void +BTwoDimensionalLayout::InvalidateLayout() +{ + BLayout::InvalidateLayout(); + + fLocalLayouter->InvalidateLayout(); +} + +// LayoutView +void +BTwoDimensionalLayout::LayoutView() +{ + _ValidateMinMax(); + + // layout the horizontal/vertical elements + BSize size = SubtractInsets(BSize(View()->Frame())); +printf("BTwoDimensionalLayout::LayoutView(%p): size: (%.1f, %.1f)\n", +View(), size.width, size.height); + + fLocalLayouter->Layout(size); + + // layout the items + int itemCount = CountItems(); + for (int i = 0; i < itemCount; i++) { + BLayoutItem* item = ItemAt(i); + if (item->IsVisible()) { + Dimensions itemDimensions; + GetItemDimensions(item, &itemDimensions); + BRect frame = fLocalLayouter->ItemFrame(itemDimensions); + frame.left += fLeftInset; + frame.top += fTopInset; + frame.right += fLeftInset; + frame.bottom += fTopInset; +{ +printf(" frame for item %2d (view: %p): ", i, item->View()); +frame.PrintToStream(); +//BSize min(item->MinSize()); +//BSize max(item->MaxSize()); +//printf(" min: (%.1f, %.1f), max: (%.1f, %.1f)\n", min.width, min.height, +// max.width, max.height); +//if (item->HasHeightForWidth()) { +//float minHeight, maxHeight, preferredHeight; +//item->GetHeightForWidth(frame.Width(), &minHeight, &maxHeight, +// &preferredHeight); +//printf(" hfw: min: %.1f, max: %.1f, pref: %.1f\n", minHeight, maxHeight, +// preferredHeight); +//} +} + + item->AlignInFrame(frame); + } +//else +//printf(" item %2d not visible", i); + } +} + +// AddInsets +BSize +BTwoDimensionalLayout::AddInsets(BSize size) +{ + size.width = BLayoutUtils::AddDistances(size.width, + fLeftInset + fRightInset - 1); + size.height = BLayoutUtils::AddDistances(size.height, + fTopInset + fBottomInset - 1); + return size; +} + +// AddInsets +void +BTwoDimensionalLayout::AddInsets(float* minHeight, float* maxHeight, + float* preferredHeight) +{ + float insets = fTopInset + fBottomInset - 1; + if (minHeight) + *minHeight = BLayoutUtils::AddDistances(*minHeight, insets); + if (maxHeight) + *maxHeight = BLayoutUtils::AddDistances(*maxHeight, insets); + if (preferredHeight) + *preferredHeight = BLayoutUtils::AddDistances(*preferredHeight, insets); +} + +// SubtractInsets +BSize +BTwoDimensionalLayout::SubtractInsets(BSize size) +{ + size.width = BLayoutUtils::SubtractDistances(size.width, + fLeftInset + fRightInset - 1); + size.height = BLayoutUtils::SubtractDistances(size.height, + fTopInset + fBottomInset - 1); + return size; +} + +// PrepareItems +void +BTwoDimensionalLayout::PrepareItems(enum orientation orientation) +{ +} + +// HasMultiColumnItems +bool +BTwoDimensionalLayout::HasMultiColumnItems() +{ + return false; +} + +// HasMultiRowItems +bool +BTwoDimensionalLayout::HasMultiRowItems() +{ + return false; +} + +// _ValidateMinMax +void +BTwoDimensionalLayout::_ValidateMinMax() +{ + fLocalLayouter->ValidateMinMax(); +} + +// _CurrentLayoutContext +BLayoutContext* +BTwoDimensionalLayout::_CurrentLayoutContext() +{ + BView* view = View(); + return (view ? view->LayoutContext() : NULL); +} + + +// #pragma mark - CompoundLayouter + +// constructor +BTwoDimensionalLayout::CompoundLayouter::CompoundLayouter( + enum orientation orientation) + : fLayouter(NULL), + fLayoutInfo(NULL), + fOrientation(orientation), + fLocalLayouters(10), + fLayoutContext(NULL), + fLastLayoutSize(-1) +{ +} + +// destructor +BTwoDimensionalLayout::CompoundLayouter::~CompoundLayouter() +{ +} + +// Orientation +orientation +BTwoDimensionalLayout::CompoundLayouter::Orientation() +{ + return fOrientation; +} + +// GetLayouter +Layouter* +BTwoDimensionalLayout::CompoundLayouter::GetLayouter(bool minMax) +{ + return fLayouter; +} + +// GetLayoutInfo +LayoutInfo* +BTwoDimensionalLayout::CompoundLayouter::GetLayoutInfo() +{ + return fLayoutInfo; +} + +// AddLocalLayouter +void +BTwoDimensionalLayout::CompoundLayouter::AddLocalLayouter( + LocalLayouter* localLayouter) +{ + if (localLayouter) { + if (!fLocalLayouters.HasItem(localLayouter)) { + fLocalLayouters.AddItem(localLayouter); + InvalidateLayout(); + } + } +} + +// RemoveLocalLayouter +void +BTwoDimensionalLayout::CompoundLayouter::RemoveLocalLayouter( + LocalLayouter* localLayouter) +{ + if (fLocalLayouters.RemoveItem(localLayouter)) + InvalidateLayout(); +} + +// AbsorbCompoundLayouter +void +BTwoDimensionalLayout::CompoundLayouter::AbsorbCompoundLayouter( + CompoundLayouter* other) +{ + if (other == this) + return; + + int32 count = other->fLocalLayouters.CountItems(); + for (int32 i = 0; i < count; i++) { + LocalLayouter* layouter + = (LocalLayouter*)other->fLocalLayouters.ItemAt(i); + AddLocalLayouter(layouter); + layouter->SetCompoundLayouter(this, fOrientation); + } + + InvalidateLayout(); +} + +// InvalidateLayout +void +BTwoDimensionalLayout::CompoundLayouter::InvalidateLayout() +{ + if (!fLayouter) + return; + + delete fLayouter; + delete fLayoutInfo; + + fLayouter = NULL; + fLayoutInfo = NULL; + fLayoutContext = NULL; + + // notify all local layouters to invalidate the respective views + int32 count = fLocalLayouters.CountItems(); + for (int32 i = 0; i < count; i++) { + LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i); + layouter->InternalInvalidateLayout(this); + } +} + +// IsMinMaxValid +bool +BTwoDimensionalLayout::CompoundLayouter::IsMinMaxValid() +{ + return (fLayouter != NULL); +} + +// ValidateMinMax +void +BTwoDimensionalLayout::CompoundLayouter::ValidateMinMax() +{ + if (IsMinMaxValid()) + return; + + fLastLayoutSize = -1; + + // create the layouter + _PrepareItems(); + + int elementCount = _CountElements(); + + if (elementCount <= 1) + fLayouter = new OneElementLayouter(); + else if (_HasMultiElementItems()) + fLayouter = new ConstraintSolverLayouter(elementCount, _Spacing()); + else + fLayouter = new SimpleLayouter(elementCount, _Spacing()); + + // tell the layouter about our constraints + // TODO: We should probably ignore local layouters whose view is hidden. It's a bit tricky to find + // out, whether the view is hidden, though, since this doesn't necessarily mean only hidden + // relative to the parent, but hidden relative to a common parent. + _AddConstraints(fLayouter); + + fLayoutInfo = fLayouter->CreateLayoutInfo(); +} + +// Layout +void +BTwoDimensionalLayout::CompoundLayouter::Layout(float size, + LocalLayouter* localLayouter, BLayoutContext* context) +{ + ValidateMinMax(); + + if (context != fLayoutContext || fLastLayoutSize != size) { + DoLayout(size, localLayouter, context); + fLayoutContext = context; + fLastLayoutSize = size; + } +} + +// DoLayout +void +BTwoDimensionalLayout::CompoundLayouter::DoLayout(float size, + LocalLayouter* localLayouter, BLayoutContext* context) +{ + fLayouter->Layout(fLayoutInfo, size); +} + +// _PrepareItems +void +BTwoDimensionalLayout::CompoundLayouter::_PrepareItems() +{ + int32 count = fLocalLayouters.CountItems(); + for (int32 i = 0; i < count; i++) { + LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i); + layouter->PrepareItems(this); + } +} + +// _CountElements +int32 +BTwoDimensionalLayout::CompoundLayouter::_CountElements() +{ + int32 elementCount = 0; + int32 count = fLocalLayouters.CountItems(); + for (int32 i = 0; i < count; i++) { + LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i); + int32 layouterCount = layouter->CountElements(this); + elementCount = max_c(elementCount, layouterCount); + } + + return elementCount; +} + +// _HasMultiElementItems +bool +BTwoDimensionalLayout::CompoundLayouter::_HasMultiElementItems() +{ + int32 count = fLocalLayouters.CountItems(); + for (int32 i = 0; i < count; i++) { + LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i); + if (layouter->HasMultiElementItems(this)) + return true; + } + + return false; +} + +// _AddConstraints +void +BTwoDimensionalLayout::CompoundLayouter::_AddConstraints(Layouter* layouter) +{ + int32 count = fLocalLayouters.CountItems(); + for (int32 i = 0; i < count; i++) { + LocalLayouter* localLayouter = (LocalLayouter*)fLocalLayouters.ItemAt(i); + localLayouter->AddConstraints(this, layouter); + } +} + +// _Spacing +float +BTwoDimensionalLayout::CompoundLayouter::_Spacing() +{ + if (!fLocalLayouters.IsEmpty()) + return ((LocalLayouter*)fLocalLayouters.ItemAt(0))->Spacing(this); + return 0; +} + + +// #pragma mark - VerticalCompoundLayouter + + +// constructor +BTwoDimensionalLayout::VerticalCompoundLayouter::VerticalCompoundLayouter() + : CompoundLayouter(B_VERTICAL), + fHeightForWidthLayouter(NULL), + fCachedMinHeightForWidth(0), + fCachedMaxHeightForWidth(0), + fCachedPreferredHeightForWidth(0), + fHeightForWidthLayoutContext(NULL) +{ +} + +// GetLayouter +Layouter* +BTwoDimensionalLayout::VerticalCompoundLayouter::GetLayouter(bool minMax) +{ + return (minMax || !_HasHeightForWidth() + ? fLayouter : fHeightForWidthLayouter); +} + +// InvalidateLayout +void +BTwoDimensionalLayout::VerticalCompoundLayouter::InvalidateLayout() +{ + CompoundLayouter::InvalidateLayout(); + + InvalidateHeightForWidth(); +} + +// InvalidateHeightForWidth +void +BTwoDimensionalLayout::VerticalCompoundLayouter::InvalidateHeightForWidth() +{ + if (fHeightForWidthLayouter != NULL) { + delete fHeightForWidthLayouter; + fHeightForWidthLayouter = NULL; + + // also make sure we're not reusing the old layout info + fLastLayoutSize = -1; + + int32 count = fLocalLayouters.CountItems(); + for (int32 i = 0; i < count; i++) { + LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i); + layouter->SetHeightForWidthConstraintsAdded(false); + } + } +} + +// InternalGetHeightForWidth +void +BTwoDimensionalLayout::VerticalCompoundLayouter::InternalGetHeightForWidth( + LocalLayouter* localLayouter, BLayoutContext* context, bool realLayout, + float* minHeight, float* maxHeight, float* preferredHeight) +{ + bool updateCachedInfo = false; + + if (_SetHeightForWidthLayoutContext(context) + || fHeightForWidthLayouter == NULL) { + // Either the layout context changed or we haven't initialized the + // height for width layouter yet. We create it and init it now. + + // clone the vertical layouter + delete fHeightForWidthLayouter; + delete fLayoutInfo; + fHeightForWidthLayouter = fLayouter->CloneLayouter(); + fLayoutInfo = fHeightForWidthLayouter->CreateLayoutInfo(); + + // add the children's height for width constraints + int32 count = fLocalLayouters.CountItems(); + for (int32 i = 0; i < count; i++) { + LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i); + if (layouter->HasHeightForWidth()) { + layouter->AddHeightForWidthConstraints(this, + fHeightForWidthLayouter, context); + } + } + + updateCachedInfo = true; + + // get the height for width info + fCachedMinHeightForWidth = fHeightForWidthLayouter->MinSize(); + fCachedMaxHeightForWidth = fHeightForWidthLayouter->MaxSize(); + fCachedPreferredHeightForWidth + = fHeightForWidthLayouter->PreferredSize(); + + } else if (localLayouter->HasHeightForWidth()) { + // There is a height for width layouter and it has been initialized + // in the current layout context. So we just add the height for width + // constraints of the calling local layouter, if they haven't been + // added yet. + updateCachedInfo = localLayouter->AddHeightForWidthConstraints(this, + fHeightForWidthLayouter, context); + } + + // update cached height for width info, if something changed + if (updateCachedInfo) { + // get the height for width info + fCachedMinHeightForWidth = fHeightForWidthLayouter->MinSize(); + fCachedMaxHeightForWidth = fHeightForWidthLayouter->MaxSize(); + fCachedPreferredHeightForWidth + = fHeightForWidthLayouter->PreferredSize(); + } + + if (minHeight) + *minHeight = fCachedMinHeightForWidth; + if (maxHeight) + *maxHeight = fCachedMaxHeightForWidth; + if (preferredHeight) + *preferredHeight = fCachedPreferredHeightForWidth; +} + +// DoLayout +void +BTwoDimensionalLayout::VerticalCompoundLayouter::DoLayout(float size, + LocalLayouter* localLayouter, BLayoutContext* context) +{ + Layouter* layouter; + if (_HasHeightForWidth()) { + float minHeight, maxHeight, preferredHeight; + InternalGetHeightForWidth(localLayouter, context, true, &minHeight, + &maxHeight, &preferredHeight); + size = max_c(size, minHeight); + layouter = fHeightForWidthLayouter; + } else + layouter = fLayouter; + + layouter->Layout(fLayoutInfo, size); +} + +// _HasHeightForWidth +bool +BTwoDimensionalLayout::VerticalCompoundLayouter::_HasHeightForWidth() +{ + int32 count = fLocalLayouters.CountItems(); + for (int32 i = 0; i < count; i++) { + LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i); + if (layouter->HasHeightForWidth()) + return true; + } + + return false; +} + +// _SetHeightForWidthLayoutContext +bool +BTwoDimensionalLayout::VerticalCompoundLayouter + ::_SetHeightForWidthLayoutContext(BLayoutContext* context) +{ + if (context == fHeightForWidthLayoutContext) + return false; + + if (fHeightForWidthLayoutContext != NULL) { + fHeightForWidthLayoutContext->RemoveListener(this); + fHeightForWidthLayoutContext = NULL; + } + + // We can ignore the whole context business, if we have no more than one + // local layouter. We use the layout context only to recognize when calls + // of different local layouters belong to the same context. + if (fLocalLayouters.CountItems() <= 1) + return false; + + fHeightForWidthLayoutContext = context; + + if (fHeightForWidthLayoutContext != NULL) + fHeightForWidthLayoutContext->AddListener(this); + + InvalidateHeightForWidth(); + + return true; +} + +// LayoutContextLeft +void +BTwoDimensionalLayout::VerticalCompoundLayouter::LayoutContextLeft( + BLayoutContext* context) +{ + fHeightForWidthLayoutContext = NULL; +} + + +// #pragma mark - LocalLayouter + + +// constructor +BTwoDimensionalLayout::LocalLayouter::LocalLayouter( + BTwoDimensionalLayout* layout) + : fLayout(layout), + fHLayouter(new CompoundLayouter(B_HORIZONTAL)), + fVLayouter(new VerticalCompoundLayouter), + fHeightForWidthItems(), + fHorizontalLayoutContext(NULL), + fHorizontalLayoutWidth(0), + fHeightForWidthConstraintsAdded(false) +{ + fHLayouter->AddLocalLayouter(this); + fVLayouter->AddLocalLayouter(this); +} + +// MinSize +BSize +BTwoDimensionalLayout::LocalLayouter::MinSize() +{ + return BSize(fHLayouter->GetLayouter(true)->MinSize(), + fVLayouter->GetLayouter(true)->MinSize()); +} + +// MaxSize +BSize +BTwoDimensionalLayout::LocalLayouter::MaxSize() +{ + return BSize(fHLayouter->GetLayouter(true)->MaxSize(), + fVLayouter->GetLayouter(true)->MaxSize()); +} + +// PreferredSize +BSize +BTwoDimensionalLayout::LocalLayouter::PreferredSize() +{ + return BSize(fHLayouter->GetLayouter(true)->PreferredSize(), + fVLayouter->GetLayouter(true)->PreferredSize()); +} + +// InvalidateLayout +void +BTwoDimensionalLayout::LocalLayouter::InvalidateLayout() +{ + fHLayouter->InvalidateLayout(); + fVLayouter->InvalidateLayout(); +} + +// Layout +void +BTwoDimensionalLayout::LocalLayouter::Layout(BSize size) +{ + DoHorizontalLayout(size.width); + fVLayouter->Layout(size.height, this, fLayout->_CurrentLayoutContext()); +} + +// ItemFrame +BRect +BTwoDimensionalLayout::LocalLayouter::ItemFrame(Dimensions itemDimensions) +{ + LayoutInfo* hLayoutInfo = fHLayouter->GetLayoutInfo(); + LayoutInfo* vLayoutInfo = fVLayouter->GetLayoutInfo(); + float x = hLayoutInfo->ElementLocation(itemDimensions.x); + float y = vLayoutInfo->ElementLocation(itemDimensions.y); + float width = hLayoutInfo->ElementRangeSize(itemDimensions.x, + itemDimensions.width); + float height = vLayoutInfo->ElementRangeSize(itemDimensions.y, + itemDimensions.height); + return BRect(x, y, x + width, y + height); +} + +// ValidateMinMax +void +BTwoDimensionalLayout::LocalLayouter::ValidateMinMax() +{ + if (fHLayouter->IsMinMaxValid() && fVLayouter->IsMinMaxValid()) + return; + + if (!fHLayouter->IsMinMaxValid()) + fHeightForWidthItems.MakeEmpty(); + + _SetHorizontalLayoutContext(NULL, -1); + + fHLayouter->ValidateMinMax(); + fVLayouter->ValidateMinMax(); +} + +// DoHorizontalLayout +void +BTwoDimensionalLayout::LocalLayouter::DoHorizontalLayout(float width) +{ + BLayoutContext* context = fLayout->_CurrentLayoutContext(); + if (fHorizontalLayoutContext != context + || width != fHorizontalLayoutWidth) { + _SetHorizontalLayoutContext(context, width); + fHLayouter->Layout(width, this, context); + fVLayouter->InvalidateHeightForWidth(); + } +} + +// InternalGetHeightForWidth +void +BTwoDimensionalLayout::LocalLayouter::InternalGetHeightForWidth(float width, + float* minHeight, float* maxHeight, float* preferredHeight) +{ + DoHorizontalLayout(width); + fVLayouter->InternalGetHeightForWidth(this, fHorizontalLayoutContext, false, + minHeight, maxHeight, preferredHeight); +} + +// AlignWith +void +BTwoDimensionalLayout::LocalLayouter::AlignWith(LocalLayouter* other, + enum orientation orientation) +{ + if (orientation == B_HORIZONTAL) + other->fHLayouter->AbsorbCompoundLayouter(fHLayouter); + else + other->fVLayouter->AbsorbCompoundLayouter(fVLayouter); +} + +// PrepareItems +void +BTwoDimensionalLayout::LocalLayouter::PrepareItems( + CompoundLayouter* compoundLayouter) +{ + fLayout->PrepareItems(compoundLayouter->Orientation()); +} + +// CountElements +int32 +BTwoDimensionalLayout::LocalLayouter::CountElements( + CompoundLayouter* compoundLayouter) +{ + if (compoundLayouter->Orientation() == B_HORIZONTAL) + return fLayout->InternalCountColumns(); + else + return fLayout->InternalCountRows(); +} + +// HasMultiElementItems +bool +BTwoDimensionalLayout::LocalLayouter::HasMultiElementItems( + CompoundLayouter* compoundLayouter) +{ + if (compoundLayouter->Orientation() == B_HORIZONTAL) + return fLayout->HasMultiColumnItems(); + else + return fLayout->HasMultiRowItems(); +} + +// AddConstraints +void +BTwoDimensionalLayout::LocalLayouter::AddConstraints( + CompoundLayouter* compoundLayouter, Layouter* layouter) +{ + enum orientation orientation = compoundLayouter->Orientation(); + int itemCount = fLayout->CountItems(); + if (itemCount > 0) { + for (int i = 0; i < itemCount; i++) { + BLayoutItem* item = fLayout->ItemAt(i); + if (item->IsVisible()) { + Dimensions itemDimensions; + fLayout->GetItemDimensions(item, &itemDimensions); + + BSize min = item->MinSize(); + BSize max = item->MaxSize(); + BSize preferred = item->PreferredSize(); + + if (orientation == B_HORIZONTAL) { + layouter->AddConstraints( + itemDimensions.x, + itemDimensions.width, + min.width, + max.width, + preferred.width); + + if (item->HasHeightForWidth()) + fHeightForWidthItems.AddItem(item); + + } else { + layouter->AddConstraints( + itemDimensions.y, + itemDimensions.height, + min.height, + max.height, + preferred.height); + } + } + } + + // add column/row constraints + ColumnRowConstraints constraints; + int elementCount = CountElements(compoundLayouter); + for (int element = 0; element < elementCount; element++) { + fLayout->GetColumnRowConstraints(orientation, element, + &constraints); + layouter->SetWeight(element, constraints.weight); + layouter->AddConstraints(element, 1, constraints.min, + constraints.max, constraints.min); + } + } +} + +// Spacing +float +BTwoDimensionalLayout::LocalLayouter::Spacing( + CompoundLayouter* compoundLayouter) +{ + return (compoundLayouter->Orientation() == B_HORIZONTAL + ? fLayout->fHSpacing : fLayout->fVSpacing); +} + +// HasHeightForWidth +bool +BTwoDimensionalLayout::LocalLayouter::HasHeightForWidth() +{ + return !fHeightForWidthItems.IsEmpty(); +} + +// AddHeightForWidthConstraints +bool +BTwoDimensionalLayout::LocalLayouter::AddHeightForWidthConstraints( + VerticalCompoundLayouter* compoundLayouter, Layouter* layouter, + BLayoutContext* context) +{ + if (context != fHorizontalLayoutContext) + return false; + + if (fHeightForWidthConstraintsAdded) + return false; + + LayoutInfo* hLayoutInfo = fHLayouter->GetLayoutInfo(); + + // add the children's height for width constraints + int32 itemCount = fHeightForWidthItems.CountItems(); + for (int32 i = 0; i < itemCount; i++) { + BLayoutItem* item = (BLayoutItem*)fHeightForWidthItems.ItemAt(i); + Dimensions itemDimensions; + fLayout->GetItemDimensions(item, &itemDimensions); + + float minHeight, maxHeight, preferredHeight; + item->GetHeightForWidth( + hLayoutInfo->ElementRangeSize(itemDimensions.x, + itemDimensions.width), + &minHeight, &maxHeight, &preferredHeight); + layouter->AddConstraints( + itemDimensions.y, + itemDimensions.height, + minHeight, + maxHeight, + preferredHeight); + } + + SetHeightForWidthConstraintsAdded(true); + + return true; +} + +// SetHeightForWidthConstraintsAdded +void +BTwoDimensionalLayout::LocalLayouter::SetHeightForWidthConstraintsAdded( + bool added) +{ + fHeightForWidthConstraintsAdded = added; +} + +// SetCompoundLayouter +void +BTwoDimensionalLayout::LocalLayouter::SetCompoundLayouter( + CompoundLayouter* compoundLayouter, enum orientation orientation) +{ + if (orientation == B_HORIZONTAL) + fHLayouter = compoundLayouter; + else + fVLayouter = (VerticalCompoundLayouter*)compoundLayouter; + + InternalInvalidateLayout(compoundLayouter); +} + +// InternalInvalidateLayout +void +BTwoDimensionalLayout::LocalLayouter::InternalInvalidateLayout( + CompoundLayouter* compoundLayouter) +{ + _SetHorizontalLayoutContext(NULL, -1); + + fLayout->BLayout::InvalidateLayout(); +} + +// _SetHorizontalLayoutContext +void +BTwoDimensionalLayout::LocalLayouter::_SetHorizontalLayoutContext( + BLayoutContext* context, float width) +{ + if (context != fHorizontalLayoutContext) { + if (fHorizontalLayoutContext != NULL) + fHorizontalLayoutContext->RemoveListener(this); + + fHorizontalLayoutContext = context; + + if (fHorizontalLayoutContext != NULL) + fHorizontalLayoutContext->AddListener(this); + } + + fHorizontalLayoutWidth = width; +} + +// LayoutContextLeft +void +BTwoDimensionalLayout::LocalLayouter::LayoutContextLeft(BLayoutContext* context) +{ + fHorizontalLayoutContext = NULL; + fHorizontalLayoutWidth = -1; +} diff --git a/src/kits/interface/View.cpp b/src/kits/interface/View.cpp index ec74c9011d..0a580131d6 100644 --- a/src/kits/interface/View.cpp +++ b/src/kits/interface/View.cpp @@ -6,6 +6,7 @@ * Adrian Oanca * Axel Dörfler, axeld@pinc-software.de * Stephan Aßmus + * Ingo Weinhold */ @@ -24,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -310,6 +314,43 @@ ViewState::UpdateFrom(BPrivate::PortLink &link) // #pragma mark - +struct BView::LayoutData { + + LayoutData() + : fMinSize(), + fMaxSize(), + fPreferredSize(), + fAlignment(), + fLayoutInvalidationDisabled(0), + fLayout(NULL), + fLayoutContext(NULL), + fLayoutValid(true), // <- TODO: Rethink this! + fLayoutInProgress(false), + fNeedsRelayout(true) + { + } + + BSize fMinSize; + BSize fMaxSize; + BSize fPreferredSize; + BAlignment fAlignment; + int fLayoutInvalidationDisabled; + BLayout* fLayout; + BLayoutContext* fLayoutContext; + bool fLayoutValid; + bool fLayoutInProgress; + bool fNeedsRelayout; +}; + + +BView::BView(const char* name, uint32 flags, BLayout* layout) +{ + _InitData(BRect(0, 0, 0, 0), name, B_FOLLOW_NONE, + flags | B_SUPPORTS_LAYOUT); + SetLayout(layout); +} + + BView::BView(BRect frame, const char *name, uint32 resizingMode, uint32 flags) : BHandler(name) { @@ -531,7 +572,7 @@ BView::~BView() RemoveSelf(); // TODO: see about BShelf! must I delete it here? is it deleted by the window? - + // we also delete all our children BView *child = fFirstChild; @@ -542,6 +583,10 @@ BView::~BView() child = nextChild; } + // delete the layout and the layout data + delete fLayoutData->fLayout; + delete fLayoutData; + if (fVerScroller) fVerScroller->SetTarget((BView*)NULL); if (fHorScroller) @@ -837,6 +882,9 @@ BView::Hide() fOwner->fLink->StartMessage(AS_LAYER_HIDE); } fShowLevel++; + + if (fShowLevel == 1 && fParent) + fParent->InvalidateLayout(); } @@ -848,6 +896,9 @@ BView::Show() check_lock(); fOwner->fLink->StartMessage(AS_LAYER_SHOW); } + + if (fShowLevel == 0 && fParent) + fParent->InvalidateLayout(); } @@ -3255,11 +3306,34 @@ BView::AddChild(BView *child, BView *before) child && child->Name() ? child->Name(): "NULL", before && before->Name() ? before->Name(): "NULL")); - if (!child) + if (!_AddChild(child, before)) return; - if (child->fParent != NULL) + if (fLayoutData->fLayout) + fLayoutData->fLayout->AddView(child); +} + + +bool +BView::AddChild(BLayoutItem* child) +{ + if (!fLayoutData->fLayout) + return false; + return fLayoutData->fLayout->AddItem(child); +} + + +bool +BView::_AddChild(BView *child, BView *before) +{ + if (!child) + return false; + + if (child->fParent != NULL) { +printf("BView::_AddChild(): child %p already has parent %p\n", child , child->fParent); debugger("AddChild failed - the view already has a parent."); + return false; + } bool lockedOwner = false; if (fOwner && !fOwner->IsLocked()) { @@ -3267,8 +3341,12 @@ BView::AddChild(BView *child, BView *before) lockedOwner = true; } - if (!_AddChildToList(child, before)) - debugger("AddChild failed!"); + if (!_AddChildToList(child, before)) { + debugger("AddChild failed!"); + if (lockedOwner) + fOwner->Unlock(); + return false; + } if (fOwner) { check_lock(); @@ -3280,6 +3358,10 @@ BView::AddChild(BView *child, BView *before) if (lockedOwner) fOwner->Unlock(); } + + InvalidateLayout(); + + return true; } @@ -3294,7 +3376,6 @@ BView::RemoveChild(BView *child) return child->RemoveSelf(); } - int32 BView::CountChildren() const { @@ -3342,6 +3423,16 @@ BView::PreviousSibling() const bool BView::RemoveSelf() +{ + if (fParent && fParent->fLayoutData->fLayout) + return fParent->fLayoutData->fLayout->RemoveView(this); + else + return _RemoveSelf(); +} + + +bool +BView::_RemoveSelf() { STRACE(("BView(%s)::RemoveSelf()...\n", Name())); @@ -3355,7 +3446,8 @@ BView::RemoveSelf() _Detach(); } - if (!fParent || !fParent->_RemoveChildFromList(this)) + BView* parent = fParent; + if (!parent || !parent->_RemoveChildFromList(this)) return false; if (owner != NULL && !fTopLevelView) { @@ -3364,6 +3456,8 @@ BView::RemoveSelf() owner->fLink->Attach(_get_object_token_(this)); } + parent->InvalidateLayout(); + STRACE(("DONE: BView(%s)::RemoveSelf()\n", Name())); return true; @@ -3725,6 +3819,285 @@ BView::Perform(perform_code d, void* arg) } +// #pragma mark - Layout Functions + + +BSize +BView::MinSize() +{ + // TODO: make sure this works correctly when some methods are overridden + float width, height; + GetPreferredSize(&width, &height); + + return BLayoutUtils::ComposeSize(fLayoutData->fMinSize, + (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize() + : BSize(width, height))); +} + + +BSize +BView::MaxSize() +{ + return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize, + (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize() + : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED))); +} + + +BSize +BView::PreferredSize() +{ + // TODO: make sure this works correctly when some methods are overridden + float width, height; + GetPreferredSize(&width, &height); + + return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize, + (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize() + : BSize(width, height))); +} + + +BAlignment +BView::Alignment() +{ + return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment, + (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment() + : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER))); +} + + +void +BView::SetExplicitMinSize(BSize size) +{ + fLayoutData->fMinSize = size; + InvalidateLayout(); +} + + +void +BView::SetExplicitMaxSize(BSize size) +{ + fLayoutData->fMaxSize = size; + InvalidateLayout(); +} + + +void +BView::SetExplicitPreferredSize(BSize size) +{ + fLayoutData->fPreferredSize = size; + InvalidateLayout(); +} + + +void +BView::SetExplicitAlignment(BAlignment alignment) +{ + fLayoutData->fAlignment = alignment; + InvalidateLayout(); +} + + +BSize +BView::ExplicitMinSize() const +{ + return fLayoutData->fMinSize; +} + + +BSize +BView::ExplicitMaxSize() const +{ + return fLayoutData->fMaxSize; +} + + +BSize +BView::ExplicitPreferredSize() const +{ + return fLayoutData->fPreferredSize; +} + + +BAlignment +BView::ExplicitAlignment() const +{ + return fLayoutData->fAlignment; +} + + +bool +BView::HasHeightForWidth() +{ + return (fLayoutData->fLayout + ? fLayoutData->fLayout->HasHeightForWidth() : false); +} + + +void +BView::GetHeightForWidth(float width, float* min, float* max, float* preferred) +{ + if (fLayoutData->fLayout) + fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred); +} + + +void +BView::SetLayout(BLayout* layout) +{ + if (layout == fLayoutData->fLayout) + return; + + fFlags |= B_SUPPORTS_LAYOUT; + + // unset and delete the old layout + if (fLayoutData->fLayout) { + fLayoutData->fLayout->SetView(NULL); + delete fLayoutData->fLayout; + } + + fLayoutData->fLayout = layout; + + if (fLayoutData->fLayout) { + fLayoutData->fLayout->SetView(this); + + // add all children + int count = CountChildren(); + for (int i = 0; i < count; i++) + fLayoutData->fLayout->AddView(ChildAt(i)); + } + + InvalidateLayout(); +} + + +BLayout* +BView::GetLayout() const +{ + return fLayoutData->fLayout; +} + + +void +BView::InvalidateLayout(bool descendants) +{ + if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress + && fLayoutData->fLayoutInvalidationDisabled == 0) { + if (fParent && fParent->fLayoutData->fLayoutValid) + fParent->InvalidateLayout(false); + + fLayoutData->fLayoutValid = false; + + if (fLayoutData->fLayout) + fLayoutData->fLayout->InvalidateLayout(); + + if (descendants) { + int count = CountChildren(); + for (int i = 0; i < count; i++) + ChildAt(i)->InvalidateLayout(descendants); + } + + if (fTopLevelView) { + // trigger layout process + if (fOwner) + fOwner->PostMessage(B_LAYOUT_WINDOW); + } + } +} + + +void +BView::EnableLayoutInvalidation() +{ + if (fLayoutData->fLayoutInvalidationDisabled > 0) + fLayoutData->fLayoutInvalidationDisabled--; +} + + +void +BView::DisableLayoutInvalidation() +{ + fLayoutData->fLayoutInvalidationDisabled++; +} + + +BLayoutContext* +BView::LayoutContext() const +{ + return fLayoutData->fLayoutContext; +} + + +void +BView::Layout(bool force) +{ + BLayoutContext context; + _Layout(force, &context); +} + + +void +BView::Relayout() +{ + if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) { + fLayoutData->fNeedsRelayout = true; + + // Layout() is recursive, that is if the parent view is currently laid + // out, we don't call layout() on this view, but wait for the parent's + // Layout() to do that for us. + if (!fParent || !fParent->fLayoutData->fLayoutInProgress) + Layout(false); + } +} + + +void +BView::DoLayout() +{ + if (fLayoutData->fLayout) + fLayoutData->fLayout->LayoutView(); +} + + +void +BView::_Layout(bool force, BLayoutContext* context) +{ +//printf("%p->BView::_Layout(%d, %p)\n", this, force, context); +//printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n", +//fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid, fLayoutData->fLayoutInProgress); + if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) { + fLayoutData->fLayoutValid = false; + + if (fLayoutData->fLayoutInProgress) + return; + + BLayoutContext* oldContext = fLayoutData->fLayoutContext; + fLayoutData->fLayoutContext = context; + + fLayoutData->fLayoutInProgress = true; + DoLayout(); + fLayoutData->fLayoutInProgress = false; + + fLayoutData->fLayoutValid = true; + fLayoutData->fNeedsRelayout = false; + + // layout children + int32 childCount = CountChildren(); + for (int32 i = 0; i < childCount; i++) { + BView* child = ChildAt(i); + if (!child->IsHidden(child)) + child->_Layout(force, context); + } + + fLayoutData->fLayoutContext = oldContext; + + // invalidate the drawn content, if requested + if (fFlags & B_INVALIDATE_AFTER_LAYOUT) + Invalidate(); + } +} + + // #pragma mark - // Private Functions @@ -3772,6 +4145,8 @@ BView::_InitData(BRect frame, const char *name, uint32 resizingMode, uint32 flag fEventMask = 0; fEventOptions = 0; + + fLayoutData = new LayoutData; } @@ -4010,8 +4385,12 @@ BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight) } // layout the children - for (BView* child = fFirstChild; child; child = child->fNextSibling) - child->_ParentResizedBy(deltaWidth, deltaHeight); + if (fFlags & B_SUPPORTS_LAYOUT) { + Relayout(); + } else { + for (BView* child = fFirstChild; child; child = child->fNextSibling) + child->_ParentResizedBy(deltaWidth, deltaHeight); + } if (fFlags & B_FRAME_EVENTS) { BMessage resized(B_VIEW_RESIZED); @@ -4383,15 +4762,15 @@ BView::do_owner_check_no_pick() const } } - -void BView::_ReservedView2(){} -void BView::_ReservedView3(){} -void BView::_ReservedView4(){} -void BView::_ReservedView5(){} -void BView::_ReservedView6(){} -void BView::_ReservedView7(){} -void BView::_ReservedView8(){} -void BView::_ReservedView9(){} +extern "C" void _ReservedView1__5BView() {} +extern "C" void _ReservedView2__5BView() {} +extern "C" void _ReservedView3__5BView() {} +extern "C" void _ReservedView4__5BView() {} +extern "C" void _ReservedView5__5BView() {} +extern "C" void _ReservedView6__5BView() {} +extern "C" void _ReservedView7__5BView() {} +extern "C" void _ReservedView8__5BView() {} +extern "C" void _ReservedView9__5BView() {} void BView::_ReservedView10(){} void BView::_ReservedView11(){} void BView::_ReservedView12(){} diff --git a/src/kits/interface/ViewLayoutItem.cpp b/src/kits/interface/ViewLayoutItem.cpp new file mode 100644 index 0000000000..f51fd6af33 --- /dev/null +++ b/src/kits/interface/ViewLayoutItem.cpp @@ -0,0 +1,139 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "ViewLayoutItem.h" + +#include + + +// constructor +BViewLayoutItem::BViewLayoutItem(BView* view) + : fView(view) +{ +} + +// destructor +BViewLayoutItem::~BViewLayoutItem() +{ +} + +// MinSize +BSize +BViewLayoutItem::MinSize() +{ + return fView->MinSize(); +} + +// MaxSize +BSize +BViewLayoutItem::MaxSize() +{ + return fView->MaxSize(); +} + +// PreferredSize +BSize +BViewLayoutItem::PreferredSize() +{ + return fView->PreferredSize(); +} + +// Alignment +BAlignment +BViewLayoutItem::Alignment() +{ + return fView->Alignment(); +} + +// SetExplicitMinSize +void +BViewLayoutItem::SetExplicitMinSize(BSize size) +{ + fView->SetExplicitMinSize(size); +} + +// SetExplicitMaxSize +void +BViewLayoutItem::SetExplicitMaxSize(BSize size) +{ + fView->SetExplicitMaxSize(size); +} + +// SetExplicitPreferredSize +void +BViewLayoutItem::SetExplicitPreferredSize(BSize size) +{ + fView->SetExplicitPreferredSize(size); +} + +// SetExplicitAlignment +void +BViewLayoutItem::SetExplicitAlignment(BAlignment alignment) +{ + fView->SetExplicitAlignment(alignment); +} + +// IsVisible +bool +BViewLayoutItem::IsVisible() +{ + return !fView->IsHidden(fView); +} + +// SetVisible +void +BViewLayoutItem::SetVisible(bool visible) +{ + if (visible != IsVisible()) { + if (visible) + fView->Show(); + else + fView->Hide(); + } +} + +// Frame +BRect +BViewLayoutItem::Frame() +{ + return fView->Frame(); +} + +// SetFrame +void +BViewLayoutItem::SetFrame(BRect frame) +{ + fView->MoveTo(frame.LeftTop()); + fView->ResizeTo(frame.Width(), frame.Height()); +} + +// HasHeightForWidth +bool +BViewLayoutItem::HasHeightForWidth() +{ + return fView->HasHeightForWidth(); +} + +// GetHeightForWidth +void +BViewLayoutItem::GetHeightForWidth(float width, float* min, float* max, + float* preferred) +{ + fView->GetHeightForWidth(width, min, max, preferred); +} + +// View +BView* +BViewLayoutItem::View() +{ + return fView; +} + +// InvalidateLayout +void +BViewLayoutItem::InvalidateLayout() +{ + fView->InvalidateLayout(); +} diff --git a/src/kits/interface/ViewLayoutItem.h b/src/kits/interface/ViewLayoutItem.h new file mode 100644 index 0000000000..0fe78ff937 --- /dev/null +++ b/src/kits/interface/ViewLayoutItem.h @@ -0,0 +1,44 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _VIEW_LAYOUT_ITEM_H +#define _VIEW_LAYOUT_ITEM_H + +#include + + +class BViewLayoutItem : public BLayoutItem { +public: + BViewLayoutItem(BView* view); + virtual ~BViewLayoutItem(); + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + virtual BAlignment Alignment(); + + virtual void SetExplicitMinSize(BSize size); + virtual void SetExplicitMaxSize(BSize size); + virtual void SetExplicitPreferredSize(BSize size); + virtual void SetExplicitAlignment(BAlignment alignment); + + virtual bool IsVisible(); + virtual void SetVisible(bool visible); + + virtual BRect Frame(); + virtual void SetFrame(BRect frame); + + virtual bool HasHeightForWidth(); + virtual void GetHeightForWidth(float width, float* min, + float* max, float* preferred); + + virtual BView* View(); + + virtual void InvalidateLayout(); + +private: + BView* fView; +}; + +#endif // _VIEW_LAYOUT_ITEM_H diff --git a/src/kits/interface/Window.cpp b/src/kits/interface/Window.cpp index 743938c273..457c446c94 100644 --- a/src/kits/interface/Window.cpp +++ b/src/kits/interface/Window.cpp @@ -1150,6 +1150,23 @@ FrameMoved(origin); break; } + case B_LAYOUT_WINDOW: + { + if (fFlags & B_AUTO_UPDATE_SIZE_LIMITS) { + // Get min/max constraints of the top view and enforce window + // size limits respectively. + BSize minSize = fTopView->MinSize(); + BSize maxSize = fTopView->MaxSize(); + SetSizeLimits(minSize.width, maxSize.width, + minSize.height, maxSize.height); + } + + // do the actual layout + fTopView->Layout(false); + + break; + } + default: BLooper::DispatchMessage(msg, target); break; @@ -2214,6 +2231,27 @@ BWindow::Run() } +void +BWindow::SetLayout(BLayout* layout) +{ + fTopView->SetLayout(layout); +} + + +BLayout* +BWindow::GetLayout() const +{ + return fTopView->GetLayout(); +} + + +void +BWindow::InvalidateLayout(bool descendants) +{ + fTopView->InvalidateLayout(descendants); +} + + status_t BWindow::GetSupportedSuites(BMessage *data) { diff --git a/src/kits/interface/layouter/ConstraintSolverLayouter.cpp b/src/kits/interface/layouter/ConstraintSolverLayouter.cpp new file mode 100644 index 0000000000..9e15016be4 --- /dev/null +++ b/src/kits/interface/layouter/ConstraintSolverLayouter.cpp @@ -0,0 +1,1680 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "ConstraintSolverLayouter.h" + +#include +#include + +#include +#include +#include + +#include "SimpleLayouter.h" + +// Since the qoca headers are DEBUG and NDEBUG conditional, we get +// incompatibilities when compiling this file with debugging and qoca +// without. So we consistently don't allow qoca to be compiled with +// debugging and undefine the macros before using the includes. +#undef DEBUG +#undef NDEBUG + +#include +#include +#include +#include + + + +// This monster is a Layouter implementation similar to SimpleLayouter with +// the difference that it accepts min/max constraints over several elements, +// i.e. not only constraints of the form x_i <=/>= a, but also of the form +// x_i + x_{i+1} + ... x_{i+m} <=/>= a. This adds significant complexity, +// hence we employ a constraint solver, QOCA's QcLinInEqSolver, to find +// solutions. +// +// Two main problems remain, though: +// 1) QOCA supplies us with a real value solution, while we actually need an +// integer solution. Generally finding an optimal integer solution for +// a inequation system is at least NP hard (AFAIK even undecidable, if +// the variables are not restricted to >= 0). Fortunately our system has +// special properties that make things less complex. I haven't found +// anything related in the literature, but I've designed an algorithm that +// derives an integer solution from a real value solution. I wasn't able +// to prove, that there's always an integer solution given there's a +// real value solution (though I've the feeling that this is the case), +// but if there is one, the algorithm should be able to find it. +// 2) Constraints given to the layouter may be contradictory. If that is the +// case, we try to relax constraints such that they become +// non-contradictory again. We use heuristics to do this, like preferring +// min constraints over max constraints, ones with few involved variables +// over ones with many involved variables. + + +//#define ERROR_MESSAGE(message...) {} +#define ERROR_MESSAGE(message...) { printf(message); } + + +// no lround() under BeOS R5 x86 +#ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST +# define lround(x) (long)floor((x) + 0.5) +#endif + + +// Set +class ConstraintSolverLayouter::Set { +public: + Set() + : fElements() + { + } + + BList& ToList() + { + return fElements; + } + + const BList& ToList() const + { + return fElements; + } + + bool Add(void* element) + { + if (fElements.HasItem(element)) + return false; + + fElements.AddItem(element); + return true; + } + + void AddAll(const Set& other) + { + AddAll(other.ToList()); + } + + void AddAll(const BList& other) + { + int32 count = other.CountItems(); + for (int32 i = 0; i < count; i++) + Add(other.ItemAt(i)); + } + + bool Remove(void* element) + { + return fElements.RemoveItem(element); + } + + void MakeEmpty() + { + fElements.MakeEmpty(); + } + + bool Contains(void* element) const + { + return fElements.HasItem(element); + } + + int32 Size() const + { + return fElements.CountItems(); + } + + bool IsEmpty() const + { + return fElements.IsEmpty(); + } + + void* Get(int32 index) const + { + return fElements.ItemAt(index); + } + +private: + BList fElements; +}; + + +// Variable +class ConstraintSolverLayouter::Variable { +public: + Variable() + : fQocaVariable(NULL), + fValue(0), + fIndex(-1) + { + } + + Variable(const char* name) + : fQocaVariable(new QcFloat(name, true)), + fValue(0), + fIndex(-1) + { + } + + Variable(int32 index) + : fQocaVariable(NULL), + fValue(0), + fIndex(index) + { + Init(index); + } + + ~Variable() + { + delete fQocaVariable; + } + + void Init(int32 index) + { + delete fQocaVariable; + + fIndex = index; + + BString name("x"); + name << index; + fQocaVariable = new QcFloat(name.String(), true); + } + + int32 Index() const + { + return fIndex; + } + + QcFloat* QocaVariable() const + { + return fQocaVariable; + } + + double SolvedValue() const + { + return fQocaVariable->Value(); + } + + int32 IntValue() const + { + return fValue; + } + + void SetIntValue(int32 value) + { + fValue = value; + } + +private: + QcFloat* fQocaVariable; + int32 fValue; + int32 fIndex; +}; + + +// Constraint +class ConstraintSolverLayouter::Constraint { +public: + Constraint(ConstraintSolverLayouter* layouter, + int32 first, int32 last, int32 value) + : fLayouter(layouter), + fFirst(first), + fLast(last), + fOriginalValue(-1), // so SetOriginalValue() detects a difference + fValue(-1), // so SetValue() detects a difference + fPolynom(NULL), + fQocaConstraint(NULL), + fAdded(false), + fAlgorithmData(0) + + { + fPolynom = new QcLinPoly(); + for (int i = first; i <= last; i++) + fPolynom->Push(1, *fLayouter->fVariables[i].QocaVariable()); + fQocaConstraint = new QcConstraint(); + } + + + virtual ~Constraint() + { + delete fPolynom; + delete fQocaConstraint; + } + + virtual Constraint* CloneConstraint(ConstraintSolverLayouter* layouter) = 0; + + int32 First() const + { + return fFirst; + } + + int32 Last() const + { + return fLast; + } + + int32 OriginalValue() const + { + return fOriginalValue; + } + + void SetOriginalValue(int32 value) + { + if (value != fOriginalValue) { + fOriginalValue = value; + SetValue(value); + } + } + + virtual void RestrictOriginalValue(int32 value) = 0; + + int32 Value() const + { + return fValue; + } + + void SetValue(int32 value) + { + if (value == fValue) + return; + + fValue = value; + + UpdateQocaConstraint(); + } + + int32 AlgorithmData() const + { + return fAlgorithmData; + } + + void SetAlgorithmData(int32 algorithmData) + { + fAlgorithmData = algorithmData; + } + + QcConstraint* QocaConstraint() const + { + return fQocaConstraint; + } + + bool IsAdded() const + { + return fAdded; + } + + void SetAdded(bool added) + { + fAdded = added; + } + + bool IsSatisfied() const + { + return (ComputeSatisfactionDistance() <= 0); + } + + /** + * Returns the distance the sum value need to change for the constraint to + * get satisfied. + * + * A negative return value means that the constraint is satisfied and its + * absolute value is the distance the sum can change to be still satisfied. + * + * @return the distance the sum value need to change for the constraint to + * get satisfied. + */ + virtual int32 ComputeSatisfactionDistance() const = 0; + + virtual void UpdateQocaConstraint() = 0; + + int32 ComputeVariableSum() const + { + int sum = 0; + for (int i = fFirst; i <= fLast; i++) + sum += fLayouter->fVariables[i].IntValue(); + + return sum; + } + + +protected: + ConstraintSolverLayouter* fLayouter; + + int32 fFirst; + int32 fLast; + int32 fOriginalValue; // The value the user set. + int32 fValue; // The value we inferred (addConstraints()). + // Might be more restrictive or lax. + + QcLinPoly* fPolynom; + QcConstraint* fQocaConstraint; + + bool fAdded; + +private: + int32 fAlgorithmData; +}; + + +// MinConstraint +class ConstraintSolverLayouter::MinConstraint : public Constraint { +public: + MinConstraint(ConstraintSolverLayouter* layouter, int32 first, int32 last, + int32 value) + : Constraint(layouter, first, last, value) + { + SetOriginalValue(value); + } + + virtual Constraint* CloneConstraint(ConstraintSolverLayouter* layouter) + { + Constraint* constraint = new MinConstraint(layouter, fFirst, fLast, + fOriginalValue); + + constraint->SetValue(fValue); + + return constraint; + } + + virtual void RestrictOriginalValue(int32 value) + { + SetOriginalValue(max_c(fOriginalValue, value)); + } + + virtual void UpdateQocaConstraint() + { + fQocaConstraint->makeGe(fPolynom, fValue); + } + + virtual int32 ComputeSatisfactionDistance() const + { + return fValue - ComputeVariableSum(); + } + +// public String toString() { +// return "Constraint[sum (x" + fFirst + " ... x" + fLast + ") >= " + fValue + "]"; +// } +}; + + +// MaxConstraint +class ConstraintSolverLayouter::MaxConstraint : public Constraint { +public: + MaxConstraint(ConstraintSolverLayouter* layouter, int32 first, int32 last, + int32 value) + : Constraint(layouter, first, last, value) + { + SetOriginalValue(value); + } + + virtual Constraint* CloneConstraint(ConstraintSolverLayouter* layouter) + { + Constraint* constraint = new MaxConstraint(layouter, fFirst, fLast, + fOriginalValue); + + constraint->SetValue(fValue); + + return constraint; + } + + virtual void RestrictOriginalValue(int32 value) + { + SetOriginalValue(min_c(fOriginalValue, value)); + } + + virtual void UpdateQocaConstraint() + { + fQocaConstraint->makeLe(fPolynom, fValue); + } + + virtual int32 ComputeSatisfactionDistance() const + { + return ComputeVariableSum() - fValue; + } + +// public String toString() { +// return "Constraint[sum (x" + fFirst + " ... x" + fLast + ") <= " + fValue + "]"; +// } +}; + + +// MinMaxEntry +class ConstraintSolverLayouter::MinMaxEntry { +public: + Constraint* minConstraint; + Constraint* maxConstraint; + int32 min; + int32 max; + int32 requiredMax; + + MinMaxEntry() + : minConstraint(NULL), + maxConstraint(NULL), + min(0), + max(B_SIZE_UNLIMITED), + requiredMax(0) + { + } + + void SetMinConstraint(Constraint* minConstraint) + { + this->minConstraint = minConstraint; + if (minConstraint != NULL) + min = minConstraint->OriginalValue(); + } + + void SetMaxConstraint(Constraint* maxConstraint) + { + this->maxConstraint = maxConstraint; + if (maxConstraint != NULL) + max = max_c(min, maxConstraint->OriginalValue()); + } +}; + + +// MinMaxMatrix +class ConstraintSolverLayouter::MinMaxMatrix { +public: + MinMaxMatrix(int size) + : fSize(size), + fEntries(NULL) + { + int count = size * (size + 1) / 2; + fEntries = new MinMaxEntry[count]; + } + + ~MinMaxMatrix() + { + delete[] fEntries; + } + + MinMaxEntry& Entry(int32 first, int32 last) + { + return fEntries[first * (2 * fSize - first + 1) / 2 + (last - first)]; + } + +private: + int32 fSize; + MinMaxEntry* fEntries; +}; + + +// MyLayoutInfo +class ConstraintSolverLayouter::MyLayoutInfo : public LayoutInfo { +public: + MyLayoutInfo(int32 elementCount) + : fCount(elementCount) + { + fLocations = new int32[elementCount]; + fSizes = new int32[elementCount]; + } + + ~MyLayoutInfo() + { + delete fLocations; + delete fSizes; + } + + virtual float ElementLocation(int32 element) + { + if (element < 0 || element >= fCount) + return 0; + + return fLocations[element]; + } + + virtual float ElementSize(int32 element) + { + if (element < 0 || element >= fCount) + return -1; + + return fSizes[element] - 1; + } + + void Dump() + { + printf("ConstraintSolverLayouter::MyLayoutInfo(): %ld elements:\n", + fCount); + for (int32 i = 0; i < fCount; i++) { + printf(" %2ld: location: %4ld, size: %4ld\n", i, fLocations[i], + fSizes[i]); + } + } + +public: + int32 fCount; + int32* fLocations; + int32* fSizes; +}; + + +// #pragma mark - ConstraintSolverLayouter + + +// constructor +ConstraintSolverLayouter::ConstraintSolverLayouter(int32 elementCount, + int32 spacing) + : fElementCount(elementCount), + fWeights(NULL), + fBasicMinConstraints(NULL), + fBasicMaxConstraints(NULL), + fComplexMinConstraints(), + fComplexMaxConstraints(), + fVariables(NULL), + fSizeVariable(NULL), + fSolver(NULL), + fSizeSumConstraint(NULL), + fSetSizeConstraint(NULL), + fConstraintsAdded(false), + fSetSizeConstraintAdded(false), + fSpacing(spacing), + fMin(0), + fMax(B_SIZE_UNLIMITED), + fMinMaxValid(false), + fLayoutInfo(NULL) +{ + fWeights = new float[fElementCount]; + for (int32 i = 0; i < fElementCount; i++) + fWeights[i] = 1; + + fBasicMinConstraints = new Constraint*[fElementCount]; + fBasicMaxConstraints = new Constraint*[fElementCount]; + + memset(fBasicMinConstraints, 0, sizeof(Constraint*) * fElementCount); + memset(fBasicMaxConstraints, 0, sizeof(Constraint*) * fElementCount); + + fSolver = new QcLinInEqSolver(); + + fVariables = new Variable[fElementCount]; + for (int i = 0; i < fElementCount; i++) { + fVariables[i].Init(i); + fSolver->AddVar(*fVariables[i].QocaVariable()); + } + + fSizeVariable = new Variable("size"); + fSolver->AddVar(*fSizeVariable->QocaVariable()); + + // create size sum constraint (x1 + x2 + ... xn == size) + QcLinPoly* polynom = new QcLinPoly(); + for (int i = 0; i < fElementCount; i++) + polynom->Push(1, *fVariables[i].QocaVariable()); + polynom->Push(-1, *fSizeVariable->QocaVariable()); + + fSizeSumConstraint = new QcConstraint(); + fSizeSumConstraint->makeEq(polynom, 0); + + // create set size constraint (size == ) + polynom = new QcLinPoly(); + polynom->Push(1, *fSizeVariable->QocaVariable()); + + fSetSizeConstraint = new QcConstraint(); + fSetSizeConstraint->makeEq(polynom, 0); +} + +// destructor +ConstraintSolverLayouter::~ConstraintSolverLayouter() +{ + delete fSetSizeConstraint; + delete fSizeSumConstraint; + delete fSizeVariable; + delete[] fVariables; + delete fSolver; + + delete[] fWeights; + delete[] fBasicMinConstraints; + delete[] fBasicMaxConstraints; +} + +// AddConstraints +void +ConstraintSolverLayouter::AddConstraints(int32 element, int32 length, + float _min, float _max, float _preferred) +{ + if (length <= 0 || length > fElementCount) + return; + if (element < 0 || element + length > fElementCount) + return; + + int32 min = (int32)_min + 1; + int32 max = (int32)_max + 1; +// int32 preferred = (int32)_preferred + 1; + + int32 last = element + length - 1; + int32 spacing = (length - 1) * fSpacing; + _AddMinConstraint(element, last, min - spacing); + _AddMaxConstraint(element, last, max - spacing); + + fMinMaxValid = false; +} + +// SetWeight +void +ConstraintSolverLayouter::SetWeight(int32 element, float weight) +{ + if (element < 0 || element >= fElementCount) + return; + + fWeights[element] = max_c(weight, 0); +} + +// MinSize +float +ConstraintSolverLayouter::MinSize() +{ + _ValidateMinMax(); + return fMin - 1; +} + +// MaxSize +float +ConstraintSolverLayouter::MaxSize() +{ + _ValidateMinMax(); + return fMax - 1; +} + +// PreferredSize +float +ConstraintSolverLayouter::PreferredSize() +{ + _ValidateMinMax(); + return fMin - 1; +} + +// CreateLayoutInfo +LayoutInfo* +ConstraintSolverLayouter::CreateLayoutInfo() +{ + return new MyLayoutInfo(fElementCount); +} + +// Layout +void +ConstraintSolverLayouter::Layout(LayoutInfo* layoutInfo, float _size) +{ +//printf("ConstraintSolverLayouter::Layout(%p, %.1f): min: %ld, max: %ld\n", +//layoutInfo, _size, fMin, fMax); + int32 size = (int32)_size + 1; + + fLayoutInfo = (MyLayoutInfo*)layoutInfo; + + _ValidateMinMax(); + + if (fElementCount == 0) + return; + + if (size < fMin) + size = fMin; + + int32 additionalSpace = max_c(size - fMax, 0); + size -= additionalSpace; + int32 spacing = (fElementCount - 1) * fSpacing; + if (!_ComputeSolution(size - spacing)) { + ERROR_MESSAGE("ConstraintSolverLayouter::Layout(): no solution\n"); + // no solution + return; + } + + // If there is additional space, distribute it according to the elements' + // weights. + if (additionalSpace > 0) { +// Mmh, distributing according to the weights doesn't look that good. +// int[] sizes = new int[fElementCount]; +// SimpleLayouter.distributeSize(additionalSpace, fWeights, sizes); +// +// for (int i = 0; i < fElementCount; i++) { +// Variable var = fVariables[i]; +// var.setIntValue(var.getIntValue() + sizes[i]); +// } + + // distribute the additional space equally + int64 sumSize = 0; + for (int i = 0; i < fElementCount; i++) { + Variable& var = fVariables[i]; + int64 oldSumSize = sumSize; + sumSize = (i + 1) * additionalSpace / fElementCount; + var.SetIntValue(var.IntValue() + (int32)(sumSize - oldSumSize)); + } + } + + // compute locations + int location = 0; + for (int i = 0; i < fElementCount; i++) { + fLayoutInfo->fLocations[i] = location; + fLayoutInfo->fSizes[i] = fVariables[i].IntValue(); + location += fSpacing + fLayoutInfo->fSizes[i]; + } + +//fLayoutInfo->Dump(); +} + +// CloneLayouter +Layouter* +ConstraintSolverLayouter::CloneLayouter() +{ + ConstraintSolverLayouter* layouter + = new ConstraintSolverLayouter(fElementCount, fSpacing); + + memcpy(layouter->fWeights, fWeights, sizeof(float) * fElementCount); + + for (int i = 0; i < fElementCount; i++) { + Constraint* constraint = fBasicMinConstraints[i]; + if (constraint != NULL) { + layouter->fBasicMinConstraints[i] + = constraint->CloneConstraint(layouter); + } + + constraint = fBasicMaxConstraints[i]; + if (constraint != NULL) { + layouter->fBasicMaxConstraints[i] + = constraint->CloneConstraint(layouter); + } + } + + int32 count = fComplexMinConstraints.CountItems(); + for (int32 i = 0; i < count; i++) { + Constraint* constraint = (Constraint*)fComplexMinConstraints.ItemAt(i); + layouter->fComplexMinConstraints.AddItem( + constraint->CloneConstraint(layouter)); + } + + count = fComplexMaxConstraints.CountItems(); + for (int32 i = 0; i < count; i++) { + Constraint* constraint = (Constraint*)fComplexMaxConstraints.ItemAt(i); + layouter->fComplexMaxConstraints.AddItem( + constraint->CloneConstraint(layouter)); + } + + return layouter; +} + +// _ValidateMinMax +void +ConstraintSolverLayouter::_ValidateMinMax() +{ + if (fMinMaxValid) + return; + + if (fElementCount == 0) { + fMin = 0; + fMax = B_SIZE_UNLIMITED; + } else { + int32 spacing = (fElementCount - 1) * fSpacing; + fMin = BLayoutUtils::AddSizesInt32(_ComputeMin(), spacing); + fMax = BLayoutUtils::AddSizesInt32(_ComputeMax(), spacing); + } + + fMinMaxValid = true; +} + +// _AddMinConstraint +void +ConstraintSolverLayouter::_AddMinConstraint(int32 first, int32 last, + int32 value) +{ + if (first == last) { + _SetConstraint(MIN_CONSTRAINT, fBasicMinConstraints, first, value, + true); + } else { + _SetConstraint(MIN_CONSTRAINT, fComplexMinConstraints, first, last, + value, true); + } +} + +// _AddMaxConstraint +void +ConstraintSolverLayouter::_AddMaxConstraint(int32 first, int32 last, + int32 value) +{ + if (first == last) { + _SetConstraint(MAX_CONSTRAINT, fBasicMaxConstraints, first, value, + true); + } else { + _SetConstraint(MAX_CONSTRAINT, fComplexMaxConstraints, first, last, + value, true); + } +} + +// _ComputeMin +int32 +ConstraintSolverLayouter::_ComputeMin() +{ + _RemoveSetSizeConstraint(); + _AddConstraints(); + + // suggest 0 values for the variables + for (int32 i = 0; i < fElementCount; i++) + fSolver->SuggestValue(*fVariables[i].QocaVariable(), 0); + fSolver->SuggestValue(*fSizeVariable->QocaVariable(), 0); + + // solve + fSolver->Solve(); + + int32 size = lround(fSizeVariable->SolvedValue()); + + bool success = _FindIntegerSolution(size); + if (!success) { + ERROR_MESSAGE( + "ConstraintSolverLayouter::_ComputeMin(): no int solution\n"); + return 0; + } + + return size; +} + +// _ComputeMax +int32 +ConstraintSolverLayouter::_ComputeMax() +{ + _RemoveSetSizeConstraint(); + _AddConstraints(); + + // Try adding the size constraint with max possible value. If that works + // out, there's no limit on the maximal size. + if (_AddSetSizeConstraint(B_SIZE_UNLIMITED)) + return B_SIZE_UNLIMITED; + + // suggest 0 values for the element variables and the maximal possible + // value for the size + for (int32 i = 0; i < fElementCount; i++) + fSolver->SuggestValue(*fVariables[i].QocaVariable(), 0); + fSolver->SuggestValue(*fSizeVariable->QocaVariable(), B_SIZE_UNLIMITED); + + // solve + fSolver->Solve(); + + int32 size = lround(fSizeVariable->SolvedValue()); + + bool success = _FindIntegerSolution(size); + if (!success) { + ERROR_MESSAGE( + "ConstraintSolverLayouter::_ComputeMax(): no int solution\n"); + return B_SIZE_UNLIMITED; + } + + return size; +} + +// _ComputeSolution +bool +ConstraintSolverLayouter::_ComputeSolution(int32 size) +{ +//printf("ConstraintSolverLayouter::_ComputeSolution(%ld)\n", size); + _RemoveSetSizeConstraint(); + _AddConstraints(); + + // suggest weighted values for the element variables + int32 sizes[fElementCount]; + SimpleLayouter::DistributeSize(size, fWeights, sizes, fElementCount); + for (int32 i = 0; i < fElementCount; i++) + fSolver->SuggestValue(*fVariables[i].QocaVariable(), sizes[i]); + + fSolver->SuggestValue(*fSizeVariable->QocaVariable(), size); + + if (!_AddSetSizeConstraint(size)) { + // Ugh! Contradictory! + ERROR_MESSAGE("ConstraintSolverLayouter::_ComputeSolution(): " + "contradictory CSP\n"); + return false; + } + + // solve + fSolver->Solve(); + + if (!_FindIntegerSolution(size)) { + ERROR_MESSAGE("ConstraintSolverLayouter::_ComputeSolution(): " + "no int solution\n"); + return false; + } + + return true; +} + +// _FindIntegerSolution +bool +ConstraintSolverLayouter::_FindIntegerSolution(int32 size) +{ +//printf("ConstraintSolverLayouter::_FindIntegerSolution(%ld)\n", size); +//printf(" solution:\n"); + // check whether there are non-integer variable values + Set nonIntVariables; + int32 sum = 0; + for (int32 i = 0; i < fElementCount; i++) { + Variable& var = fVariables[i]; + double value = var.SolvedValue(); + int32 intValue = (int32)floor(value); +//printf(" %ld: %4.2f: %4ld\n", i, value, intValue); + + bool nonIntVar = false; + if (intValue != value) { + // the solved value is not integral + nonIntVar = true; + + // make sure the minimum constraint for the variable is satisfied + // -- if not, this is just a rounding error + if (fBasicMinConstraints[i] != NULL) { + if (intValue < fBasicMinConstraints[i]->OriginalValue()) { + intValue = fBasicMinConstraints[i]->OriginalValue(); + nonIntVar = false; + } + } + + // make sure the maximum constraint for the variable is satisfied + // -- if not, this is just a rounding error + if (nonIntVar && fBasicMaxConstraints[i] != NULL) { + // also include the == case here, since the variable can't grow anymore + if (intValue >= fBasicMaxConstraints[i]->OriginalValue()) { + intValue = fBasicMaxConstraints[i]->OriginalValue(); + nonIntVar = false; + } + } + } + + var.SetIntValue(intValue); + sum += intValue; + + if (nonIntVar) + nonIntVariables.Add(&var); + } + + if (sum == size) + return true; + + if (sum > size) { + ERROR_MESSAGE("ConstraintSolverLayouter::_FindIntegerSolution(): " + "computed size %ld, but element sum is %ld\n", size, sum); + return false; + } + + if (nonIntVariables.IsEmpty()) { + ERROR_MESSAGE("ConstraintSolverLayouter::_FindIntegerSolution(): " + "computed size %ld, element sum is %ld, but we have no " + "non-integer variables\n", size, sum); + return false; + } + + // Apparently rounding down the non-integer variables caused their sum to be less than the computed + // size. This should cause at least one complex minimum constraint to be violated. We need to + // distribute the size difference between the variables we have. + + // get the max constraints + BList maxConstraints; + int32 count = nonIntVariables.Size(); + for (int32 i = 0; i < count; i++) { + Variable* var = (Variable*)nonIntVariables.Get(i); + Constraint* constraint = fBasicMaxConstraints[var->Index()]; + if (constraint != NULL) + maxConstraints.AddItem(constraint); + } + maxConstraints.AddList(&fComplexMaxConstraints); + + return _FindIntegerSolution(nonIntVariables, fComplexMinConstraints, + maxConstraints, size - sum); +} + +// _FindIntegerSolution +bool +ConstraintSolverLayouter::_FindIntegerSolution(const Set& _nonIntVariables, + const BList& _minConstraints, const BList& _maxConstraints, int32 sizeDiff) +{ + // We get the variables that had a non-integer value, and lists of minimum + // and maximum constraints that need to be satisfied. The minimum + // constraints are only those that may be violated at the moment. Maximum + // constraints are those that may be involved with the variables. First of + // all we narrow the collections down to their minimal size, i.e. we filter + // the maximum constraints that are really involved, filter the variables + // that may still grow (i.e. remove those that are used in barely satisfied + // maximum constraints), and filter the minimum constraints that are + // violated. + // The recursion will end at the latest at sizeDiff levels. + + // get the involved maximum constraints + BList maxConstraints; + _GetInvolvedConstraints(_maxConstraints, _nonIntVariables.ToList(), + maxConstraints); + + // Filter the variables according to the maximum constraints that are + // barely satisfied. Neither of the variables involved can grow anymore. + Set nonIntVariables; + _FilterVariablesByMaxConstraints(_nonIntVariables.ToList(), maxConstraints, + nonIntVariables); + + // get the violated minimum constraints; maximum constraints never get + // violated, since we filter out variables early that, when increase, + // would cause a maximum constraint to be violated + BList minConstraints; + _GetViolatedConstraints(_minConstraints, minConstraints); + + // If the size is correct, we can stop. This is a solution if there are no + // more violated constraints. + if (sizeDiff == 0) + return (minConstraints.IsEmpty()); + + // There's at least one violated constraint. If there are no more variables + // we can temper with, this is apparently a dead end. + if (nonIntVariables.IsEmpty()) + return false; + + // If there is at least one violated constraint, we take the first + // constraint (the one with the greatest satisfaction distance) and pick + // the involved variable with the greatest distance to its non-integer + // value. Increment the variable value, remove the variable, recompute + // nonIntVariables, minConstraints, maxConstraints, violatedConstraints. + // If there are no unsatisfied constraints, we simply consider all + // variables. + + BList constraintVariables; + + if (minConstraints.IsEmpty()) { + constraintVariables.AddList(&nonIntVariables.ToList()); + } else { + // get the variables involved in the constraint with the greatest + // satisfaction distance + Constraint* constraint = (Constraint*)minConstraints.ItemAt(0); + constraintVariables.MakeEmpty(); + for (int32 i = constraint->First(); i <= constraint->Last(); i++) { + Variable* var = &fVariables[i]; + if (nonIntVariables.Contains(var)) + constraintVariables.AddItem(var); + } + } + + // sort the variables by real value - integer value difference in + // descending order + if (constraintVariables.CountItems() > 1) + constraintVariables.SortItems(_CompareVariables); + + // Now pick a variable (starting with the one with the greatest + // real value - integer value difference), increment its integer value + // and recurse. + int32 count = constraintVariables.CountItems(); + for (int32 i = 0; i < count; i++) { + Variable* var = (Variable*)constraintVariables.ItemAt(i); + int32 varValue = var->IntValue(); + var->SetIntValue(varValue + 1); + + // recursion... + Set remainingVariables; + remainingVariables.AddAll(nonIntVariables); + remainingVariables.Remove(var); + + bool success = _FindIntegerSolution(remainingVariables, minConstraints, + maxConstraints, sizeDiff - 1); + if (success) + return true; + + // no solution: reset to old var value + var->SetIntValue(varValue); + } + + // if we are here, we didn't find a solution + ERROR_MESSAGE("ConstraintSolverLayouter::_FindIntegerSolution(): " + "found no int solution\n"); + return false; +} + +// _CreateConstraint +ConstraintSolverLayouter::Constraint* +ConstraintSolverLayouter::_CreateConstraint(int32 type, int32 first, + int32 last, int32 value) +{ + switch (type) { + case MIN_CONSTRAINT: + return new MinConstraint(this, first, last, value); + case MAX_CONSTRAINT: + return new MaxConstraint(this, first, last, value); + } + + // illegal constraint type + return NULL; +} + +// _SetConstraint +void +ConstraintSolverLayouter::_SetConstraint(int32 type, Constraint** constraints, + int32 element, int32 value, bool restrict) +{ + if (element < 0 || element >= fElementCount) + return; + + // ignore non-restricting min/max constraints + if (type == MIN_CONSTRAINT && value <= 0 + || type == MAX_CONSTRAINT && value >= B_SIZE_UNLIMITED) { + return; + } + + _RemoveConstraints(); + + if (constraints[element] != NULL) { + if (restrict) + constraints[element]->RestrictOriginalValue(value); + else + constraints[element]->SetOriginalValue(value); + } else + constraints[element] = _CreateConstraint(type, element, element, value); +} + +// _SetConstraint +void +ConstraintSolverLayouter::_SetConstraint(int32 type, BList& constraints, + int32 first, int32 last, int32 value, bool restrict) +{ + if (first < 0 || first > last || last >= fElementCount) + return; + + // ignore non-restricting min/max constraints + if (type == MIN_CONSTRAINT && value <= 0 + || type == MAX_CONSTRAINT && value >= B_SIZE_UNLIMITED) { + return; + } + + _RemoveConstraints(); + + int32 index = _IndexOfConstraint(constraints, first, last); + if (index >= 0) { + Constraint* constraint = (Constraint*)constraints.ItemAt(index); + if (restrict) + constraint->RestrictOriginalValue(value); + else + constraint->SetOriginalValue(value); + } else { + Constraint* constraint = _CreateConstraint(type, first, last, value); + constraints.AddItem(constraint); + } +} + +// _IndexOfConstraint +int +ConstraintSolverLayouter::_IndexOfConstraint(BList& constraints, int32 first, + int32 last) +{ + int32 count = constraints.CountItems(); + for (int32 i = 0; i < count; i++) { + Constraint* constraint = (Constraint*)constraints.ItemAt(i); + if (constraint->First() == first && constraint->Last() == last) + return i; + } + + return -1; +} + +// _AddSetSizeConstraint +bool +ConstraintSolverLayouter::_AddSetSizeConstraint(int32 size) +{ + if (fSetSizeConstraintAdded) { + if (fSetSizeConstraint->RHS() == size) + return true; + _RemoveSetSizeConstraint(); + } + + fSetSizeConstraint->SetRHS(size); + + bool success = fSolver->AddConstraint(*fSetSizeConstraint); + if (!success) + return false; + + fSetSizeConstraintAdded = true; + return true; +} + +// _AddConstraints +void +ConstraintSolverLayouter::_AddConstraints() +{ + if (fConstraintsAdded) + return; + + // We try to make constraints non-contradictory (i.e. adjust MAX + // constraints respectively). That's non-trivial. Example: + // 0 <= x1 <= inf, 0 <= x2 <= 9, 0 <= x3 <= inf + // 10 <= x1 + x2 <= inf, 10 <= x2 + x3 <= inf + // The resulting minimum for x1 + x2 + x3 is not 10, but 11. Naturally a + // constraint x1 + x2 + x3 <= 10 would be contradictory, but we can't + // easily infer that. Even if we could recognize the constraints involved + // in the conflict (the two min and the two max constraints) and decide + // that we don't want to change min constraints, we still have to decide + // whether we want adjust the x2 or the x1 + x2 + x3 max constraint. + // + // So what we do is, we enforce some of the simpler required properties, + // like: + // 1) min_k,j >= min_k,l + min_l,j + // 2) max_k,j <= max_k,l + max_l,j + // 3) min_k,j <= max_k,j + // 4) min_k,j <= max_k,l + max_l,j + // + // By adding the constraints in the order min constraints, basic max + // constraints, complex max constraints we make sure that we only drop + // complex max constraints, if the CSP is still contradictory. + + // create a MinMaxMatrix we can work with + MinMaxMatrix matrix(fElementCount); + + // set the basic constraints + for (int i = 0; i < fElementCount; i++) { + MinMaxEntry& entry = matrix.Entry(i, i); + + Constraint* minConstraint = fBasicMinConstraints[i]; + if (minConstraint != NULL) + entry.SetMinConstraint(minConstraint); + + Constraint* maxConstraint = fBasicMaxConstraints[i]; + if (maxConstraint != NULL) + entry.SetMaxConstraint(maxConstraint); + } + + // set the complex min constraints + int32 count = fComplexMinConstraints.CountItems(); + for (int32 i = 0; i < count; i++) { + Constraint* constraint = (Constraint*)fComplexMinConstraints.ItemAt(i); + MinMaxEntry& entry = matrix.Entry(constraint->First(), + constraint->Last()); + entry.SetMinConstraint(constraint); + } + + // set the complex max constraints + count = fComplexMaxConstraints.CountItems(); + for (int32 i = 0; i < count; i++) { + Constraint* constraint = (Constraint*)fComplexMaxConstraints.ItemAt(i); + MinMaxEntry& entry = matrix.Entry(constraint->First(), + constraint->Last()); + entry.SetMaxConstraint(constraint); + } + + // create lists containing the constraints (actually only the length of + // the constraints) starting at a common point + BList startLists[fElementCount]; + void* one = (void*)1L; + for (int i = 0; i < fElementCount; i++) { + startLists[i].AddItem(one); + + MinMaxEntry& entry = matrix.Entry(i, i); + entry.requiredMax = entry.min; + } + + // make sure that min_k,j >= min_k,l + min_l,j and + // max_k,j <= max_k,l + max_l,j and min_k,j <= max_k,j + for (int32 length = 2; length <= fElementCount; length++) { + for (int32 first = 0; first < fElementCount - length + 1; first++) { + int32 last = first + length - 1; + MinMaxEntry& entry = matrix.Entry(first, last); + + count = startLists[first].CountItems(); + for (int32 i = 0; i < count; i++) { + int32 split = first + (int32)startLists[first].ItemAt(i); + MinMaxEntry& left = matrix.Entry(first, split - 1); + MinMaxEntry& right = matrix.Entry(split, last); + + int32 min = BLayoutUtils::AddSizesInt32(left.min, right.min); + if (min >= entry.min) { + entry.min = min; + entry.minConstraint = NULL; // constraint is redundant + } + + int32 max = BLayoutUtils::AddSizesInt32(left.max, right.max); + if (max <= entry.max) { + entry.max = max; + // TODO: When we relax the max constraints later, the + // constraint might become a real restriction again. So we + // don't remove it. We could re-check after relaxing the + // max constraints. +// entry.maxConstraint = NULL; // constraint is redundant + } + } + + entry.max = max_c(entry.max, entry.min); + entry.requiredMax = entry.min; + + if (entry.minConstraint != NULL || entry.maxConstraint != NULL) + startLists[first].AddItem((void*)length); + } + } + + // now propagate down the requirements on the maximum constraints the min + // constraints impose, i.e. min_k,j <= max_k,l + max_l,j + for (int32 length = fElementCount; length >= 2; length--) { + for (int32 first = 0; first < fElementCount - length + 1; first++) { + int32 last = first + length - 1; + MinMaxEntry& entry = matrix.Entry(first, last); + + if (entry.requiredMax > entry.max) + entry.max = entry.requiredMax; + + count = startLists[first].CountItems(); + for (int32 i = 0; i < count; i++) { + int leftLen = (int32)startLists[first].ItemAt(i); + if (leftLen >= length) + break; + + int32 split = first + leftLen; + MinMaxEntry& left = matrix.Entry(first, split - 1); + MinMaxEntry& right = matrix.Entry(split, last); + + int32 max = BLayoutUtils::AddSizesInt32(left.max, right.max); + if (max < entry.requiredMax) { + // distribute the difference + int32 diff = entry.requiredMax - max; + int32 leftDiff = diff * leftLen / length; + int32 rightDiff = diff - leftDiff; + left.requiredMax = max_c(left.requiredMax, + left.max + leftDiff); + right.requiredMax = max_c(right.requiredMax, + right.max + rightDiff); + } + } + } + } + + // apply the maximum requirements to the basic elements + for (int32 i = 0; i < fElementCount; i++) { + MinMaxEntry& entry = matrix.Entry(i, i); + if (entry.requiredMax > entry.max) + entry.max = entry.requiredMax; + } + + // now filter and adjust the min/max constraints + // basic min/max constraints + BList minConstraints; + BList maxConstraints; + for (int32 i = 0; i < fElementCount; i++) { + MinMaxEntry& entry = matrix.Entry(i, i); + if (entry.minConstraint != NULL) { + entry.minConstraint->SetValue(entry.min); + minConstraints.AddItem(entry.minConstraint); + } + + if (entry.maxConstraint != NULL) { + entry.maxConstraint->SetValue(entry.max); + maxConstraints.AddItem(entry.maxConstraint); + } + } + + // complex min constraints + count = fComplexMinConstraints.CountItems(); + for (int32 i = 0; i < count; i++) { + Constraint* constraint = (Constraint*)fComplexMinConstraints.ItemAt(i); + MinMaxEntry& entry = matrix.Entry(constraint->First(), + constraint->Last()); + if (entry.minConstraint != NULL) { + entry.minConstraint->SetValue(entry.min); + minConstraints.AddItem(entry.minConstraint); + } + } + + // complex max constraints + count = fComplexMaxConstraints.CountItems(); + for (int32 i = 0; i < count; i++) { + Constraint* constraint = (Constraint*)fComplexMaxConstraints.ItemAt(i); + MinMaxEntry& entry = matrix.Entry(constraint->First(), + constraint->Last()); + if (entry.maxConstraint != NULL) { + entry.maxConstraint->SetValue(entry.max); + maxConstraints.AddItem(entry.maxConstraint); + } + } + + // We first add the min constraints, since they are vital. They can't + // contradict each other because they only define lower bounds for the + // variables. + + _AddConstraints(minConstraints); + + // Adding a max constraint can fail. Not for the basic constraints though. + // We ensured that by propagating the consequences of the min constraints + // down. Complex max constraints may conflict with a combination of other + // max and some min constraints, though. Hence we sort the constraints by + // length (i.e. number of involved elements). + + maxConstraints.SortItems(_CompareConstraintsByLength); + _AddConstraints(maxConstraints); + + // finally add the size sum constraint (which isn't a constraint really) + if (!fSolver->AddConstraint(*fSizeSumConstraint)) { + // That's something that can never possibly happen, since this + // constraint just introduces the size variable, defining it to be the + // sum of all elements. +// System.out.println("Failed to add sum constraint!"); + } + + fConstraintsAdded = true; +} + +// _AddConstraints +void +ConstraintSolverLayouter::_AddConstraints(const BList& constraints) +{ + int32 count = constraints.CountItems(); + for (int32 i = 0; i < count; i++) { + Constraint* constraint = (Constraint*)constraints.ItemAt(i); + bool success = fSolver->AddConstraint(*constraint->QocaConstraint()); + if (success) { + constraint->SetAdded(true); + } else { + // Failed to add the constraint: This can only happen for max + // constraints, when the other _AddConstraints() method wasn't able + // to resolve the conflict. We try to relax the constraint until + // there no longer is a conflict. + // The alternative would be to drop it completely, which might even + // cause that there remains no maximum restriction at all, which is + // certainly undesired. + + // find an upper bound first + int32 value = constraint->Value(); + int32 lower = value + 1; + int32 upper = max_c(lower, 128); + bool foundUpperBound = false; + while (upper < B_SIZE_UNLIMITED / 2) { + constraint->SetValue(upper); + if (fSolver->AddConstraint(*constraint->QocaConstraint())) { + foundUpperBound = true; + fSolver->RemoveConstraint(*constraint->QocaConstraint()); + break; + } + + lower = upper + 1; + upper *= 2; + } + + if (!foundUpperBound) { +// System.out.println("Failed to add constraint: " + constraint); + continue; + } + + // now narrow the range down until we found the exact upper bound + while (lower < upper) { + int32 mid = (lower + upper) / 2; + + constraint->SetValue(mid); + if (fSolver->AddConstraint(*constraint->QocaConstraint())) { + upper = mid; + fSolver->RemoveConstraint(*constraint->QocaConstraint()); + } else + lower = mid + 1; + } + + // now add the constraint for real + constraint->SetValue(upper); + if (fSolver->AddConstraint(*constraint->QocaConstraint())) { +// System.out.println("Added constraint: " + constraint + ". Original value was: " + value); + constraint->SetAdded(true); + } else { +// System.out.println("Failed to add constraint " + constraint + ", although it worked " +// + "before!"); + } + } + } +} + +// _RemoveSetSizeConstraint +void +ConstraintSolverLayouter::_RemoveSetSizeConstraint() +{ + if (fSetSizeConstraintAdded) { + fSolver->RemoveConstraint(*fSetSizeConstraint); + fSetSizeConstraintAdded = false; + } +} + +// _RemoveConstraints +void +ConstraintSolverLayouter::_RemoveConstraints() +{ + if (!fConstraintsAdded) + return; + + // set size constraint + _RemoveSetSizeConstraint(); + + // size sum constraint + fSolver->RemoveConstraint(*fSizeSumConstraint); + + // basic min/max constraints + for (int32 i = 0; i < fElementCount; i++) { + _RemoveConstraint(fBasicMinConstraints[i]); + _RemoveConstraint(fBasicMaxConstraints[i]); + } + + // complex min constraints + int32 count = fComplexMinConstraints.CountItems(); + for (int32 i = 0; i < count; i++) + _RemoveConstraint((Constraint*)fComplexMinConstraints.ItemAt(i)); + + // complex max constraints + count = fComplexMaxConstraints.CountItems(); + for (int32 i = 0; i < count; i++) + _RemoveConstraint((Constraint*)fComplexMaxConstraints.ItemAt(i)); +} + +// _RemoveConstraint +void +ConstraintSolverLayouter::_RemoveConstraint(Constraint* constraint) +{ + if (constraint != NULL && constraint->IsAdded()) { + fSolver->RemoveConstraint(*constraint->QocaConstraint()); + constraint->SetAdded(false); + } +} + +// _GetInvolvedConstraints +void +ConstraintSolverLayouter::_GetInvolvedConstraints(const BList& constraints, + const BList& variables, BList& filteredConstraints) +{ + filteredConstraints.MakeEmpty(); + if (constraints.IsEmpty() || variables.IsEmpty()) + return; + + // create a fast lookup array for the variables + int32 varDistances[fElementCount]; + int32 count = variables.CountItems(); + for (int32 i = 0; i < count; i++) { + Variable* var = (Variable*)variables.ItemAt(i); + varDistances[var->Index()] = 1; + } + + int32 nextSetVar = fElementCount; + for (int32 i = fElementCount - 1; i >= 0; i--) { + if (varDistances[i] == 1) + nextSetVar = i; + varDistances[i] = nextSetVar - i; + } + + // now filter the constraints + count = constraints.CountItems(); + for (int32 i = 0; i < count; i++) { + Constraint* constraint = (Constraint*)constraints.ItemAt(i); + int32 first = constraint->First(); + if (first + varDistances[first] <= constraint->Last()) + filteredConstraints.AddItem(constraint); + } +} + +// _GetViolatedConstraints +void +ConstraintSolverLayouter::_GetViolatedConstraints(const BList& constraints, + BList& violatedConstraints) +{ + violatedConstraints.MakeEmpty(); + + int32 count = constraints.CountItems(); + for (int32 i = 0; i < count; i++) { + Constraint* constraint = (Constraint*)constraints.ItemAt(i); + int32 distance = constraint->ComputeSatisfactionDistance(); + if (distance > 0) { + constraint->SetAlgorithmData(distance); + violatedConstraints.AddItem(constraint); + } + } + + // sort the constraints by (descending) satisfaction distance + if (violatedConstraints.CountItems() > 1) { + violatedConstraints.SortItems( + _CompareConstraintsBySatisfactionDistance); + } +} + +// _FilterVariablesByMaxConstraints +void +ConstraintSolverLayouter::_FilterVariablesByMaxConstraints( + const BList& variables, const BList& constraints, Set& filteredVars) +{ + filteredVars.MakeEmpty(); + if (variables.IsEmpty()) + return; + + filteredVars.AddAll(variables); + if (constraints.IsEmpty()) + return; + + int32 count = constraints.CountItems(); + for (int32 k = 0; k < count; k++) { + Constraint* constraint = (Constraint*)constraints.ItemAt(k); + int32 distance = constraint->ComputeSatisfactionDistance(); + if (distance >= 0) { + for (int32 i = constraint->First(); i <= constraint->Last(); i++) + filteredVars.Remove(&fVariables[i]); + + if (filteredVars.IsEmpty()) + break; + } + } +} + +// _CompareVariables +int +ConstraintSolverLayouter::_CompareVariables(const void* _a, const void* _b) +{ + // compare by distance of the float solution to the integer solution + Variable* a = *(Variable**)_a; + Variable* b = *(Variable**)_b; + double diff1 = a->SolvedValue() - a->IntValue(); + double diff2 = b->SolvedValue() - b->IntValue(); + + // descending order + if (diff2 < diff1) + return -1; + return (diff2 > diff1 ? 1 : 0); +} + +// _CompareConstraints +int +ConstraintSolverLayouter::_CompareConstraintsByLength(const void* _a, + const void* _b) +{ + // compare by number of involved variables + Constraint* a = *(Constraint**)_a; + Constraint* b = *(Constraint**)_b; + + return (a->Last() - a->First()) - (b->Last() - b->First()); +} + +// _CompareConstraints +int +ConstraintSolverLayouter::_CompareConstraintsBySatisfactionDistance( + const void* _a, const void* _b) +{ + // compare by number of involved variables + Constraint* a = *(Constraint**)_a; + Constraint* b = *(Constraint**)_b; + + // descending + return b->AlgorithmData() - a->AlgorithmData(); +} diff --git a/src/kits/interface/layouter/ConstraintSolverLayouter.h b/src/kits/interface/layouter/ConstraintSolverLayouter.h new file mode 100644 index 0000000000..e5ab5f84db --- /dev/null +++ b/src/kits/interface/layouter/ConstraintSolverLayouter.h @@ -0,0 +1,144 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef CONSTRAINT_SOLVER_LAYOUTER_H +#define CONSTRAINT_SOLVER_LAYOUTER_H + +#include "Layouter.h" + +#include + +class QcLinInEqSolver; +class QcConstraint; +class QcConstraint; + +namespace BPrivate { +namespace Layout { + +class ConstraintSolverLayouter : public Layouter { +public: + ConstraintSolverLayouter(int32 elementCount, + int32 spacing); + virtual ~ConstraintSolverLayouter(); + + virtual void AddConstraints(int32 element, int32 length, + float min, float max, float preferred); + virtual void SetWeight(int32 element, float weight); + + virtual float MinSize(); + virtual float MaxSize(); + virtual float PreferredSize(); + + virtual LayoutInfo* CreateLayoutInfo(); + + virtual void Layout(LayoutInfo* layoutInfo, float size); + + virtual Layouter* CloneLayouter(); + +private: + class Set; + + class Variable; + class Constraint; + class MinConstraint; + class MaxConstraint; + class MinMaxEntry; + class MinMaxMatrix; + class MyLayoutInfo; + + friend class Constraint; + + enum { + MIN_CONSTRAINT = 0, + MAX_CONSTRAINT = 1, + }; + + + void _ValidateMinMax(); + + void _AddMinConstraint(int32 first, int32 last, + int32 value); + void _AddMaxConstraint(int32 first, int32 last, + int32 value); + + int32 _ComputeMin(); + int32 _ComputeMax(); + bool _ComputeSolution(int32 size); + + bool _FindIntegerSolution(int32 size); + bool _FindIntegerSolution(const Set& nonIntVariables, + const BList& minConstraints, + const BList& maxConstraints, + int32 sizeDiff); + + Constraint* _CreateConstraint(int32 type, int32 first, + int32 last, int32 value); + void _SetConstraint(int32 type, + Constraint** constraints, + int32 element, int32 value, bool restrict); + void _SetConstraint(int32 type, + BList& constraints, + int32 first, int32 last, int32 value, + bool restrict); + int _IndexOfConstraint(BList& constraints, + int32 first, int32 last); + bool _AddSetSizeConstraint(int32 size); + + void _AddConstraints(); + void _AddConstraints(const BList& constraints); + void _RemoveSetSizeConstraint(); + void _RemoveConstraints(); + void _RemoveConstraint(Constraint* constraint); + void _GetInvolvedConstraints( + const BList& constraints, + const BList& variables, + BList& filteredConstraints); + void _GetViolatedConstraints( + const BList& constraints, + BList& violatedConstraints); + void _FilterVariablesByMaxConstraints( + const BList& variables, + const BList& constraints, + Set& filteredVars); + + static int _CompareVariables(const void* a, const void* b); + static int _CompareConstraintsByLength(const void* a, + const void* b); + static int _CompareConstraintsBySatisfactionDistance( + const void* a, const void* b); + +private: + int32 fElementCount; + float* fWeights; + + Constraint** fBasicMinConstraints; + Constraint** fBasicMaxConstraints; + + BList fComplexMinConstraints; + BList fComplexMaxConstraints; + + Variable* fVariables; + Variable* fSizeVariable; + + QcLinInEqSolver* fSolver; + QcConstraint* fSizeSumConstraint; + QcConstraint* fSetSizeConstraint; + + bool fConstraintsAdded; + bool fSetSizeConstraintAdded; + + int32 fSpacing; + int32 fMin; + int32 fMax; + bool fMinMaxValid; + + MyLayoutInfo* fLayoutInfo; +}; + +} // namespace Layout +} // namespace BPrivate + +using BPrivate::Layout::ConstraintSolverLayouter; + +#endif // CONSTRAINT_SOLVER_LAYOUTER_H diff --git a/src/kits/interface/layouter/Layouter.cpp b/src/kits/interface/layouter/Layouter.cpp new file mode 100644 index 0000000000..6c4908de1d --- /dev/null +++ b/src/kits/interface/layouter/Layouter.cpp @@ -0,0 +1,43 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "Layouter.h" + + +// constructor +LayoutInfo::LayoutInfo() +{ +} + +// destructor +LayoutInfo::~LayoutInfo() +{ +} + +// ElementRangeSize +float +LayoutInfo::ElementRangeSize(int32 position, int32 length) +{ + if (length == 1) + return ElementSize(position); + + int lastIndex = position + length - 1; + return ElementLocation(lastIndex) + ElementSize(lastIndex) + - ElementLocation(position); +} + + +// #pragma mark - + + +// constructor +Layouter::Layouter() +{ +} + +// destructor +Layouter::~Layouter() +{ +} diff --git a/src/kits/interface/layouter/Layouter.h b/src/kits/interface/layouter/Layouter.h new file mode 100644 index 0000000000..b146c566da --- /dev/null +++ b/src/kits/interface/layouter/Layouter.h @@ -0,0 +1,52 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef LAYOUTER_H +#define LAYOUTER_H + +#include + +namespace BPrivate { +namespace Layout { + +class LayoutInfo { +public: + LayoutInfo(); + virtual ~LayoutInfo(); + + virtual float ElementLocation(int32 element) = 0; + virtual float ElementSize(int32 element) = 0; + + virtual float ElementRangeSize(int32 position, int32 length); +}; + + +class Layouter { +public: + Layouter(); + virtual ~Layouter(); + + virtual void AddConstraints(int32 element, int32 length, + float min, float max, float preferred) = 0; + virtual void SetWeight(int32 element, float weight) = 0; + + virtual float MinSize() = 0; + virtual float MaxSize() = 0; + virtual float PreferredSize() = 0; + + virtual LayoutInfo* CreateLayoutInfo() = 0; + + virtual void Layout(LayoutInfo* layoutInfo, float size) = 0; + + virtual Layouter* CloneLayouter() = 0; +}; + + +} // namespace Layout +} // namespace BPrivate + +using BPrivate::Layout::LayoutInfo; +using BPrivate::Layout::Layouter; + +#endif // LAYOUTER_H diff --git a/src/kits/interface/layouter/OneElementLayouter.cpp b/src/kits/interface/layouter/OneElementLayouter.cpp new file mode 100644 index 0000000000..76736f9799 --- /dev/null +++ b/src/kits/interface/layouter/OneElementLayouter.cpp @@ -0,0 +1,110 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "OneElementLayouter.h" + +#include + + +class OneElementLayouter::MyLayoutInfo : public LayoutInfo { +public: + float fSize; + + MyLayoutInfo() + : fSize(0) + { + } + + virtual float ElementLocation(int32 element) + { + return 0; + } + + virtual float ElementSize(int32 element) + { + return fSize; + } +}; + + +// constructor +OneElementLayouter::OneElementLayouter() + : fMin(-1), + fMax(B_SIZE_UNLIMITED), + fPreferred(-1) +{ +} + +// destructor +OneElementLayouter::~OneElementLayouter() +{ +} + +// AddConstraints +void +OneElementLayouter::AddConstraints(int32 element, int32 length, + float min, float max, float preferred) +{ + fMin = max_c(fMin, min); + fMax = min_c(fMax, max); + fMax = max_c(fMax, fMin); + fPreferred = max_c(fPreferred, preferred); + fPreferred = max_c(fPreferred, fMin); + fPreferred = min_c(fPreferred, fMax); +} + +// SetWeight +void +OneElementLayouter::SetWeight(int32 element, float weight) +{ + // not needed +} + +// MinSize +float +OneElementLayouter::MinSize() +{ + return fMin; +} + +// MaxSize +float +OneElementLayouter::MaxSize() +{ + return fMax; +} + +// PreferredSize +float +OneElementLayouter::PreferredSize() +{ + return fPreferred; +} + +// CreateLayoutInfo +LayoutInfo* +OneElementLayouter::CreateLayoutInfo() +{ + return new MyLayoutInfo; +} + +// Layout +void +OneElementLayouter::Layout(LayoutInfo* layoutInfo, float size) +{ + ((MyLayoutInfo*)layoutInfo)->fSize = max_c(size, fMin); +} + +// CloneLayouter +Layouter* +OneElementLayouter::CloneLayouter() +{ + OneElementLayouter* layouter = new OneElementLayouter; + layouter->fMin = fMin; + layouter->fMax = fMax; + layouter->fPreferred = fPreferred; + + return layouter; +} diff --git a/src/kits/interface/layouter/OneElementLayouter.h b/src/kits/interface/layouter/OneElementLayouter.h new file mode 100644 index 0000000000..de2f24e399 --- /dev/null +++ b/src/kits/interface/layouter/OneElementLayouter.h @@ -0,0 +1,45 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef ONE_ELEMENT_LAYOUTER_H +#define ONE_ELEMENT_LAYOUTER_H + +#include "Layouter.h" + +namespace BPrivate { +namespace Layout { + +class OneElementLayouter : public Layouter { +public: + OneElementLayouter(); + virtual ~OneElementLayouter(); + + virtual void AddConstraints(int32 element, int32 length, + float min, float max, float preferred); + virtual void SetWeight(int32 element, float weight); + + virtual float MinSize(); + virtual float MaxSize(); + virtual float PreferredSize(); + + virtual LayoutInfo* CreateLayoutInfo(); + + virtual void Layout(LayoutInfo* layoutInfo, float size); + + virtual Layouter* CloneLayouter(); + +private: + class MyLayoutInfo; + + float fMin; + float fMax; + float fPreferred; +}; + +} // namespace Layout +} // namespace BPrivate + +using BPrivate::Layout::OneElementLayouter; + +#endif // ONE_ELEMENT_LAYOUTER_H diff --git a/src/kits/interface/layouter/SimpleLayouter.cpp b/src/kits/interface/layouter/SimpleLayouter.cpp new file mode 100644 index 0000000000..06f02e18df --- /dev/null +++ b/src/kits/interface/layouter/SimpleLayouter.cpp @@ -0,0 +1,457 @@ +/* + * Copyright 2006, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "SimpleLayouter.h" + +#include + +#include +#include +#include + + +// no lround() under BeOS R5 x86 +#ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST +# define lround(x) (long)floor((x) + 0.5) +#endif + + +// ElementLayoutInfo +class SimpleLayouter::ElementLayoutInfo { +public: + int32 size; + int32 location; + + ElementLayoutInfo() + : size(0), + location(0) + { + } +}; + +// ElementInfo +class SimpleLayouter::ElementInfo { +public: + int32 index; + int32 min; + int32 max; + int32 preferred; + float weight; + int64 tempWeight; + + ElementInfo() + : index(0), + min(0), + max(B_SIZE_UNLIMITED), + preferred(0), + weight(1), + tempWeight(0) + { + } + + ElementInfo(int index) + : index(index), + min(0), + max(B_SIZE_UNLIMITED), + preferred(0), + weight(1), + tempWeight(0) + { + } + + void Assign(const ElementInfo& info) + { + min = info.min; + max = info.max; + preferred = info.preferred; + weight = info.weight; + tempWeight = info.tempWeight; + } +}; + +// MyLayoutInfo +class SimpleLayouter::MyLayoutInfo : public LayoutInfo { +public: + int32 fSize; + ElementLayoutInfo* fElements; + int32 fElementCount; + + MyLayoutInfo(int32 elementCount) + : fSize(0), + fElementCount(elementCount) + { + fElements = new ElementLayoutInfo[elementCount]; + } + + virtual ~MyLayoutInfo() + { + delete[] fElements; + } + + virtual float ElementLocation(int32 element) + { + if (element < 0 || element >= fElementCount) { + // error + return 0; + } + + return fElements[element].location; + } + + virtual float ElementSize(int32 element) + { + if (element < 0 || element >= fElementCount) { + // error + return -1; + } + + return fElements[element].size - 1; + } +}; + + +// constructor +SimpleLayouter::SimpleLayouter(int32 elementCount, int32 spacing) + : fElementCount(elementCount), + fSpacing(spacing), + fMin(0), + fMax(B_SIZE_UNLIMITED), + fPreferred(0), + fMinMaxValid(false), + fLayoutInfo(NULL) +{ + fElements = new ElementInfo[elementCount]; + for (int i = 0; i < elementCount; i++) + fElements[i].index = i; +} + +// destructor +SimpleLayouter::~SimpleLayouter() +{ + delete[] fElements; +} + +// AddConstraints +void +SimpleLayouter::AddConstraints(int32 element, int32 length, + float _min, float _max, float _preferred) +{ + if (element < 0 || element >= fElementCount) { + // error + return; + } + if (length != 1) { + // error + return; + } + + int32 min = (int32)_min + 1; + int32 max = (int32)_max + 1; +// int32 preferred = (int32)_preferred + 1; + + ElementInfo& info = fElements[element]; + info.min = max_c(info.min, min); + info.max = min_c(info.max, max); + info.preferred = max_c(info.min, min); + + fMinMaxValid = false; +} + +// SetWeight +void +SimpleLayouter::SetWeight(int32 element, float weight) +{ + if (element < 0 || element >= fElementCount) { + // error + return; + } + + fElements[element].weight = weight; +} + +// MinSize +float +SimpleLayouter::MinSize() +{ + _ValidateMinMax(); + return fMin - 1; +} + +// MaxSize +float +SimpleLayouter::MaxSize() +{ + _ValidateMinMax(); + return fMax - 1; +} + +// PreferredSize +float +SimpleLayouter::PreferredSize() +{ + _ValidateMinMax(); + return fPreferred - 1; +} + +// CreateLayoutInfo +LayoutInfo* +SimpleLayouter::CreateLayoutInfo() +{ + return new MyLayoutInfo(fElementCount); +} + +// Layout +void +SimpleLayouter::Layout(LayoutInfo* layoutInfo, float _size) +{ + int32 size = int32(_size + 1); + + fLayoutInfo = (MyLayoutInfo*)layoutInfo; + + _ValidateMinMax(); + + if (fElementCount == 0) + return; + + fLayoutInfo->fSize = max_c(size, fMin); + + // layout the elements + if (fLayoutInfo->fSize >= fMax) + _LayoutMax(); + else + _LayoutStandard(); + + // set locations + int location = 0; + for (int i = 0; i < fElementCount; i++) { + fLayoutInfo->fElements[i].location = location; + location += fSpacing + fLayoutInfo->fElements[i].size; + } +} + +// CloneLayouter +Layouter* +SimpleLayouter::CloneLayouter() +{ + SimpleLayouter* layouter = new SimpleLayouter(fElementCount, fSpacing); + + for (int i = 0; i < fElementCount; i++) + layouter->fElements[i].Assign(fElements[i]); + + layouter->fMin = fMin; + layouter->fMax = fMax; + layouter->fPreferred = fPreferred; + + return layouter; +} + +// DistributeSize +void +SimpleLayouter::DistributeSize(int32 size, float weights[], int32 sizes[], + int32 count) +{ + // create element infos + BList elementInfos(count); + for (int32 i = 0; i < count; i++) { + ElementInfo* info = new ElementInfo(i); + info->weight = weights[i]; + elementInfos.AddItem(info); + } + + // compute integer weights + int64 sumWeight = _CalculateSumWeight(elementInfos); + + // distribute the size + int64 weight = 0; + int32 sumSize = 0; + for (int32 i = 0; i < count; i++) { + ElementInfo* info = (ElementInfo*)elementInfos.ItemAt(i); + weight += info->tempWeight; + int32 oldSumSize = sumSize; + sumSize = (int32)(size * weight / sumWeight); + sizes[i] = sumSize - oldSumSize; + + delete info; + } +} + +// _CalculateSumWeight +long +SimpleLayouter::_CalculateSumWeight(BList& elementInfos) +{ + if (elementInfos.IsEmpty()) + return 0; + int32 count = elementInfos.CountItems(); + + // sum up the floating point weight, so we get a scale + double scale = 0; + for (int32 i = 0; i < count; i++) { + ElementInfo* info = (ElementInfo*)elementInfos.ItemAt(i); + scale += info->weight; + } + + int64 weight = 0; + + if (scale == 0) { + // The weight sum is 0: We assign each info a temporary weight of 1. + for (int32 i = 0; i < count; i++) { + ElementInfo* info = (ElementInfo*)elementInfos.ItemAt(i); + info->tempWeight = 1; + weight += info->tempWeight; + } + } else { + // We scale the weights so that their sum is about 100000. This should + // give us ample resolution. If possible make the scale integer, so that + // integer weights will produce exact results. + if (scale >= 1 && scale <= 100000) + scale = lround(100000 / scale); + else + scale = 100000 / scale; + + for (int32 i = 0; i < count; i++) { + ElementInfo* info = (ElementInfo*)elementInfos.ItemAt(i); + info->tempWeight = (int64)(info->weight * scale); + weight += info->tempWeight; + } + } + + return weight; +} + +// _ValidateMinMax +void +SimpleLayouter::_ValidateMinMax() +{ + if (fMinMaxValid) + return; + + fMinMaxValid = true; + + if (fElementCount == 0) { + fMin = 0; + fMax = B_SIZE_UNLIMITED; + fPreferred = 0; + return; + } + + int spacing = (fElementCount - 1) * fSpacing; + fMin = spacing; + fMax = spacing; + fPreferred = spacing; + + for (int i = 0; i < fElementCount; i++) { + ElementInfo& info = fElements[i]; + + // correct the preferred and maximum sizes + if (info.max < info.min) + info.max = info.min; + if (info.preferred < info.min) + info.preferred = info.min; + else if (info.preferred > info.max) + info.preferred = info.max; + + // sum up + fMin += info.min; + fMax = BLayoutUtils::AddSizesInt32(fMax, info.max); + fPreferred = BLayoutUtils::AddSizesInt32(fPreferred, info.preferred); + } +} + +// _LayoutMax +void +SimpleLayouter::_LayoutMax() +{ + ElementInfo* infos = fElements; + int32 count = fElementCount; + if (count == 0) + return; + + int32 additionalSpace = fLayoutInfo->fSize - fMax; + + // layout to the maximum first + for (int i = 0; i < count; i++) + fLayoutInfo->fElements[infos[i].index].size = infos[i].max; + +// Mmh, distributing according to the weights doesn't look that good. +// // Now distribute the additional space according to the weights. +// int64 sumWeight = calculateSumWeight(Arrays.asList(infos)); +// int64 weight = 0; +// int64 sumSize = 0; +// for (int i = 0; i < infos.length; i++) { +// weight += infos[i].tempWeight; +// int64 oldSumSize = sumSize; +// sumSize = (int)(additionalSpace * weight / sumWeight); +// fLayoutInfo.fElements[infos[i].index].size += sumSize - oldSumSize; +// } + + // distribute the additional space equally + int64 sumSize = 0; + for (int i = 0; i < count; i++) { + int64 oldSumSize = sumSize; + sumSize = additionalSpace * (i + 1) / count; + fLayoutInfo->fElements[infos[i].index].size + += int32(sumSize - oldSumSize); + } +} + +// _LayoutStandard +void +SimpleLayouter::_LayoutStandard() +{ + int32 space = fLayoutInfo->fSize - (fElementCount - 1) * fSpacing; + + BList infosToLayout(fElementCount); + for (int i = 0; i < fElementCount; i++) { + infosToLayout.AddItem(&fElements[i]); + fLayoutInfo->fElements[i].size = 0; + } + + BList infosUnderMax(fElementCount); + BList infosOverMin(fElementCount); + while (infosToLayout.CountItems() > 0) { + int32 remainingSpace = 0; + int32 infoCount = infosToLayout.CountItems(); + int64 sumWeight = _CalculateSumWeight(infosToLayout); + int64 assignedWeight = 0; + int32 assignedSize = 0; + + for (int32 i = 0; i < infoCount; i++) { + ElementInfo* info = (ElementInfo*)infosToLayout.ItemAt(i); + ElementLayoutInfo& layoutInfo = fLayoutInfo->fElements[info->index]; + // The simple algorithm is this: + // info.size += (int)(space * info.tempWeight / sumWeight); + // I.e. we simply assign space according to the weight. To avoid the + // rounding problematic, we make it a bit more complicated. We + // assign the difference of total assignment for all infos including + // the current one minus the total excluding the current one. + assignedWeight += info->tempWeight; + int32 oldAssignedSize = assignedSize; + assignedSize = (int32)(space * assignedWeight / sumWeight); + layoutInfo.size += assignedSize - oldAssignedSize; + + if (layoutInfo.size < info->min) { + remainingSpace += layoutInfo.size - info->min; + layoutInfo.size = info->min; + } else if (layoutInfo.size > info->max) { + remainingSpace += layoutInfo.size - info->max; + layoutInfo.size = info->max; + } + + if (layoutInfo.size > info->min) + infosOverMin.AddItem(info); + if (layoutInfo.size < info->max) + infosUnderMax.AddItem(info); + } + + infosToLayout.MakeEmpty(); + if (remainingSpace > 0) + infosToLayout.AddList(&infosUnderMax); + else if (remainingSpace < 0) + infosToLayout.AddList(&infosOverMin); + infosUnderMax.MakeEmpty(); + infosOverMin.MakeEmpty(); + space = remainingSpace; + } +} diff --git a/src/kits/interface/layouter/SimpleLayouter.h b/src/kits/interface/layouter/SimpleLayouter.h new file mode 100644 index 0000000000..48f310d902 --- /dev/null +++ b/src/kits/interface/layouter/SimpleLayouter.h @@ -0,0 +1,68 @@ +/* + * Copyright 2006, Haiku Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef SIMPLE_LAYOUTER_H +#define SIMPLE_LAYOUTER_H + +#include "Layouter.h" + +class BList; + +namespace BPrivate { +namespace Layout { + +class SimpleLayouter : public Layouter { +public: + SimpleLayouter(int32 elementCount, + int32 spacing); + virtual ~SimpleLayouter(); + + virtual void AddConstraints(int32 element, int32 length, + float min, float max, float preferred); + virtual void SetWeight(int32 element, float weight); + + virtual float MinSize(); + virtual float MaxSize(); + virtual float PreferredSize(); + + virtual LayoutInfo* CreateLayoutInfo(); + + virtual void Layout(LayoutInfo* layoutInfo, float size); + + virtual Layouter* CloneLayouter(); + + static void DistributeSize(int32 size, float weights[], + int32 sizes[], int32 count); + +private: + static long _CalculateSumWeight(BList& elementInfos); + + void _ValidateMinMax(); + void _LayoutMax(); + void _LayoutStandard(); + +private: + class ElementLayoutInfo; + class ElementInfo; + class MyLayoutInfo; + + int32 fElementCount; + int32 fSpacing; + ElementInfo* fElements; + + int32 fMin; + int32 fMax; + int32 fPreferred; + + bool fMinMaxValid; + + MyLayoutInfo* fLayoutInfo; +}; + +} // namespace Layout +} // namespace BPrivate + +using BPrivate::Layout::SimpleLayouter; + +#endif // SIMPLE_LAYOUTER_H diff --git a/src/kits/interface/qoca/ChangeLog b/src/kits/interface/qoca/ChangeLog new file mode 100644 index 0000000000..aa1fb3f669 --- /dev/null +++ b/src/kits/interface/qoca/ChangeLog @@ -0,0 +1,17 @@ +2000-10-16 Peter Moulder + + * QcConstraintRep.hh (isSatisfied): Compile in unconditionally. + +2000-08-14 Peter Moulder + + + * QcBiMap.hh (class QcBiMap): Remove unused methods ChangeIndex, EraseByIdentifier. + * QcBiMapNotifier.hh (class QcBiMapNotifier): Remove unused method ChangeConstraint. + + * QcSolver and all derived classes (EndAddConstraint): return a + bool indicating success. + +2000-07-21 Peter Moulder + + * QcFloat.hh (GetValue): New method. + diff --git a/src/kits/interface/qoca/Jamfile b/src/kits/interface/qoca/Jamfile new file mode 100644 index 0000000000..c98d91c6a4 --- /dev/null +++ b/src/kits/interface/qoca/Jamfile @@ -0,0 +1,60 @@ +SubDir HAIKU_TOP src kits interface qoca ; + +# Don't compile qoca with debugging. Debug/non-debug versions are +# incompatible. +DEBUG = 0 ; + +SetSubDirSupportedPlatforms haiku libbe_test ; + +{ + local defines = [ FDefines HAVE_RINT=1 QOCA_INTERNALS ] ; + SubDirCcFlags $(defines) ; + SubDirC++Flags $(defines) ; +} + +SubDirSysHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ; + +SharedLibrary libqoca.so : + QcCassSolver.cc + QcCompPivotSystem.cc + QcCompPivotTableau.cc + QcConstraintRep.cc + QcCoreTableau.cc + QcDelCoreTableau.cc + QcDelLinEqTableau.cc + QcDelLinInEqTableau.cc + QcDenseMatrix.cc + QcFixedFloatRep.cc + QcFloatRep.cc + QcIneqSolverBase.cc + QcLinEqSolver.cc + QcLinEqSystem.cc + QcLinEqTableau.cc + QcLinInEqSolver.cc + QcLinInEqSystem.cc + QcLinInEqTableau.cc + QcLinPoly.cc + QcLinEqColStateVector.cc + QcLinEqRowStateVector.cc + QcLinInEqColStateVector.cc + QcLinInEqRowColStateVector.cc + QcNlpSolver.cc + QcNomadicFloatRep.cc + QcOrigRowStateVector.cc + QcQuasiRowColStateVector.cc + QcQuasiRowStateVector.cc + QcSolver.cc + QcSparseMatrix.cc + QcVarStow.cc + QcVariableBiMap.cc + : + $(TARGET_LIBSTDC++) +; + + +# also install in app_server test environment +if ( $(TARGET_PLATFORM) = libbe_test ) { + HaikuInstall install-test-apps : $(HAIKU_APP_TEST_LIB_DIR) + : libqoca.so + : tests!apps ; +} diff --git a/src/kits/interface/qoca/KeyIterator.hh b/src/kits/interface/qoca/KeyIterator.hh new file mode 100644 index 0000000000..53f132779d --- /dev/null +++ b/src/kits/interface/qoca/KeyIterator.hh @@ -0,0 +1,25 @@ +#ifndef KeyIteratorHH +#define KeyIteratorHH + +template +class KeyIterator + : public Iterator +{ +public: + KeyIterator (Iterator i) + : Iterator (i) + { + } + + Key const & operator* () const + { + return (*((Iterator const *) this))->first; + } + + Key const * operator->() const + { + return &(*((Iterator const *) this))->first; + } +}; + +#endif /* !KeyIteratorHH */ diff --git a/src/kits/interface/qoca/Makefile.am b/src/kits/interface/qoca/Makefile.am new file mode 100644 index 0000000000..309c060d9d --- /dev/null +++ b/src/kits/interface/qoca/Makefile.am @@ -0,0 +1,138 @@ +$(srcdir)/Makefile.am: Makefile.am.m4 + rm -f $(srcdir)/$(@F) + m4 -P $(srcdir)/$( $(srcdir)/$(@F) +# AFAIK, this has to be in srcdir (as opposed to bsrcdir). + + + + + + +##bsrcdir = $(srcdir) +bsrcdir = . + + + +.ch.cc: $(CH2XX) + @rm -f $(bsrcdir)/$(*F).cc && if echo "$(CH2XX) -c $< > $(bsrcdir)/$(*F).cc" \ + && $(CH2XX) -c $< > $(bsrcdir)/$(*F).cc; \ + then :; \ + else echo "rm -f $(bsrcdir)/$(*F).cc; exit 1" \ + && rm -f $(bsrcdir)/$(*F).cc; exit 1; fi + +.ch.hh: $(CH2XX) + @rm -f $(bsrcdir)/$(*F).hh && if echo "$(CH2XX) -i $< > $(bsrcdir)/$(*F).hh" \ + && $(CH2XX) -i $< > $(bsrcdir)/$(*F).hh; \ + then :; \ + else echo "rm -f $(bsrcdir)/$(*F).hh; exit 1" \ + && rm -f $(bsrcdir)/$(*F).hh; exit 1; fi + +.ch.H: $(CH2XX) + @rm -f $(bsrcdir)/$(*F).H && if echo "$(CH2XX) -d $< > $(bsrcdir)/$(*F).H" \ + && $(CH2XX) -d $< > $(bsrcdir)/$(*F).H; \ + then :; \ + else echo "rm -f $(bsrcdir)/$(*F).H; exit 1" \ + && rm -f $(bsrcdir)/$(*F).H; exit 1; fi + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + + + + +DEP_FILES = .deps/QcCassSolver.P .deps/QcCompPivotSystem.P .deps/QcCompPivotTableau.P .deps/QcConstraintRep.P .deps/QcCoreTableau.P .deps/QcDelCoreTableau.P .deps/QcDelLinEqTableau.P .deps/QcDelLinInEqTableau.P .deps/QcDenseMatrix.P .deps/QcFixedFloatRep.P .deps/QcFloatRep.P .deps/QcIneqSolverBase.P .deps/QcLinEqSolver.P .deps/QcLinEqSystem.P .deps/QcLinEqTableau.P .deps/QcLinInEqSolver.P .deps/QcLinInEqSystem.P .deps/QcLinInEqTableau.P .deps/QcLinPoly.P .deps/QcLinEqColStateVector.P .deps/QcLinEqRowStateVector.P .deps/QcLinInEqColStateVector.P .deps/QcLinInEqRowColStateVector.P .deps/QcNlpSolver.P .deps/QcNomadicFloatRep.P .deps/QcOrigRowStateVector.P .deps/QcQuasiRowColStateVector.P .deps/QcQuasiRowStateVector.P .deps/QcSolver.P .deps/QcSparseMatrix.P .deps/QcVarStow.P .deps/QcVariableBiMap.P + + +-include $(DEP_FILES) + +.cc.ii0: + @rm -f $(bsrcdir)/$(@F) && if echo "$(CXXCPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) -Wp,-MD,.deps/$(*F).pp $< > $(bsrcdir)/$(@F)" \ + && $(CXXCPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) -Wp,-MD,.deps/$(*F).pp $< > $(bsrcdir)/$(@F); \ + then :; \ + else echo "rm -f $(bsrcdir)/$(@F); exit 1" \ + && rm -f $(bsrcdir)/$(@F); exit 1; fi + @rm -f .deps/$(*F).P + @-sed 's/\.o/.ii0/g' < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + + +CXXFLAGS = @CXXFLAGS@ +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ +CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) + +libqoca_la_myOBJECTS = QcCassSolver.lo QcCompPivotSystem.lo QcCompPivotTableau.lo QcConstraintRep.lo QcCoreTableau.lo QcDelCoreTableau.lo QcDelLinEqTableau.lo QcDelLinInEqTableau.lo QcDenseMatrix.lo QcFixedFloatRep.lo QcFloatRep.lo QcIneqSolverBase.lo QcLinEqSolver.lo QcLinEqSystem.lo QcLinEqTableau.lo QcLinInEqSolver.lo QcLinInEqSystem.lo QcLinInEqTableau.lo QcLinPoly.lo QcLinEqColStateVector.lo QcLinEqRowStateVector.lo QcLinInEqColStateVector.lo QcLinInEqRowColStateVector.lo QcNlpSolver.lo QcNomadicFloatRep.lo QcOrigRowStateVector.lo QcQuasiRowColStateVector.lo QcQuasiRowStateVector.lo QcSolver.lo QcSparseMatrix.lo QcVarStow.lo QcVariableBiMap.lo + +ii0_files = QcCassSolver.ii0 QcCompPivotSystem.ii0 QcCompPivotTableau.ii0 QcConstraintRep.ii0 QcCoreTableau.ii0 QcDelCoreTableau.ii0 QcDelLinEqTableau.ii0 QcDelLinInEqTableau.ii0 QcDenseMatrix.ii0 QcFixedFloatRep.ii0 QcFloatRep.ii0 QcIneqSolverBase.ii0 QcLinEqSolver.ii0 QcLinEqSystem.ii0 QcLinEqTableau.ii0 QcLinInEqSolver.ii0 QcLinInEqSystem.ii0 QcLinInEqTableau.ii0 QcLinPoly.ii0 QcLinEqColStateVector.ii0 QcLinEqRowStateVector.ii0 QcLinInEqColStateVector.ii0 QcLinInEqRowColStateVector.ii0 QcNlpSolver.ii0 QcNomadicFloatRep.ii0 QcOrigRowStateVector.ii0 QcQuasiRowColStateVector.ii0 QcQuasiRowStateVector.ii0 QcSolver.ii0 QcSparseMatrix.ii0 QcVarStow.ii0 QcVariableBiMap.ii0 + +libqoca.la: $(ii0_files) $(libqoca_la_myOBJECTS) $(libqoca_la_DEPENDENCIES) + $(CXXLINK) -rpath $(libdir) $(libqoca_la_LDFLAGS) $(libqoca_la_myOBJECTS) $(libqoca_la_LIBADD) $(LIBS) + + +.ii0.o: + @if test -f $@ && cmp -s $(bsrcdir)/$(/dev/null; then :; else \ + echo "cp $(bsrcdir)/$(/dev/null; then :; else \ + echo "cp $(bsrcdir)/$( $(distdir)/Makefile.tmp + mv $(distdir)/Makefile.tmp $(distdir)/Makefile.in diff --git a/src/kits/interface/qoca/Makefile.am.m4 b/src/kits/interface/qoca/Makefile.am.m4 new file mode 100644 index 0000000000..f2af83dcfb --- /dev/null +++ b/src/kits/interface/qoca/Makefile.am.m4 @@ -0,0 +1,286 @@ +$(srcdir)/Makefile.am: Makefile.am.m4 + rm -f $(srcdir)/$(@F) + m4 -P $(srcdir)/$( $(srcdir)/$(@F) +# AFAIK, this has to be in srcdir (as opposed to bsrcdir). + +m4_changequote([[, ]])m4_dnl + +m4_define([[m4_echodo]], [[echo "m4_patsubst([[$1]], [[["\\`]\|\$\$]], [[\\\&]])" \ + && $1]]) + +m4_define([[m4_outputas]], + [[@rm -f $2 && if m4_echodo([[$1 > $2]]); \ + then :; \ + else m4_echodo([[rm -f $2; exit 1]]); fi]]) + +##bsrcdir = $(srcdir) +bsrcdir = . + +m4_define([[m4_ch2xx_rule]], +[[.ch.$2: $(CH2XX) + m4_outputas([[$(CH2XX) $1 $<]], [[$(bsrcdir)/$(*F).$2]])]]) + +m4_ch2xx_rule(-c, cc) + +m4_ch2xx_rule(-i, hh) + +m4_ch2xx_rule(-d, H) + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +m4_dnl Like: tr -s ' \t\n' ' ' +m4_define([[m4u_white]], [[m4_patsubst([[$1]], [[[ +]+]], [[ ]])]]) + +m4_define(m4_libqoca_la_OBJECTS, m4u_white([[ + QcCassSolver.lo QcCompPivotSystem.lo QcCompPivotTableau.lo + QcConstraintRep.lo QcCoreTableau.lo QcDelCoreTableau.lo + QcDelLinEqTableau.lo QcDelLinInEqTableau.lo QcDenseMatrix.lo + QcFixedFloatRep.lo + QcFloatRep.lo + QcIneqSolverBase.lo + QcLinEqSolver.lo QcLinEqSystem.lo QcLinEqTableau.lo + QcLinInEqSolver.lo QcLinInEqSystem.lo QcLinInEqTableau.lo + QcLinPoly.lo + QcLinEqColStateVector.lo + QcLinEqRowStateVector.lo + QcLinInEqColStateVector.lo + QcLinInEqRowColStateVector.lo + QcNlpSolver.lo + QcNomadicFloatRep.lo + QcOrigRowStateVector.lo + QcQuasiRowColStateVector.lo + QcQuasiRowStateVector.lo + QcSolver.lo QcSparseMatrix.lo + QcVarStow.lo + QcVariableBiMap.lo]]))m4_dnl + +DEP_FILES = m4_patsubst(m4_libqoca_la_OBJECTS, [[\(\w*\)\.lo]], [[.deps/\1.P]]) + + +-include $(DEP_FILES) + +.cc.ii0: + m4_outputas([[$(CXXCPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) -Wp,-MD,.deps/$(*F).pp $<]], + [[$(bsrcdir)/$(@F)]]) + @rm -f .deps/$(*F).P + @-sed 's/\.o/.ii0/g' < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + + +CXXFLAGS = @CXXFLAGS@ +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ +CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) + +libqoca_la_myOBJECTS = m4_libqoca_la_OBJECTS + +ii0_files = m4_patsubst(m4_libqoca_la_OBJECTS, \.lo, .ii0) + +libqoca.la: $(ii0_files) $(libqoca_la_myOBJECTS) $(libqoca_la_DEPENDENCIES) + $(CXXLINK) -rpath $(libdir) $(libqoca_la_LDFLAGS) $(libqoca_la_myOBJECTS) $(libqoca_la_LIBADD) $(LIBS) + +m4_define([[m4_compile]], +[[.ii0.$1: + @if test -f [[$]]@ && cmp -s $(bsrcdir)/$(/dev/null; then :; else \ + m4_echodo([[cp $(bsrcdir)/$( $(distdir)/Makefile.tmp + mv $(distdir)/Makefile.tmp $(distdir)/Makefile.in diff --git a/src/kits/interface/qoca/Makefile.in b/src/kits/interface/qoca/Makefile.in new file mode 100644 index 0000000000..e106925d56 --- /dev/null +++ b/src/kits/interface/qoca/Makefile.in @@ -0,0 +1,455 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = ../.. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AS = @AS@ +CC = @CC@ +CH2XX = @CH2XX@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +DLLTOOL = @DLLTOOL@ +DOCXX = @DOCXX@ +JAVA = @JAVA@ +JAVAC = @JAVAC@ +JAVACDEFINES = @JAVACDEFINES@ +JAVADOC = @JAVADOC@ +JCOM = @JCOM@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MINUSDEPEND = @MINUSDEPEND@ +NLPSOLVER_COM = @NLPSOLVER_COM@ +NLPSOLVER_HASH = @NLPSOLVER_HASH@ +OBJDUMP = @OBJDUMP@ +PACKAGE = @PACKAGE@ +QC_NDEBUG_COM = @QC_NDEBUG_COM@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +lgmp = @lgmp@ +lwn = @lwn@ +# AFAIK, this has to be in srcdir (as opposed to bsrcdir). + +bsrcdir = . + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +DEP_FILES = .deps/QcCassSolver.P .deps/QcCompPivotSystem.P .deps/QcCompPivotTableau.P .deps/QcConstraintRep.P .deps/QcCoreTableau.P .deps/QcDelCoreTableau.P .deps/QcDelLinEqTableau.P .deps/QcDelLinInEqTableau.P .deps/QcDenseMatrix.P .deps/QcFixedFloatRep.P .deps/QcFloatRep.P .deps/QcIneqSolverBase.P .deps/QcLinEqSolver.P .deps/QcLinEqSystem.P .deps/QcLinEqTableau.P .deps/QcLinInEqSolver.P .deps/QcLinInEqSystem.P .deps/QcLinInEqTableau.P .deps/QcLinPoly.P .deps/QcLinEqColStateVector.P .deps/QcLinEqRowStateVector.P .deps/QcLinInEqColStateVector.P .deps/QcLinInEqRowColStateVector.P .deps/QcNlpSolver.P .deps/QcNomadicFloatRep.P .deps/QcOrigRowStateVector.P .deps/QcQuasiRowColStateVector.P .deps/QcQuasiRowStateVector.P .deps/QcSolver.P .deps/QcSparseMatrix.P .deps/QcVarStow.P .deps/QcVariableBiMap.P + +CXXFLAGS = @CXXFLAGS@ +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ +CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) + +libqoca_la_myOBJECTS = QcCassSolver.lo QcCompPivotSystem.lo QcCompPivotTableau.lo QcConstraintRep.lo QcCoreTableau.lo QcDelCoreTableau.lo QcDelLinEqTableau.lo QcDelLinInEqTableau.lo QcDenseMatrix.lo QcFixedFloatRep.lo QcFloatRep.lo QcIneqSolverBase.lo QcLinEqSolver.lo QcLinEqSystem.lo QcLinEqTableau.lo QcLinInEqSolver.lo QcLinInEqSystem.lo QcLinInEqTableau.lo QcLinPoly.lo QcLinEqColStateVector.lo QcLinEqRowStateVector.lo QcLinInEqColStateVector.lo QcLinInEqRowColStateVector.lo QcNlpSolver.lo QcNomadicFloatRep.lo QcOrigRowStateVector.lo QcQuasiRowColStateVector.lo QcQuasiRowStateVector.lo QcSolver.lo QcSparseMatrix.lo QcVarStow.lo QcVariableBiMap.lo + +ii0_files = QcCassSolver.ii0 QcCompPivotSystem.ii0 QcCompPivotTableau.ii0 QcConstraintRep.ii0 QcCoreTableau.ii0 QcDelCoreTableau.ii0 QcDelLinEqTableau.ii0 QcDelLinInEqTableau.ii0 QcDenseMatrix.ii0 QcFixedFloatRep.ii0 QcFloatRep.ii0 QcIneqSolverBase.ii0 QcLinEqSolver.ii0 QcLinEqSystem.ii0 QcLinEqTableau.ii0 QcLinInEqSolver.ii0 QcLinInEqSystem.ii0 QcLinInEqTableau.ii0 QcLinPoly.ii0 QcLinEqColStateVector.ii0 QcLinEqRowStateVector.ii0 QcLinInEqColStateVector.ii0 QcLinInEqRowColStateVector.ii0 QcNlpSolver.ii0 QcNomadicFloatRep.ii0 QcOrigRowStateVector.ii0 QcQuasiRowColStateVector.ii0 QcQuasiRowStateVector.ii0 QcSolver.ii0 QcSparseMatrix.ii0 QcVarStow.ii0 QcVariableBiMap.ii0 + +# Note that we must start off with no .deps files. + +cc = cc +BUILT_SOURCES = arith.H QcAliasedBiMap.H QcAliasedBiMap.hh QcASetSolver.H QcASetSolver.hh QcASetSolver.$(cc) QcBiMap.H QcBiMap.hh QcFloatRep.H QcFloatRep.hh QcFloatRep.$(cc) QcFixedFloatRep.H QcFixedFloatRep.hh QcFixedFloatRep.$(cc) QcIneqSolverBase.H QcIneqSolverBase.hh QcIneqSolverBase.$(cc) QcLinEqColStateVector.H QcLinEqColStateVector.hh QcLinEqColStateVector.$(cc) QcLinEqRowStateVector.H QcLinEqRowStateVector.hh QcLinEqRowStateVector.$(cc) QcLinInEqColStateVector.H QcLinInEqColStateVector.hh QcLinInEqColStateVector.$(cc) QcLinInEqRowColStateVector.H QcLinInEqRowColStateVector.hh QcLinInEqRowColStateVector.$(cc) QcNlpSolver.H QcNlpSolver.hh QcNlpSolver.$(cc) QcNomadicFloatRep.H QcNomadicFloatRep.hh QcNomadicFloatRep.$(cc) QcNullIterator.H QcOrigRowStateVector.H QcOrigRowStateVector.hh QcOrigRowStateVector.$(cc) QcQuasiRowColStateVector.H QcQuasiRowColStateVector.hh QcQuasiRowColStateVector.$(cc) QcQuasiRowStateVector.H QcQuasiRowStateVector.hh QcQuasiRowStateVector.$(cc) QcSolver.H QcSolver.hh QcSolver.$(cc) QcVarStow.H QcVarStow.hh QcVarStow.$(cc) QcVariableBiMap.H QcVariableBiMap.hh QcVariableBiMap.$(cc) + +SUFFIXES = .ch .cc .hh .H .ii0 + +lib_LTLIBRARIES = libqoca.la +# Version info is `CURRENT[:REVISION[:AGE]]': *see (libtool)Versioning, +# in the libtool info page. +libqoca_la_LDFLAGS = -version-info 0:0:0 +libqoca_la_LIBADD = -lstdc++ $(lwn) $(lgmp) + +# Package visibility is implemented in C++ as `#ifdef QOCA_INTERNALS'. +# N.B. This is only for methods; for vars, make the var itself private +# and provide package-visible inline access methods. +# N.B.2: Also be careful of the needs of inline functions. +INCLUDES = -DQOCA_INTERNALS -I.. -I$(top_srcdir)/cxx + +# Things needed by user programs. User programs #include only Qc.h, but Qc.h +# #includes the rest of these. +pkginclude_HEADERS = arith.H KeyIterator.hh QcASetSolver.H QcAliasedBiMap.H QcAliasedBiMap.hh QcFloat.hh QcFixedFloat.hh QcConstraint.hh QcBasicnessVarIndexIterator.hh QcBiMap.H QcBiMap.hh QcCassSolver.hh QcLinEqSolver.hh QcLinInEqSolver.hh QcUtility.hh QcDefines.hh QcEnables.H QcFixedFloatRep.H QcFixedFloatRep.hh QcFloatRep.H QcFloatRep.hh QcCassConstraint.hh QcDelLinEqSystem.hh QcDesireValueStore.hh QcCompPivotSystem.hh QcCompPivotTableau.hh QcConstraintRep.hh QcDelLinEqTableau.hh QcDelLinInEqSystem.hh QcException.hh QcIneqSolverBase.H QcLinEqSystem.hh QcLinInEqSystem.hh QcLinPoly.hh QcBiMapNotifier.hh QcDelLinInEqTableau.hh QcLinEqTableau.hh QcLinInEqTableau.hh QcLinPolyTerm.hh QcSolver.H QcSolver.hh QcSparseCoeff.hh QcConstraintBiMap.hh QcDelCoreTableau.hh QcLinEqRowColStateVector.hh QcLinInEqRowColStateVector.H QcLinInEqRowColStateVector.hh QcRowAdaptor.hh QcTableau.hh QcVariableBiMap.H QcVariableBiMap.hh QcCoreTableau.hh QcDenseMatrix.hh QcLinEqColStateVector.H QcLinEqColStateVector.hh QcLinEqRowStateVector.H QcLinEqRowStateVector.hh QcLinInEqColStateVector.H QcLinInEqColStateVector.hh QcNullableConstraint.hh QcNullableElement.hh QcNullableFloat.hh QcQuasiRowColStateVector.H QcQuasiRowColStateVector.hh QcSparseMatrixColIterator.hh QcTableauRowIterator.hh QcLinEqColState.hh QcLinEqRowState.hh QcLinInEqColState.hh QcMatrix.hh QcNlpSolver.H QcNlpSolver.hh QcNomadicFloatRep.H QcNomadicFloatRep.hh QcOrigRowStateVector.H QcOrigRowStateVector.hh QcQuasiColStateVector.hh QcQuasiRowStateVector.H QcQuasiRowStateVector.hh QcSolvedFormMatrix.hh QcSparseMatrixIterator.hh QcSparseMatrixRowIterator.hh QcMatrixIterator.hh QcOrigRowState.hh QcQuasiColState.hh QcQuasiRowState.hh QcSparseMatrix.hh QcStateVector.hh QcIterator.hh QcSparseMatrixElement.hh QcState.hh QcUnsortedListSet.hh QcVarStow.H + +dist_libqoca_sources = QcASetSolver.H QcASetSolver.hh QcASetSolver.$(cc) QcCassSolver.cc QcCompPivotSystem.cc QcCompPivotTableau.cc QcConstraintRep.cc QcCoreTableau.cc QcDelCoreTableau.cc QcDelLinEqTableau.cc QcDelLinInEqTableau.cc QcDenseMatrix.cc QcFloatRep.cc QcIneqSolverBase.H QcIneqSolverBase.hh QcIneqSolverBase.$(cc) QcLinEqSolver.cc QcLinEqSystem.cc QcLinEqTableau.cc QcLinInEqSolver.cc QcLinInEqSystem.cc QcLinInEqTableau.cc QcLinPoly.cc QcSolver.cc QcSparseMatrix.cc KeyIterator.hh QcAliasedBiMap.H QcAliasedBiMap.hh QcBasicnessVarIndexIterator.hh QcBasicVarIndexIterator.hh QcBiMap.H QcBiMap.hh QcBiMapNotifier.hh QcCassConstraint.hh QcCassSolver.hh QcCompPivotSystem.hh QcCompPivotTableau.hh QcConstraint.hh QcConstraintBiMap.hh QcConstraintIndexIterator.hh QcConstraintRep.hh QcCoreTableau.hh QcDefines.hh QcDelCoreTableau.hh QcDelLinEqSystem.hh QcDelLinEqTableau.hh QcDelLinInEqSystem.hh QcDelLinInEqTableau.hh QcDenseMatrix.hh QcDenseMatrixColIterator.hh QcDenseMatrixIterator.hh QcDenseMatrixRowIterator.hh QcDenseTableauColIterator.hh QcDenseTableauIterator.hh QcDenseTableauRowIterator.hh QcDesireValueStore.hh QcException.hh QcFixedFloat.hh QcFixedFloatRep.cc QcFixedFloatRep.hh QcFloat.hh QcFloatRep.hh QcIterator.hh QcLinEqColState.hh QcLinEqColStateVector.H QcLinEqColStateVector.hh QcLinEqColStateVector.$(cc) QcLinEqRowColStateVector.hh QcLinEqRowState.hh QcLinEqRowStateVector.H QcLinEqRowStateVector.hh QcLinEqRowStateVector.$(cc) QcLinEqSolver.hh QcLinEqSystem.hh QcLinEqTableau.hh QcLinInEqColState.hh QcLinInEqColStateVector.H QcLinInEqColStateVector.hh QcLinInEqColStateVector.$(cc) QcLinInEqRowColStateVector.H QcLinInEqRowColStateVector.hh QcLinInEqRowColStateVector.$(cc) QcLinInEqSolver.hh QcLinInEqSystem.hh QcLinInEqTableau.hh QcLinPoly.hh QcLinPolyTerm.hh QcMatrix.hh QcMatrixIterator.hh QcOrigRowState.hh QcNlpSolver.H QcNlpSolver.hh QcNlpSolver.$(cc) QcNomadicFloatRep.cc QcNomadicFloatRep.hh QcNullIterator.H QcNullableConstraint.hh QcNullableElement.hh QcNullableFloat.hh QcOrigRowStateVector.H QcOrigRowStateVector.hh QcOrigRowStateVector.cc QcParamVarIndexIterator.hh QcQuasiColState.hh QcQuasiColStateVector.hh QcQuasiRowColStateVector.H QcQuasiRowColStateVector.hh QcQuasiRowColStateVector.$(cc) QcRowAdaptor.hh QcQuasiRowStateVector.H QcQuasiRowStateVector.hh QcQuasiRowStateVector.cc QcQuasiRowState.hh QcSolvedFormMatrix.hh QcSolver.hh QcSparseCoeff.hh QcSparseMatrix.hh QcSparseMatrixColIterator.hh QcSparseMatrixElement.hh QcSparseMatrixIterator.hh QcSparseMatrixRowIterator.hh QcState.hh QcStateVector.hh QcStructVarIndexIterator.hh QcTableau.hh QcTableauColIterator.hh QcTableauRowIterator.hh QcUnsortedListSet.hh QcUtility.hh QcVarStow.H QcVarStow.hh QcVarStow.$(cc) QcVariableBiMap.H QcVariableBiMap.hh QcVariableBiMap.$(cc) QcVariableIndexIterator.hh arith.H + +ch_files = QcAliasedBiMap.ch QcASetSolver.ch QcBiMap.ch QcFixedFloatRep.ch QcFloatRep.ch QcIneqSolverBase.ch QcLinEqColStateVector.ch QcLinEqRowStateVector.ch QcLinInEqColStateVector.ch QcLinInEqRowColStateVector.ch QcNlpSolver.ch QcNomadicFloatRep.ch QcNullIterator.ch QcOrigRowStateVector.ch QcQuasiRowColStateVector.ch QcQuasiRowStateVector.ch QcSolver.ch QcVariableBiMap.ch QcVarStow.ch arith.ch + +libqoca_la_SOURCES = +# Rationale for emptiness: If it has any .cc files, then automake +# produces .cc.o rules, which stuffs things up (because make sometimes +# tries to use them directly instead of using the .ii0.o rule). If it +# had .ii0 files, then the .ii0 files would be put into distdir, which +# is wrong because .ii0 files contain system header file contents. + +EXTRA_DIST = $(dist_libqoca_sources) Makefile.am.m4 $(ch_files) + +CLEANFILES = *.ii *.ii0 + +DISTCLEANFILES = -r .deps +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_CLEAN_FILES = QcEnables.H +LTLIBRARIES = $(lib_LTLIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libqoca_la_DEPENDENCIES = +libqoca_la_OBJECTS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(pkginclude_HEADERS) + +DIST_COMMON = ChangeLog Makefile.am Makefile.in QcEnables.H.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +SOURCES = $(libqoca_la_SOURCES) +OBJECTS = $(libqoca_la_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .H .S .c .cc .ch .hh .ii0 .lo .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps cxx/qoca/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +QcEnables.H: $(top_builddir)/config.status QcEnables.H.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +mostlyclean-libLTLIBRARIES: + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + +distclean-libLTLIBRARIES: + +maintainer-clean-libLTLIBRARIES: + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(libdir) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo "$(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p"; \ + $(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.c.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(pkgincludedir) + @list='$(pkginclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \ + echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(pkgincludedir)/$$p"; \ + $(INSTALL_DATA) $$d$$p $(DESTDIR)$(pkgincludedir)/$$p; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + list='$(pkginclude_HEADERS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(pkgincludedir)/$$p; \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = cxx/qoca + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-libLTLIBRARIES +install-exec: install-exec-am + +install-data-am: install-pkgincludeHEADERS +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-libLTLIBRARIES uninstall-pkgincludeHEADERS +uninstall: uninstall-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(pkgincludedir) + + +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean-am: mostlyclean-libLTLIBRARIES mostlyclean-compile \ + mostlyclean-libtool mostlyclean-tags \ + mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-libLTLIBRARIES clean-compile clean-libtool clean-tags \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-libLTLIBRARIES distclean-compile \ + distclean-libtool distclean-tags distclean-generic \ + clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-libLTLIBRARIES \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \ +clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \ +uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \ +distclean-compile clean-compile maintainer-clean-compile \ +mostlyclean-libtool distclean-libtool clean-libtool \ +maintainer-clean-libtool uninstall-pkgincludeHEADERS \ +install-pkgincludeHEADERS tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +$(srcdir)/Makefile.am: Makefile.am.m4 + rm -f $(srcdir)/$(@F) + m4 -P $(srcdir)/$( $(srcdir)/$(@F) + +.ch.cc: $(CH2XX) + @rm -f $(bsrcdir)/$(*F).cc && if echo "$(CH2XX) -c $< > $(bsrcdir)/$(*F).cc" \ + && $(CH2XX) -c $< > $(bsrcdir)/$(*F).cc; \ + then :; \ + else echo "rm -f $(bsrcdir)/$(*F).cc; exit 1" \ + && rm -f $(bsrcdir)/$(*F).cc; exit 1; fi + +.ch.hh: $(CH2XX) + @rm -f $(bsrcdir)/$(*F).hh && if echo "$(CH2XX) -i $< > $(bsrcdir)/$(*F).hh" \ + && $(CH2XX) -i $< > $(bsrcdir)/$(*F).hh; \ + then :; \ + else echo "rm -f $(bsrcdir)/$(*F).hh; exit 1" \ + && rm -f $(bsrcdir)/$(*F).hh; exit 1; fi + +.ch.H: $(CH2XX) + @rm -f $(bsrcdir)/$(*F).H && if echo "$(CH2XX) -d $< > $(bsrcdir)/$(*F).H" \ + && $(CH2XX) -d $< > $(bsrcdir)/$(*F).H; \ + then :; \ + else echo "rm -f $(bsrcdir)/$(*F).H; exit 1" \ + && rm -f $(bsrcdir)/$(*F).H; exit 1; fi + + +.cc.ii0: + @rm -f $(bsrcdir)/$(@F) && if echo "$(CXXCPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) -Wp,-MD,.deps/$(*F).pp $< > $(bsrcdir)/$(@F)" \ + && $(CXXCPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) -Wp,-MD,.deps/$(*F).pp $< > $(bsrcdir)/$(@F); \ + then :; \ + else echo "rm -f $(bsrcdir)/$(@F); exit 1" \ + && rm -f $(bsrcdir)/$(@F); exit 1; fi + @rm -f .deps/$(*F).P + @-sed 's/\.o/.ii0/g' < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +libqoca.la: $(ii0_files) $(libqoca_la_myOBJECTS) $(libqoca_la_DEPENDENCIES) + $(CXXLINK) -rpath $(libdir) $(libqoca_la_LDFLAGS) $(libqoca_la_myOBJECTS) $(libqoca_la_LIBADD) $(LIBS) + +.ii0.o: + @if test -f $@ && cmp -s $(bsrcdir)/$(/dev/null; then :; else \ + echo "cp $(bsrcdir)/$(/dev/null; then :; else \ + echo "cp $(bsrcdir)/$( $(distdir)/Makefile.tmp + mv $(distdir)/Makefile.tmp $(distdir)/Makefile.in + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/kits/interface/qoca/QcASetSolver.H b/src/kits/interface/qoca/QcASetSolver.H new file mode 100644 index 0000000000..6a2558e653 --- /dev/null +++ b/src/kits/interface/qoca/QcASetSolver.H @@ -0,0 +1,35 @@ +// Generated automatically from QcASetSolver.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcASetSolverDCL +#define QcASetSolverDCL +#line 1 "QcASetSolver.ch" +#include + + +class QcASetSolver + : public QcSolver +{ +public: + +inline +QcASetSolver(); +#line 15 "QcASetSolver.ch" +inline +QcASetSolver(unsigned hintNumConstraints, unsigned hintNumVariables); +#line 22 "QcASetSolver.ch" +virtual ~QcASetSolver() +{ +} + + +}; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcASetSolverDCL */ diff --git a/src/kits/interface/qoca/QcASetSolver.cc b/src/kits/interface/qoca/QcASetSolver.cc new file mode 100644 index 0000000000..6a797579e2 --- /dev/null +++ b/src/kits/interface/qoca/QcASetSolver.cc @@ -0,0 +1,20 @@ +// Generated automatically from QcASetSolver.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcASetSolver.hh" +#line 1 "QcASetSolver.ch" + +#include + + + + + + +#line 29 "QcASetSolver.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcASetSolver.ch b/src/kits/interface/qoca/QcASetSolver.ch new file mode 100644 index 0000000000..da61ee0b26 --- /dev/null +++ b/src/kits/interface/qoca/QcASetSolver.ch @@ -0,0 +1,36 @@ +//o[d] #include +//o[ci] #include + +//ho class QcASetSolver +//ho : public QcSolver +//ho { +//ho public: + +inline +QcASetSolver() + : QcSolver() +{ +} + +inline +QcASetSolver(unsigned hintNumConstraints, unsigned hintNumVariables) + : QcSolver() +{ +} + +//begin ho +virtual ~QcASetSolver() +{ +} +//end ho + +//ho }; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcASetSolver.hh b/src/kits/interface/qoca/QcASetSolver.hh new file mode 100644 index 0000000000..40b03e9c6a --- /dev/null +++ b/src/kits/interface/qoca/QcASetSolver.hh @@ -0,0 +1,37 @@ +// Generated automatically from QcASetSolver.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcASetSolver.H" +#ifndef QcASetSolverIFN +#define QcASetSolverIFN +#line 1 "QcASetSolver.ch" + +#include + + + + + + +inline +QcASetSolver::QcASetSolver() + : QcSolver() +{ +} + +inline +QcASetSolver::QcASetSolver(unsigned hintNumConstraints, unsigned hintNumVariables) + : QcSolver() +{ +} + + +#line 29 "QcASetSolver.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcASetSolverIFN */ diff --git a/src/kits/interface/qoca/QcAliasedBiMap.H b/src/kits/interface/qoca/QcAliasedBiMap.H new file mode 100644 index 0000000000..9d8223a90e --- /dev/null +++ b/src/kits/interface/qoca/QcAliasedBiMap.H @@ -0,0 +1,72 @@ +// Generated automatically from QcAliasedBiMap.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcAliasedBiMapDCL +#define QcAliasedBiMapDCL +#line 1 "QcAliasedBiMap.ch" + +#include + + +#line 11 "QcAliasedBiMap.ch" +#define TMPL template +TMPL +class QcAliasedBiMap + : public QcBiMap +{ + + + + +public: + QcAliasedBiMap() { } + + + +inline void +Update(ExternalT const &ident, int index); +#line 33 "QcAliasedBiMap.ch" +inline void +Update(PointedToT *ident, int index); +#line 41 "QcAliasedBiMap.ch" +inline bool +IdentifierPresent(ExternalT const &ident) const; +#line 48 "QcAliasedBiMap.ch" +inline bool +IdentifierPtrPresent(PointedToT *ident) const; +#line 55 "QcAliasedBiMap.ch" +inline ExternalT & +Identifier(int index); +#line 67 "QcAliasedBiMap.ch" +inline ExternalT & +Identifier(char const *n); +#line 79 "QcAliasedBiMap.ch" +inline PointedToT * +getIdentifierPtr(int index); +#line 87 "QcAliasedBiMap.ch" +inline int +Index(ExternalT const &ident) const; +#line 94 "QcAliasedBiMap.ch" +inline int +Index(PointedToT *ident) const; +#line 101 "QcAliasedBiMap.ch" +inline int +safeIndex(ExternalT const &ident) const; +#line 108 "QcAliasedBiMap.ch" +inline int +safeIndex(PointedToT *ident) const; +#line 114 "QcAliasedBiMap.ch" +}; + +#undef TMPL +#undef A2E +#undef const_E2A + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcAliasedBiMapDCL */ diff --git a/src/kits/interface/qoca/QcAliasedBiMap.ch b/src/kits/interface/qoca/QcAliasedBiMap.ch new file mode 100644 index 0000000000..9a2ac9201c --- /dev/null +++ b/src/kits/interface/qoca/QcAliasedBiMap.ch @@ -0,0 +1,127 @@ +//begin o[d] +#include +//end o[d] +//begin o[i] +#include + +#define A2E(_nkey) *((ExternalT *)((void *)&(_nkey))) +#define const_E2A(_ekey) reinterpret_cast(_ekey) +//end o[i] + +#define TMPL template +//o[d] TMPL +//o[d] class QcAliasedBiMap +//o[d] : public QcBiMap +//o[d] { + +//$class_prefix = QcAliasedBiMap:: + +//begin o[d] +public: + QcAliasedBiMap() { } +//end o[d] + +//o[i] TMPL +inline void +Update(ExternalT const &ident, int index) +{ + qcAssertPre( ident.pointer() != 0); + QcBiMap::Update(const_E2A(ident), index); +} + +//o[i] TMPL +inline void +Update(PointedToT *ident, int index) +{ + qcAssertPre( ident != 0); + QcBiMap::Update( NullableT( ident), index); +} + +//o[i] TMPL +inline bool +IdentifierPresent(ExternalT const &ident) const +{ + return QcBiMap::IdentifierPresent(const_E2A(ident)); +} + +//o[i] TMPL +inline bool +IdentifierPtrPresent(PointedToT *ident) const +{ + return QcBiMap::IdentifierPresent( NullableT( ident)); +} + +//o[i] TMPL +inline ExternalT & +Identifier(int index) +{ + NullableT &nid = QcBiMap::Identifier( index); + NullableT *nidp = &nid; + void *vp = nidp; + ExternalT *ep = (ExternalT *) vp; + ExternalT &eid = *ep; + return eid; +} + +//o[i] TMPL +inline ExternalT & +Identifier(char const *n) +{ + NullableT &nid = QcBiMap::Identifier( n); + NullableT *nidp = &nid; + void *vp = nidp; + ExternalT *ep = (ExternalT *) vp; + ExternalT &eid = *ep; + return eid; +} + +//o[i] TMPL +inline PointedToT * +getIdentifierPtr(int index) +{ + NullableT &nid = QcBiMap::Identifier( index); + return nid.pointer(); +} + +//o[i] TMPL +inline int +Index(ExternalT const &ident) const +{ + return QcBiMap::Index(const_E2A(ident)); +} + +//o[i] TMPL +inline int +Index(PointedToT *ident) const +{ + return QcBiMap::Index( NullableT( ident)); +} + +//o[i] TMPL +inline int +safeIndex(ExternalT const &ident) const +{ + return QcBiMap::safeIndex(const_E2A(ident)); +} + +//o[i] TMPL +inline int +safeIndex(PointedToT *ident) const +{ + return QcBiMap::safeIndex( NullableT( ident)); +} + +//o[d] }; + +#undef TMPL +#undef A2E +#undef const_E2A + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcAliasedBiMap.hh b/src/kits/interface/qoca/QcAliasedBiMap.hh new file mode 100644 index 0000000000..22caef6f8a --- /dev/null +++ b/src/kits/interface/qoca/QcAliasedBiMap.hh @@ -0,0 +1,129 @@ +// Generated automatically from QcAliasedBiMap.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcAliasedBiMap.H" +#ifndef QcAliasedBiMapIFN +#define QcAliasedBiMapIFN +#line 1 "QcAliasedBiMap.ch" + +#line 5 "QcAliasedBiMap.ch" +#include + +#define A2E(_nkey) *((ExternalT *)((void *)&(_nkey))) +#define const_E2A(_ekey) reinterpret_cast(_ekey) + + +#define TMPL template + + + + + + + + +#line 24 "QcAliasedBiMap.ch" +TMPL +inline void +QcAliasedBiMap::Update(ExternalT const &ident, int index) +{ + qcAssertPre( ident.pointer() != 0); + QcBiMap::Update(const_E2A(ident), index); +} + +TMPL +inline void +QcAliasedBiMap::Update(PointedToT *ident, int index) +{ + qcAssertPre( ident != 0); + QcBiMap::Update( NullableT( ident), index); +} + +TMPL +inline bool +QcAliasedBiMap::IdentifierPresent(ExternalT const &ident) const +{ + return QcBiMap::IdentifierPresent(const_E2A(ident)); +} + +TMPL +inline bool +QcAliasedBiMap::IdentifierPtrPresent(PointedToT *ident) const +{ + return QcBiMap::IdentifierPresent( NullableT( ident)); +} + +TMPL +inline ExternalT & +QcAliasedBiMap::Identifier(int index) +{ + NullableT &nid = QcBiMap::Identifier( index); + NullableT *nidp = &nid; + void *vp = nidp; + ExternalT *ep = (ExternalT *) vp; + ExternalT &eid = *ep; + return eid; +} + +TMPL +inline ExternalT & +QcAliasedBiMap::Identifier(char const *n) +{ + NullableT &nid = QcBiMap::Identifier( n); + NullableT *nidp = &nid; + void *vp = nidp; + ExternalT *ep = (ExternalT *) vp; + ExternalT &eid = *ep; + return eid; +} + +TMPL +inline PointedToT * +QcAliasedBiMap::getIdentifierPtr(int index) +{ + NullableT &nid = QcBiMap::Identifier( index); + return nid.pointer(); +} + +TMPL +inline int +QcAliasedBiMap::Index(ExternalT const &ident) const +{ + return QcBiMap::Index(const_E2A(ident)); +} + +TMPL +inline int +QcAliasedBiMap::Index(PointedToT *ident) const +{ + return QcBiMap::Index( NullableT( ident)); +} + +TMPL +inline int +QcAliasedBiMap::safeIndex(ExternalT const &ident) const +{ + return QcBiMap::safeIndex(const_E2A(ident)); +} + +TMPL +inline int +QcAliasedBiMap::safeIndex(PointedToT *ident) const +{ + return QcBiMap::safeIndex( NullableT( ident)); +} + + + +#undef TMPL +#undef A2E +#undef const_E2A + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcAliasedBiMapIFN */ diff --git a/src/kits/interface/qoca/QcBasicVarIndexIterator.hh b/src/kits/interface/qoca/QcBasicVarIndexIterator.hh new file mode 100644 index 0000000000..04575625e9 --- /dev/null +++ b/src/kits/interface/qoca/QcBasicVarIndexIterator.hh @@ -0,0 +1,69 @@ +// $Id: QcBasicVarIndexIterator.hh,v 1.5 2000/11/29 01:58:42 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcBasicVarIndexIteratorH +#define __QcBasicVarIndexIteratorH + +#include + +class QcBasicVarIndexIterator + : public QcBasicnessVarIndexIterator +{ +public: + + //------------------------------------------------------------------------// + // Constructor. // + //------------------------------------------------------------------------// + QcBasicVarIndexIterator( const QcLinEqTableau &tab) + : QcBasicnessVarIndexIterator( &tab.GetColState().fBasicHead) + { + } + + void Reset() + { + QcBasicnessVarIndexIterator::Reset(); + qcAssertPost( fCurrent->isBasic()); + } + + void Increment() + { + QcBasicnessVarIndexIterator::Increment(); + qcAssertPost( fCurrent->isBasic()); + } + + /** @precondition !AtEnd() + @postcondition (int) ret ≥ 0 + **/ + unsigned getConstraintBasicIn() const + { + qcAssertPre (!AtEnd()); + int ret = fCurrent->getConstraintBasicIn(); + qcAssertPost (ret >= 0); + return (unsigned) ret; + } +}; + +#endif /* !__QcBasicVarIndexIteratorH */ diff --git a/src/kits/interface/qoca/QcBasicnessVarIndexIterator.hh b/src/kits/interface/qoca/QcBasicnessVarIndexIterator.hh new file mode 100644 index 0000000000..200d84e7e5 --- /dev/null +++ b/src/kits/interface/qoca/QcBasicnessVarIndexIterator.hh @@ -0,0 +1,86 @@ +// $Id: QcBasicnessVarIndexIterator.hh,v 1.1 2000/11/29 01:58:42 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcBasicnessVarIndexIteratorH +#define __QcBasicnessVarIndexIteratorH + +class QcBasicnessVarIndexIterator +{ +public: + + //------------------------------------------------------------------------// + // Constructor. // + //------------------------------------------------------------------------// + QcBasicnessVarIndexIterator (QcLinEqColState const *head); + + //------------------------------------------------------------------------// + // Iteration functions. // + //------------------------------------------------------------------------// + bool AtEnd() const + { + return (fCurrent == fHead); + } + + /** @precondition !AtEnd() + @postcondition (int) ret ≥ 0 + **/ + unsigned getIndex() const + { + qcAssertPre (!AtEnd()); + unsigned ret = fCurrent->fIndex; + qcAssertPost ((int) ret >= 0); + return ret; + } + + + void Increment() + { + qcAssertPre (!AtEnd()); + + fCurrent = fCurrent->getNextBasicnessCol(); + } + + + void Reset() + { + fCurrent = fHead->getNextBasicnessCol(); + } + +protected: + QcLinEqColState const *fCurrent; +private: + QcLinEqColState const *fHead; +}; + + +inline +QcBasicnessVarIndexIterator::QcBasicnessVarIndexIterator (QcLinEqColState const *head) + : fHead (head) +{ + Reset(); +} + +#endif /* !__QcBasicnessVarIndexIteratorH */ diff --git a/src/kits/interface/qoca/QcBiMap.H b/src/kits/interface/qoca/QcBiMap.H new file mode 100644 index 0000000000..bc374a15f9 --- /dev/null +++ b/src/kits/interface/qoca/QcBiMap.H @@ -0,0 +1,194 @@ +// Generated automatically from QcBiMap.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcBiMapDCL +#define QcBiMapDCL +#line 1 "QcBiMap.ch" + +#include +#include +#include +#include "qoca/QcDefines.hh" +#include "qoca/KeyIterator.hh" + + +/** Bi-directional one-to-one mapping between identifier class and non-negative + integers. + + @invariant ∀[ix ∈ indexes] ix ≥ 0 + @invariant ∀[id ∈ idents] index(id) ∈ indexes + @invariant ∀[ix ∈ indexes] identifier(ix) ∈ idents + @invariant &neg;∃[i ≠ j] {i, j} &subeq; indexes ∧ identifier(i) = identifier(j) + @invariant &neg;∃[i ≠ j] {i, j} &subeq; idents ∧ index(i) = index(j) + @invariant ∀[ix ∈ indexes] index(identifier(ix)) = ix + @invariant ∀[id ∈ idents] identifier(index(id)) = id +**/ + + + +template +class QcBiMap +{ + + +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcBiMap() + { } + + virtual ~QcBiMap() { } + + + +#ifndef NDEBUG + +inline void +assertInvar() const; +#line 63 "QcBiMap.ch" +inline void +assertDeepInvar() const; +#line 70 "QcBiMap.ch" +virtual inline void +vAssertDeepInvar() const; +#line 75 "QcBiMap.ch" +#endif + + +protected: + typedef map > TIdentifierMap; + typedef vector TIndexMap; + +public: + typedef KeyIterator const_identifier_iterator; + + + //-----------------------------------------------------------------------// + // BiMap manipulation functions. // + //-----------------------------------------------------------------------// + +/** Remove item with index index. + @precondition index is currently in this bimap. +**/ + +inline void +EraseByIndex(int index); +#line 107 "QcBiMap.ch" +/** Erase everything ready to start afresh. */ + +inline void +Restart(); +#line 117 "QcBiMap.ch" +/** Swap the mappings around so that {ix1 ↔ id1, ix2 ↔ id2} + becomes {ix1 ↔ id2, ix2 ↔ id1}. + + @precondition ix1 and ix2 are both present in this + bimap. +**/ + +inline void +SwapByIndex(int i1, int i2); +#line 147 "QcBiMap.ch" +/** Insert the mapping identindex into this + bimap. + + @precondition index ≥ 0 + @precondition Neither index nor ident is currently + in this bimap. + @postcondition identifier(index) == ident + @postcondition index(ident) == index +**/ + +inline void +Update(const AKey &ident, int index); +#line 184 "QcBiMap.ch" +//-----------------------------------------------------------------------// +// Query functions. // +//-----------------------------------------------------------------------// + + + + /** Number of entries. */ + unsigned GetSize() const + { return fIdentifierMap.size(); } + + bool IdentifierPresent(AKey const &ident) const + { return (fIdentifierMap.find(ident) != fIdentifierMap.end()); } + + const_identifier_iterator + getIdentifiers_begin() const + { + TIdentifierMap::const_iterator i = fIdentifierMap.begin(); + return const_identifier_iterator (i); + } + + const_identifier_iterator getIdentifiers_end() const + { return const_identifier_iterator (fIdentifierMap.end()); } + + + + +inline AKey & +Identifier(int index); +#line 220 "QcBiMap.ch" +inline AKey & +Identifier(char const *n); +#line 237 "QcBiMap.ch" +/** Return the index associated with ident. + + @precondition IdentifierPresent(ident) + @postcondition ret ≥ 0. +**/ + +inline int +Index(AKey const &ident) const; +#line 255 "QcBiMap.ch" +/** Return the index associated with ident, + or -1 if ident is not present. + + @postcondition IdentifierPresent(ident) ⇔ (ret ≥ 0) +**/ + +inline int +safeIndex(AKey const &ident) const; +#line 273 "QcBiMap.ch" +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// +#ifndef qcNoStream + +inline void +Print(ostream &os) const; +#line 294 "QcBiMap.ch" +#endif /* !qcNoStream */ + + +protected: + TIdentifierMap fIdentifierMap; // AKey -> int + TIndexMap fIndexMap; // int -> AKey + +}; + + + +#ifndef qcNoStream +template +ostream &operator<<(ostream &os, const QcBiMap &bm) +{ + bm.Print(os); + return os; +} +#endif /* !qcNoStream */ + + + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcBiMapDCL */ diff --git a/src/kits/interface/qoca/QcBiMap.ch b/src/kits/interface/qoca/QcBiMap.ch new file mode 100644 index 0000000000..707b0f1771 --- /dev/null +++ b/src/kits/interface/qoca/QcBiMap.ch @@ -0,0 +1,324 @@ +//begin o[d] +#include +#include +#include +#include "qoca/QcDefines.hh" +#include "qoca/KeyIterator.hh" +//end o[d] + +/** Bi-directional one-to-one mapping between identifier class and non-negative + integers. + + @invariant ∀[ix ∈ indexes] ix ≥ 0 + @invariant ∀[id ∈ idents] index(id) ∈ indexes + @invariant ∀[ix ∈ indexes] identifier(ix) ∈ idents + @invariant &neg;∃[i ≠ j] {i, j} &subeq; indexes ∧ identifier(i) = identifier(j) + @invariant &neg;∃[i ≠ j] {i, j} &subeq; idents ∧ index(i) = index(j) + @invariant ∀[ix ∈ indexes] index(identifier(ix)) = ix + @invariant ∀[id ∈ idents] identifier(index(id)) = id +**/ + +//o[ci] #define TMPL template + +//o[d] template +//o[d] class QcBiMap +//o[d] { +//$class_prefix = QcBiMap:: +//begin o[d] +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcBiMap() + { } + + virtual ~QcBiMap() { } +//end o[d] + + +#ifndef NDEBUG +//o[i] TMPL +inline void +assertInvar() const +{ + for(int i = fIndexMap.size(); --i >= 0;) + { + fIndexMap[ i].assertInvar(); + if(fIndexMap[ i].isDead()) + continue; + TIdentifierMap::const_iterator f = fIdentifierMap.find(fIndexMap[i]); + qcAssertInvar( f != fIdentifierMap.end()); + qcAssertInvar( f->second == i); + } + + for(TIdentifierMap::const_iterator ii = fIdentifierMap.begin(); ii != fIdentifierMap.end(); ii++) + { + unsigned ix = ii->second; + qcAssertInvar( ix < fIndexMap.size()); + qcAssertInvar( fIndexMap[ ix] == ii->first); + } +} + +//o[i] TMPL +inline void +assertDeepInvar() const +{ + assertInvar(); +} + +//o[i] TMPL +virtual inline void +vAssertDeepInvar() const +{ + assertDeepInvar(); +} +#endif + +//begin o[d] +protected: + typedef map > TIdentifierMap; + typedef vector TIndexMap; + +public: + typedef KeyIterator const_identifier_iterator; +//end o[d] + + //-----------------------------------------------------------------------// + // BiMap manipulation functions. // + //-----------------------------------------------------------------------// + +/** Remove item with index index. + @precondition index is currently in this bimap. +**/ +//o[i] TMPL +inline void +EraseByIndex(int index) +{ + qcAssertPre( unsigned( index) < fIndexMap.size()); + + AKey &ident = fIndexMap[ index]; + qcAssertPre( ident.notDead()); + fIdentifierMap.erase( ident); + qcAssertPost( ident.notDead()); + ident.Decrease(); +} + + +/** Erase everything ready to start afresh. */ +//o[i] TMPL +inline void +Restart() +{ + fIdentifierMap.clear(); + fIndexMap.clear(); +} + + +/** Swap the mappings around so that {ix1 ↔ id1, ix2 ↔ id2} + becomes {ix1 ↔ id2, ix2 ↔ id1}. + + @precondition ix1 and ix2 are both present in this + bimap. +**/ +//o[i] TMPL +inline void +SwapByIndex(int i1, int i2) +{ + qcAssertPre( unsigned( i1) < fIndexMap.size()); + qcAssertPre( unsigned( i2) < fIndexMap.size()); + + AKey ident1 = fIndexMap[ i1]; + AKey ident2 = fIndexMap[ i2]; + qcAssertPre( ident1.notDead()); + qcAssertPre( ident2.notDead()); + fIndexMap[ i1] = ident2; + fIndexMap[ i2] = ident1; + + QcBiMap::TIdentifierMap::iterator it1 = fIdentifierMap.find( ident1); + qcAssertPost( it1 != fIdentifierMap.end()); + it1->second = i2; + + QcBiMap::TIdentifierMap::iterator it2 = fIdentifierMap.find( ident2); + qcAssertPost( it2 != fIdentifierMap.end()); + it2->second = i1; +} + + +/** Insert the mapping identindex into this + bimap. + + @precondition index ≥ 0 + @precondition Neither index nor ident is currently + in this bimap. + @postcondition identifier(index) == ident + @postcondition index(ident) == index +**/ +//o[i] TMPL +inline void +Update(const AKey &ident, int index) +{ + if(index >= (int) fIndexMap.size()) + fIndexMap.resize( (index * 2) + 1); + else + { + qcAssertPre( index >= 0); + qcAssertPre( fIndexMap[ index].isDead()); // index not present + } + + // Insert index->ident mapping. + fIndexMap[ index] = ident; + + // Insert ident->index mapping. + TIdentifierMap::value_type ins (ident, index); + typedef pair insResultT; + dbgPre(insResultT insResult =) + fIdentifierMap.insert (ins); + + qcAssertPre (insResult.second); // assert that ident wasn't present + + qcAssertPost (Identifier (index) == ident); + qcAssertPost (safeIndex (ident) == index); +} + + +//-----------------------------------------------------------------------// +// Query functions. // +//-----------------------------------------------------------------------// + +//begin o[d] + + /** Number of entries. */ + unsigned GetSize() const + { return fIdentifierMap.size(); } + + bool IdentifierPresent(AKey const &ident) const + { return (fIdentifierMap.find(ident) != fIdentifierMap.end()); } + + const_identifier_iterator + getIdentifiers_begin() const + { + TIdentifierMap::const_iterator i = fIdentifierMap.begin(); + return const_identifier_iterator (i); + } + + const_identifier_iterator getIdentifiers_end() const + { return const_identifier_iterator (fIdentifierMap.end()); } +//end o[d] + + +//o[i] TMPL +inline AKey & +Identifier(int index) +{ + qcAssertPre( unsigned( index) < fIndexMap.size()); + qcAssertPre( fIndexMap[ index].notDead()); + return fIndexMap[ index]; +} + + +//o[i] TMPL +inline AKey & +Identifier(char const *n) +{ + QcBiMap::TIdentifierMap::iterator iIt = fIdentifierMap.begin(); + + while(iIt != fIdentifierMap.end()) + { + AKey const &id = iIt->first; + if(strcmp( id.Name(), n) == 0) + return const_cast( id); + iIt++; + } + + throw QcWarning("Identifier cannot be found"); +} + + +/** Return the index associated with ident. + + @precondition IdentifierPresent(ident) + @postcondition ret ≥ 0. +**/ +//o[i] TMPL +inline int +Index(AKey const &ident) const +{ + QcBiMap::TIdentifierMap::const_iterator iIt = fIdentifierMap.find( ident); + qcAssertPre( iIt != fIdentifierMap.end()); + unsigned ix = iIt->second; + qcAssertPost( (ix < fIndexMap.size()) + && (fIndexMap[ix] == ident)); + return ix; +} + + +/** Return the index associated with ident, + or -1 if ident is not present. + + @postcondition IdentifierPresent(ident) ⇔ (ret ≥ 0) +**/ +//o[i] TMPL +inline int +safeIndex(AKey const &ident) const +{ + QcBiMap::TIdentifierMap::const_iterator iIt = fIdentifierMap.find( ident); + if(iIt == fIdentifierMap.end()) + return -1; + int ix = iIt->second; + qcAssertPost( ix >= 0); + return ix; +} + + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// +#ifndef qcNoStream +//o[i] TMPL +inline void +Print(ostream &os) const +{ + os << "Map start:" << endl; + + for (unsigned int i = 0; i < fIndexMap.size(); i++) + os << i << " -> " << fIndexMap[i] << endl; + + os << "Reverse Map:" << endl; + QcBiMap::TIdentifierMap::const_iterator itF; + + for (itF = fIdentifierMap.begin(); itF != fIdentifierMap.end(); ++itF) + os << (*itF).first << " -> " << (*itF).second << endl; + + os << "Map end." << endl; +} +#endif /* !qcNoStream */ + +//begin o[d] +protected: + TIdentifierMap fIdentifierMap; // AKey -> int + TIndexMap fIndexMap; // int -> AKey +//end o[d] +//o[d] }; + + +//begin o[d] +#ifndef qcNoStream +template +ostream &operator<<(ostream &os, const QcBiMap &bm) +{ + bm.Print(os); + return os; +} +#endif /* !qcNoStream */ +//end o[d] + +//o[ci] #undef TMPL + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcBiMap.hh b/src/kits/interface/qoca/QcBiMap.hh new file mode 100644 index 0000000000..1cb3ef3846 --- /dev/null +++ b/src/kits/interface/qoca/QcBiMap.hh @@ -0,0 +1,242 @@ +// Generated automatically from QcBiMap.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcBiMap.H" +#ifndef QcBiMapIFN +#define QcBiMapIFN +#line 1 "QcBiMap.ch" + +#line 21 "QcBiMap.ch" +#define TMPL template + + + + + + +#line 39 "QcBiMap.ch" +#ifndef NDEBUG +TMPL +inline void +QcBiMap::assertInvar() const +{ + for(int i = fIndexMap.size(); --i >= 0;) + { + fIndexMap[ i].assertInvar(); + if(fIndexMap[ i].isDead()) + continue; + TIdentifierMap::const_iterator f = fIdentifierMap.find(fIndexMap[i]); + qcAssertInvar( f != fIdentifierMap.end()); + qcAssertInvar( f->second == i); + } + + for(TIdentifierMap::const_iterator ii = fIdentifierMap.begin(); ii != fIdentifierMap.end(); ii++) + { + unsigned ix = ii->second; + qcAssertInvar( ix < fIndexMap.size()); + qcAssertInvar( fIndexMap[ ix] == ii->first); + } +} + +TMPL +inline void +QcBiMap::assertDeepInvar() const +{ + assertInvar(); +} + +TMPL +inline void +QcBiMap::vAssertDeepInvar() const +{ + assertDeepInvar(); +} +#endif + + +#line 86 "QcBiMap.ch" + //-----------------------------------------------------------------------// + // BiMap manipulation functions. // + //-----------------------------------------------------------------------// + + +#line 93 "QcBiMap.ch" +TMPL +inline void +QcBiMap::EraseByIndex(int index) +{ + qcAssertPre( unsigned( index) < fIndexMap.size()); + + AKey &ident = fIndexMap[ index]; + qcAssertPre( ident.notDead()); + fIdentifierMap.erase( ident); + qcAssertPost( ident.notDead()); + ident.Decrease(); +} + + + +TMPL +inline void +QcBiMap::Restart() +{ + fIdentifierMap.clear(); + fIndexMap.clear(); +} + + + +#line 123 "QcBiMap.ch" +TMPL +inline void +QcBiMap::SwapByIndex(int i1, int i2) +{ + qcAssertPre( unsigned( i1) < fIndexMap.size()); + qcAssertPre( unsigned( i2) < fIndexMap.size()); + + AKey ident1 = fIndexMap[ i1]; + AKey ident2 = fIndexMap[ i2]; + qcAssertPre( ident1.notDead()); + qcAssertPre( ident2.notDead()); + fIndexMap[ i1] = ident2; + fIndexMap[ i2] = ident1; + + QcBiMap::TIdentifierMap::iterator it1 = fIdentifierMap.find( ident1); + qcAssertPost( it1 != fIdentifierMap.end()); + it1->second = i2; + + QcBiMap::TIdentifierMap::iterator it2 = fIdentifierMap.find( ident2); + qcAssertPost( it2 != fIdentifierMap.end()); + it2->second = i1; +} + + + +#line 156 "QcBiMap.ch" +TMPL +inline void +QcBiMap::Update(const AKey &ident, int index) +{ + if(index >= (int) fIndexMap.size()) + fIndexMap.resize( (index * 2) + 1); + else + { + qcAssertPre( index >= 0); + qcAssertPre( fIndexMap[ index].isDead()); // index not present + } + + // Insert index->ident mapping. + fIndexMap[ index] = ident; + + // Insert ident->index mapping. + TIdentifierMap::value_type ins (ident, index); + typedef pair insResultT; + dbgPre(insResultT insResult =) + fIdentifierMap.insert (ins); + + qcAssertPre (insResult.second); // assert that ident wasn't present + + qcAssertPost (Identifier (index) == ident); + qcAssertPost (safeIndex (ident) == index); +} + + +//-----------------------------------------------------------------------// +// Query functions. // +//-----------------------------------------------------------------------// + + +#line 209 "QcBiMap.ch" +TMPL +inline AKey & +QcBiMap::Identifier(int index) +{ + qcAssertPre( unsigned( index) < fIndexMap.size()); + qcAssertPre( fIndexMap[ index].notDead()); + return fIndexMap[ index]; +} + + +TMPL +inline AKey & +QcBiMap::Identifier(char const *n) +{ + QcBiMap::TIdentifierMap::iterator iIt = fIdentifierMap.begin(); + + while(iIt != fIdentifierMap.end()) + { + AKey const &id = iIt->first; + if(strcmp( id.Name(), n) == 0) + return const_cast( id); + iIt++; + } + + throw QcWarning("Identifier cannot be found"); +} + + + +#line 242 "QcBiMap.ch" +TMPL +inline int +QcBiMap::Index(AKey const &ident) const +{ + QcBiMap::TIdentifierMap::const_iterator iIt = fIdentifierMap.find( ident); + qcAssertPre( iIt != fIdentifierMap.end()); + unsigned ix = iIt->second; + qcAssertPost( (ix < fIndexMap.size()) + && (fIndexMap[ix] == ident)); + return ix; +} + + + +#line 260 "QcBiMap.ch" +TMPL +inline int +QcBiMap::safeIndex(AKey const &ident) const +{ + QcBiMap::TIdentifierMap::const_iterator iIt = fIdentifierMap.find( ident); + if(iIt == fIdentifierMap.end()) + return -1; + int ix = iIt->second; + qcAssertPost( ix >= 0); + return ix; +} + + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// +#ifndef qcNoStream +TMPL +inline void +QcBiMap::Print(ostream &os) const +{ + os << "Map start:" << endl; + + for (unsigned int i = 0; i < fIndexMap.size(); i++) + os << i << " -> " << fIndexMap[i] << endl; + + os << "Reverse Map:" << endl; + QcBiMap::TIdentifierMap::const_iterator itF; + + for (itF = fIdentifierMap.begin(); itF != fIdentifierMap.end(); ++itF) + os << (*itF).first << " -> " << (*itF).second << endl; + + os << "Map end." << endl; +} +#endif /* !qcNoStream */ + + +#line 315 "QcBiMap.ch" +#undef TMPL + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcBiMapIFN */ diff --git a/src/kits/interface/qoca/QcBiMapNotifier.hh b/src/kits/interface/qoca/QcBiMapNotifier.hh new file mode 100644 index 0000000000..0aa331721b --- /dev/null +++ b/src/kits/interface/qoca/QcBiMapNotifier.hh @@ -0,0 +1,120 @@ +// $Id: QcBiMapNotifier.hh,v 1.6 2001/01/30 01:32:07 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcBiMapNotifierH +#define __QcBiMapNotifierH + +#include "qoca/QcConstraintBiMap.hh" +#include "qoca/QcVariableBiMap.hh" + +class QcBiMapNotifier +{ +private: + QcConstraintBiMap fOCMap; + QcVariableBiMap fVMap; + +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcBiMapNotifier() {} + virtual ~QcBiMapNotifier() {} + +#ifndef NDEBUG + void assertDeepInvar() const; + + virtual void vAssertDeepInvar() const + { + assertDeepInvar(); + } +#endif + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + QcConstraintBiMap &GetOCMap() + { return fOCMap; } + + QcVariableBiMap &GetVMap() + { return fVMap; } + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + virtual void DropConstraint(int ci); + + virtual void DropVariable(int vi) + { fVMap.EraseByIndex(vi); } + + virtual void SwapVariables(int vi1, int vi2) + { fVMap.SwapByIndex(vi1, vi2); } + + virtual void Restart(); + // Restart erases everything ready to start afresh. + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; +}; + +#ifndef NDEBUG +inline void QcBiMapNotifier::assertDeepInvar() const +{ + fOCMap.assertDeepInvar(); + fVMap.assertDeepInvar(); +} +#endif + +inline void QcBiMapNotifier::DropConstraint(int ci) +{ + fOCMap.EraseByIndex(ci); +} + +inline void QcBiMapNotifier::Print(ostream &os) const +{ + os << "Variables:" << endl; + fVMap.Print(os); + os << endl << "Constraints:" << endl; + fOCMap.Print(os); + os << endl; +} + +inline void QcBiMapNotifier::Restart() +{ + fOCMap.Restart(); + fVMap.Restart(); +} + +#ifndef qcNoStream +inline ostream& operator<<(ostream& os, const QcBiMapNotifier &n) +{ + n.Print(os); + return os; +} +#endif + +#endif diff --git a/src/kits/interface/qoca/QcCassConstraint.hh b/src/kits/interface/qoca/QcCassConstraint.hh new file mode 100644 index 0000000000..d4ee9a94ca --- /dev/null +++ b/src/kits/interface/qoca/QcCassConstraint.hh @@ -0,0 +1,66 @@ +// $Id: QcCassConstraint.hh,v 1.3 2000/07/27 08:10:04 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcCassConstraintH +#define __QcCassConstraintH + +class QcCassConstraint +{ +public: + QcFloat fVariable; + QcConstraint fConstraint; + QcFloat fDvp; + QcFloat fDvm; + + //-----------------------------------------------------------------------// + // Constructor // + //-----------------------------------------------------------------------// + QcCassConstraint(QcFloat &v, QcConstraint &c, QcFloat &dvp, QcFloat &dvm); + virtual ~QcCassConstraint() { } + + //-----------------------------------------------------------------------// + // Utility functions // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; +}; + +inline QcCassConstraint::QcCassConstraint(QcFloat &v, QcConstraint &c, + QcFloat &dvp, QcFloat &dvm) + : fVariable(v), fConstraint(c), fDvp(dvp), fDvm(dvm) +{ +} + +inline void QcCassConstraint::Print(ostream &os) const +{ + os << "CassConstraint(" + << fVariable << "," + << fConstraint << "," + << fDvp << "," + << fDvm << ")"; +} + +#endif + diff --git a/src/kits/interface/qoca/QcCassSolver.cc b/src/kits/interface/qoca/QcCassSolver.cc new file mode 100644 index 0000000000..2d96a25c72 --- /dev/null +++ b/src/kits/interface/qoca/QcCassSolver.cc @@ -0,0 +1,368 @@ +// $Id: QcCassSolver.cc,v 1.14 2001/01/04 05:20:11 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcCassSolver.hh" +#include "qoca/QcStructVarIndexIterator.hh" +#include "qoca/QcVariableIndexIterator.hh" + +QcCassSolver::~QcCassSolver() +{ + // Deallocate memory allocated to Cassowary stay constraints. + TStayMap::iterator sIt = fStayMap.begin(); + + while (sIt != fStayMap.end()) { + delete (*sIt).second; + sIt++; + } +} + +bool QcCassSolver::AddConstraint(QcConstraint &c) +{ + const QcLinPoly &lp = c.LinPoly(); + const QcLinPoly::TTermsVector &terms = lp.GetTerms(); + + // For each QcFloat, check if it has already been added as stay + // constraint. + for (unsigned int i = 0; i < terms.size(); i++) { + QcFloat &v = terms[i]->GetVariable(); + if (!IsRegistered(v)) + AddVar(v); + } + + bool success = QcDelLinInEqSystem::AddConstraint(c); + if (success) { +#if qcCheckPost + addCheckedConstraint( c.pointer()); +#endif + + if (fAutoSolve) + Solve(); + } + return success; +} + +bool QcCassSolver::AddConstraint(QcConstraint &c, QcFloat &hint) +{ + const QcLinPoly &lp = c.LinPoly(); + const QcLinPoly::TTermsVector &terms = lp.GetTerms(); + + // For each QcFloat, check if it has already been added as stay + // constraint. + for (unsigned int i = 0; i < terms.size(); i++) { + QcFloat &v = terms[i]->GetVariable(); + if (!IsRegistered(v)) + AddVar(v); + } + + bool success = QcDelLinInEqSystem::AddConstraint(c, hint); + if (success) { +#if qcCheckPost + addCheckedConstraint( c.pointer()); +#endif + + if (fAutoSolve) + Solve(); + } + return success; +} + +void QcCassSolver::AddEditVar(QcFloat &v) +{ + QcSolver::AddEditVar(v); + TStayMap::iterator sIt = fStayMap.find(v); + if (sIt == fStayMap.end()) { + throw QcWarning( + "QcCassSolver::AddEditVar - adding an unregistered variable"); + return; + } + + QcCassConstraint *stay = (*sIt).second; + stay->fDvp.SetToEditWeight(); + stay->fDvm.SetToEditWeight(); + fEditMap.push_back(stay); + fEditVarsSetup = false; +} + +void QcCassSolver::AddVar(QcFloat &v) +{ + if (IsRegistered(v)) + return; + + QcDelLinInEqSystem::AddVar(v); + QcFloat dvp("", 0.0, v.StayWeight(), v.EditWeight(), true); + QcFloat dvm("", 0.0, v.StayWeight(), v.EditWeight(), true); + fVBiMap.Update(dvp, fTableau.AddError()); + fVBiMap.Update(dvm, fTableau.AddError()); + + QcConstraint stay = ((-1 * v) + (1 * dvp) + (-1 * dvm) + == -v.DesireValue()); + dbg(bool consistent_stay_constraint =) + QcDelLinInEqSystem::AddConstraint( stay); + assert( consistent_stay_constraint); + + QcCassConstraint *cass = new QcCassConstraint( v, stay, dvp, dvm); + fStayMap[v] = cass; + fStaySeqMap.push_back( cass); + + qcAssertExternalPost( IsRegistered( v)); +} + +void QcCassSolver::BeginAddConstraint() +{ + throw QcWarning("Warning: QcCassSolver::BeginAddConstraint() not implemented yet"); +} + +void QcCassSolver::BeginEdit() +{ + if (!fEditVarsSetup) { + if (fTableau.getNRestrictedRows() != 0) { + InitObjective(); + SimplexII(); + } + fEditVarsSetup = true; + } +} + +bool QcCassSolver::EndAddConstraint() +{ + throw QcWarning("Warning: QcCassSolver::EndAddConstraint() not implemented yet"); +} + +bool QcCassSolver::Reset() +{ + cerr << "Warning: QcCassSolver::Reset() not implemented yet\n"; + return false; +} + +void QcCassSolver::EndEdit() +{ + for (TEditMap::iterator eIt = fEditMap.begin(); + eIt != fEditMap.end(); + eIt++) + { + QcCassConstraint *edit = (*eIt); + edit->fDvp.SetToStayWeight(); + edit->fDvm.SetToStayWeight(); + } + fEditMap.clear(); + + // Call RestDesVal on things. + for (TStaySeqMap::iterator sIt = fStaySeqMap.begin(); + sIt != fStaySeqMap.end(); + sIt++) + { + QcCassConstraint *stay = (*sIt); + unsigned rowIx = fOCBiMap.Index( stay->fConstraint); + /* TODO: Do more work on keeping fTableau RHS in sync with user variable + goal value. Then we can make ChangeRHS conditional on the return value + of RestDesVal. + + Also makes for better behaviour when user does suggestValue on a + non-edit-variable. */ + stay->fVariable.RestDesVal(); + fTableau.ChangeRHS( rowIx, + -stay->fVariable.DesireValue()); + } + + fEditVarsSetup = false; + QcSolver::EndEdit(); +} + +void QcCassSolver::InitObjective() +{ + QcVariableIndexIterator vIt(fTableau); + + while (!vIt.AtEnd()) { + if (fTableau.IsError(vIt.getIndex())) { + QcFloat &v = fVBiMap.Identifier(vIt.getIndex()); + fTableau.SetObjValue(vIt.getIndex(), v.Weight()); + } else + fTableau.SetObjValue(vIt.getIndex(), 0.0); + + vIt.Increment(); + } + + #ifdef qcSafetyChecks + for (unsigned i = 0; i < fTableau.getNColumns(); i++) + if (fTableau.GetObjValue( i) != 0.0) + assert( fTableau.IsError( i)); + #endif + + fTableau.EliminateObjective(); +} + +void QcCassSolver::LoadDesValCache() +{ + QcStructVarIndexIterator vIt (fTableau); + while (!vIt.AtEnd()) + { + unsigned vi = vIt.getIndex(); + if (!fTableau.IsSlack (vi)) + fTableau.SetDesireValue (vi, fVBiMap.Identifier(vi).DesireValue()); + vIt.Increment(); + } +} + +void QcCassSolver::Print(ostream &os) const +{ + QcDelLinInEqSystem::Print(os); + os << "Stay constraints: "; + + TStaySeqMap::const_iterator sIt = fStaySeqMap.begin(); + + while (sIt != fStaySeqMap.end()) { + (*sIt)->Print(os); + os << endl; + sIt++; + } + + os << endl; + os << "Edit constraints: "; + + TEditMap::const_iterator eIt = fEditMap.begin(); + + while (eIt != fEditMap.end()) { + (*eIt)->Print(os); + os << endl; + eIt++; + } + + os << endl; +} + +void QcCassSolver::RawSolve() +{ + LoadDesValCache(); + + for (QcStructVarIndexIterator vIt (fTableau); + !vIt.AtEnd(); + vIt.Increment()) + { + unsigned vi = vIt.getIndex(); + if (fTableau.IsSlack (vi)) + continue; + + QcFloat &v = fVBiMap.Identifier (vi); + if (fTableau.IsBasic (vi)) + { + int ci = fTableau.IsBasicIn (vi); + assert (ci != QcTableau::fInvalidConstraintIndex); + v.SetValue (fTableau.GetRHS (ci)); + } + else + v.SetVariable(); + } +} + +bool QcCassSolver::RemoveVar(QcFloat &v) +{ + TStayMap::iterator sIt = fStayMap.find(v); + + // If the variable to be deleted is not in the solver. + if (sIt == fStayMap.end()) { + throw QcWarning( + "QcCassSolver::RemoveVar - removing an unregistered variable"); + return false; + } + + QcCassConstraint *stay = (*sIt).second; + + // Remove the stay constraint permanently since the associated variables + // is removed. Note that the error variables are not removed here, but + // through the LinInEqTableau class. + QcDelLinInEqSystem::RemoveConstraint(stay->fConstraint); + QcDelLinInEqSystem::RemoveVar(stay->fVariable); + + // Remove the Cassowary constraint from the stay sequential map. + TStaySeqMap::iterator ssIt = fStaySeqMap.begin(); + + while (ssIt != fStaySeqMap.end()) { + if ((*ssIt) == stay) { + fStaySeqMap.erase(ssIt); + break; + } + ssIt++; + } + + // Remove the Cassowary constraint from stay map. + delete stay; + fStayMap.erase(sIt); + + return true; +} + +void QcCassSolver::Resolve() +{ + if (!fEditVarsSetup) + BeginEdit(); + + TEditMap::iterator eIt = fEditMap.begin(); + + while (eIt != fEditMap.end()) { + QcCassConstraint *edit = (*eIt); + fTableau.ChangeRHS(fOCBiMap.Index(edit->fConstraint), + -edit->fVariable.DesireValue()); + eIt++; + } + + DualSimplexII(); + RawSolve(); + +#if qcCheckPost + checkSatisfied(); +#endif +} + +void QcCassSolver::Solve() +{ + InitObjective(); + SimplexII(); + RawSolve(); + + TStaySeqMap::iterator sIt = fStaySeqMap.begin(); + + while (sIt != fStaySeqMap.end()) { + QcCassConstraint *stay = (*sIt); + fTableau.ChangeRHS(fOCBiMap.Index(stay->fConstraint), + -stay->fVariable.Value()); + sIt++; + } + +#if qcCheckPost + checkSatisfied(); +#endif +} + +void QcCassSolver::Restart() +{ + QcDelLinInEqSystem::Restart(); + fStayMap.clear(); + fStaySeqMap.clear(); + fEditMap.clear(); +} + + diff --git a/src/kits/interface/qoca/QcCassSolver.hh b/src/kits/interface/qoca/QcCassSolver.hh new file mode 100644 index 0000000000..37bb7ce498 --- /dev/null +++ b/src/kits/interface/qoca/QcCassSolver.hh @@ -0,0 +1,131 @@ +// $Id: QcCassSolver.hh,v 1.8 2001/01/04 05:20:11 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcCassSolverH +#define __QcCassSolverH + +#include +#include "qoca/QcDelLinInEqSystem.hh" +#include "qoca/QcCassConstraint.hh" + +class QcCassSolver : public QcDelLinInEqSystem +{ +protected: + typedef map TStayMap; + typedef vector TEditMap; + typedef vector TStaySeqMap; + + TStayMap fStayMap; + TEditMap fEditMap; + TStaySeqMap fStaySeqMap; + // Corresponding data structure to fStayMap. This is used to speed + // things up when there is a need to iterate through all the stay + // constraints. Should not use fStayMap for iteration is not very + // efficient. + +public: + //-----------------------------------------------------------------------// + // Constructors. // + //-----------------------------------------------------------------------// + QcCassSolver(); + QcCassSolver(unsigned hintNumConstraints, unsigned hintNumVariables); + virtual ~QcCassSolver(); + + //-----------------------------------------------------------------------// + // Variable management methods // + //-----------------------------------------------------------------------// + virtual void AddVar(QcFloat &v); + virtual bool RemoveVar(QcFloat &v); + + //-----------------------------------------------------------------------// + // Constraint management methods // + //-----------------------------------------------------------------------// + virtual bool AddConstraint(QcConstraint &c); + virtual bool AddConstraint(QcConstraint &c, QcFloat &hint); + virtual void BeginAddConstraint(); + virtual bool EndAddConstraint(); + virtual bool ChangeConstraint(QcConstraint &oldc, numT rhs); + virtual void InitObjective(); + virtual bool RemoveConstraint(QcConstraint &c); + virtual bool Reset(); + + //-----------------------------------------------------------------------// + // High Level Edit Variable Interface for use by solver clients. // + //-----------------------------------------------------------------------// + virtual void AddEditVar(QcFloat &v); + virtual void EndEdit(); + virtual void BeginEdit(); + + //-----------------------------------------------------------------------// + // Constraint Solving methods // + //-----------------------------------------------------------------------// + virtual void Solve(); + virtual void Resolve(); + + void LoadDesValCache(); + void RawSolve(); + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Restart(); + virtual void Print(ostream &os) const; +}; + +inline QcCassSolver::QcCassSolver() + : QcDelLinInEqSystem() +{ +} + +inline QcCassSolver::QcCassSolver(unsigned hintNumConstraints, unsigned hintNumVariables) + : QcDelLinInEqSystem(hintNumConstraints, hintNumVariables) +{ +} + +inline bool QcCassSolver::ChangeConstraint(QcConstraint &oldc, numT rhs) +{ + bool success = QcDelLinInEqSystem::ChangeConstraint(oldc, rhs); +#if qcCheckPost + if (success) + changeCheckedConstraint( oldc.pointer(), rhs); +#endif + return success; +} + +inline bool QcCassSolver::RemoveConstraint(QcConstraint &c) +{ + bool success = QcDelLinInEqSystem::RemoveConstraint(c); + if (success) { +#if qcCheckPost + removeCheckedConstraint( c.pointer()); +#endif + if (fAutoSolve) + Solve(); + } + return success; +} + +#endif /* !__QcCassSolverH */ diff --git a/src/kits/interface/qoca/QcCompPivotSystem.cc b/src/kits/interface/qoca/QcCompPivotSystem.cc new file mode 100644 index 0000000000..5fc8d4818b --- /dev/null +++ b/src/kits/interface/qoca/QcCompPivotSystem.cc @@ -0,0 +1,335 @@ +// $Id: QcCompPivotSystem.cc,v 1.11 2001/01/31 04:53:11 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcCompPivotSystem.hh" +#include "qoca/QcStructVarIndexIterator.hh" +#include "qoca/QcTableauColIterator.hh" +#include "qoca/QcTableauRowIterator.hh" + +bool QcCompPivotSystem::ApplyHints(int cs) +{ + bool pivoted = false; + + if (cs < 0 || cs >= fTableau.GetRows() || fTableau.IsRedundant(cs)) + throw QcWarning("ApplyHints called for invalid constraint", + cs, fTableau.GetRows() - 1); + else { + for (unsigned int i = 0; i < fTableau.fPivotHints.size() && !pivoted; + i++) { + int hint = fTableau.fPivotHints[i]; + if (!fTableau.IsConstrained(hint)) + pivoted = fTableau.Pivot(cs, hint); + } + } + + return pivoted; +} + +bool QcCompPivotSystem::CopyConstraint(QcConstraint &c, int bvi) +{ + int ci = AddToTableau(c); + + if (ci == QcTableau::fInvalidConstraintIndex) + return false; + else { + fOCBiMap.Update(c, ci); + fTableau.SetRowState(bvi, ci, QcLinEqRowState::fRegular); + } + + return true; +} + +bool QcCompPivotSystem::CopyInEq(QcConstraint &c) +{ + int ci = AddToTableau(c); + + if (ci == QcTableau::fInvalidConstraintIndex) + return false; + else { + fOCBiMap.Update(c, ci); + fTableau.SetRowState(fTableau.GetColumns() - 1, ci, + QcLinEqRowState::fRegular); + } + + fEditVarsSetup = false; + return true; +} + +void QcCompPivotSystem::EqRawSolve() +{ +#ifdef qcSafetyChecks + if (!fTableau.IsBasicFeasibleSolved()) + throw QcWarning(qcPlace, + "Tableau is not in basic feasible solved form"); +#endif + + QcStructVarIndexIterator vIt(fTableau); + while (!vIt.AtEnd()) + { + unsigned vi = vIt.getIndex(); + int ci = fTableau.IsBasicIn (vi); + if ((ci >= fTableau.GetBeginEq()) + && (ci != QcTableau::fInvalidConstraintIndex)) + { + numT value = EvalBasicVar (vi); + QcFloat &v = fVBiMap.Identifier (vi); + v.SetValue (QcUtility::Zeroise (value)); + } + vIt.Increment(); + } +} + +void QcCompPivotSystem::EqRawSolveComplex() +{ +#ifdef qcSafetyChecks + if (!fTableau.IsBasicFeasibleSolved()) + throw QcWarning(qcPlace, + "Tableau is not in basic feasible solved form"); +#endif + + QcStructVarIndexIterator vIt (fTableau); + while (!vIt.AtEnd()) + { + unsigned vi = vIt.getIndex(); + int ci = fTableau.IsBasicIn (vi); + if ((ci >= fTableau.GetBeginEq()) + && (ci != QcTableau::fInvalidConstraintIndex)) + { + numT value = EvalBasicVarComplex (vi); + QcFloat v = fVBiMap.Identifier (vi); + v.SetValue (QcUtility::Zeroise (value)); + } + vIt.Increment(); + } +} + +numT +QcCompPivotSystem::EvalBasicVar(unsigned vi) +{ + qcAssertPre( IsBasic( fVBiMap.Identifier( vi))); + + int ci = fTableau.IsBasicIn( vi); + assert( ci != QcTableau::fInvalidConstraintIndex); + numT value = fTableau.GetRHS(ci); // rhs sign is not critical here + + for (QcTableauRowIterator varCoeffs( fTableau, ci); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + unsigned coeff_vi = varCoeffs.getIndex(); + if ((coeff_vi != vi) + && (fTableau.IsStructural( coeff_vi))) + { + QcFloatRep *vr = fVBiMap.getIdentifierPtr( coeff_vi); + value -= varCoeffs.getValue() * vr->Value(); + } + } + + return value; +} + +numT QcCompPivotSystem::EvalBasicVarComplex(unsigned vi) +{ + qcAssertPre( IsBasic( fVBiMap.Identifier( vi))); + + int ci = fTableau.IsBasicIn( vi); + assert( ci != QcTableau::fInvalidConstraintIndex); + + numT value = fTableau.GetComplexRHS( ci); // rhs sign is not critical here + + for (QcTableauRowIterator varCoeffs( fTableau, ci); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + unsigned coeff_vi = varCoeffs.getIndex(); + if ((coeff_vi != vi) + && (fTableau.IsStructural( coeff_vi))) + { + QcFloatRep *vr = fVBiMap.getIdentifierPtr( coeff_vi); + value -= varCoeffs.GetValue() * vr->Value(); + } + } + + return value; +} + +void QcCompPivotSystem::InEqRawSolve() +{ +#ifdef qcSafetyChecks + if (!fTableau.IsBasicFeasibleSolved()) + throw QcWarning(qcPlace, + "Tableau is not in basic feasible solved form"); +#endif + + QcStructVarIndexIterator vIt (fTableau); + while (!vIt.AtEnd()) + { + unsigned vi = vIt.getIndex(); + int ci = fTableau.IsBasicIn (vi); + + /* TODO: What happens if GetBeginEq < 0? + Should `!= fInvalidConstraintIndex' be tested first? */ + if (ci < fTableau.GetBeginEq()) + { + QcFloat &v = fVBiMap.Identifier (vi); + + if (ci != QcTableau::fInvalidConstraintIndex) + { + numT value = fTableau.GetRHS (ci); + v.SetValue (QcUtility::Zeroise (value)); + } + else + v.SetVariable(); + } + vIt.Increment(); + } +} + +void QcCompPivotSystem::InEqRawSolveComplex() +{ +#ifdef qcSafetyChecks + if (!fTableau.IsBasicFeasibleSolved()) + throw QcWarning(qcPlace, + "Tableau is not in basic feasible solved form"); +#endif + + QcStructVarIndexIterator vIt (fTableau); + while (!vIt.AtEnd()) + { + unsigned vi = vIt.getIndex(); + int ci = fTableau.IsBasicIn (vi); + + if (ci < fTableau.GetBeginEq()) + { + QcFloat &v = fVBiMap.Identifier (vi); + + if (ci != QcTableau::fInvalidConstraintIndex) + { + numT value = fTableau.GetComplexRHS (ci); + v.SetValue (QcUtility::Zeroise (value)); + } + else + v.SetVariable(); + } + vIt.Increment(); + } +} + +int QcCompPivotSystem::SelectExitVar (unsigned vi) +{ + qcAssertPre( vi < fTableau.getNColumns()); + + int ei = QcTableau::fInvalidConstraintIndex; + numT minval = DBL_MAX; + int bi = fTableau.GetColumns(); // Bland Index + +#ifdef qcSafetyChecks + qcAssert(!fTableau.IsBasic(vi) && fTableau.IsConstrained(vi)); +#endif + + for (QcTableauColIterator colCoeffs( fTableau, vi); + !colCoeffs.AtEnd(); + colCoeffs.Increment()) + if(colCoeffs.GetIndex() < fTableau.GetBeginEq()) + { + qcAssert( fTableau.GetBasicVar( colCoeffs.GetIndex()) != (int) vi); + if (fTableau.IsRestricted( colCoeffs.GetIndex())) + { + numT rhs = fTableau.GetRHS( colCoeffs.GetIndex()); + if (CannotIncrease( colCoeffs.GetValue(), rhs)) + { + numT coeff = rhs / colCoeffs.GetValue(); + if ((coeff < minval) + || ((coeff == minval) + && (fTableau.GetBasicVar(colCoeffs.GetIndex()) < bi))) + { + minval = coeff; + ei = colCoeffs.GetIndex(); + bi = fTableau.GetBasicVar( ei); + qcAssert( !QcUtility::IsNegative( minval)); + } + } + } + } + +#ifdef qcSafetyChecks + qcAssert( fTableau.IsBasicFeasibleSolved()); + if (ei < 0) + throw QcWarning("SelectExitVar: No suitable variable"); +#endif + + return ei; +} + + +int QcCompPivotSystem::SelectExitVarComplex (int vi) +{ + int ei = QcTableau::fInvalidConstraintIndex; + numT minval = DBL_MAX; + int bi = fTableau.GetColumns(); // Bland Index + +#ifdef qcSafetyChecks + qcAssert(!fTableau.IsBasic(vi) && fTableau.IsConstrained(vi)); +#endif + + for (QcTableauColIterator colCoeffs( fTableau, vi); + !colCoeffs.AtEnd(); + colCoeffs.Increment()) + if(colCoeffs.GetIndex() < fTableau.GetBeginEq()) + { + unsigned const coeff_ix = colCoeffs.getIndex(); + qcAssert (fTableau.GetBasicVar (coeff_ix) != vi); + if (fTableau.IsRestricted (coeff_ix)) + { + numT rhs = fTableau.GetComplexRHS (coeff_ix); + if (CannotIncrease (colCoeffs.getValue(), rhs)) + { + numT coeff = rhs / colCoeffs.getValue(); + if ((coeff < minval) + || ((coeff == minval) + && (fTableau.GetBasicVar (coeff_ix) + < bi))) + { + minval = coeff; + ei = coeff_ix; + bi = fTableau.GetBasicVar (ei); + qcAssert (!QcUtility::IsNegative (minval)); + } + } + } + } + +#ifdef qcSafetyChecks + /* fixme: the following assertion can fail (in the test suite), with fTableau + solved but not basic feasible. */ + qcAssert (fTableau.IsBasicFeasibleSolved()); + if (ei < 0) + throw QcWarning("SelectExitVar: No suitable variable"); +#endif + + return ei; +} diff --git a/src/kits/interface/qoca/QcCompPivotSystem.hh b/src/kits/interface/qoca/QcCompPivotSystem.hh new file mode 100644 index 0000000000..f3bcffe8c1 --- /dev/null +++ b/src/kits/interface/qoca/QcCompPivotSystem.hh @@ -0,0 +1,98 @@ +// $Id: QcCompPivotSystem.hh,v 1.7 2000/12/12 01:29:00 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcCompPivotSystemH +#define __QcCompPivotSystemH + +#include "qoca/QcLinInEqSystem.hh" +#include "qoca/QcCompPivotTableau.hh" + +class QcCompPivotSystem : public QcLinInEqSystem +{ +protected: + QcCompPivotTableau &fTableau; + +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcCompPivotSystem(); + QcCompPivotSystem(int hintRows, int hintCols); + QcCompPivotSystem(QcCompPivotTableau &tab); + + //-----------------------------------------------------------------------// + // Variable management methods // + //-----------------------------------------------------------------------// + void AddSlack(QcFloat &v) + { fVBiMap.Update(v, fTableau.AddSlack()); } + + //-----------------------------------------------------------------------// + // Constraint management methods // + //-----------------------------------------------------------------------// + virtual bool ApplyHints(int cs); + // This is a convenience function to pivot an independent new + // solved form constraint according to the PivotHints. + virtual bool CopyInEq(QcConstraint &c); + virtual bool CopyConstraint(QcConstraint &c, int bvi); + // Extracts the various components and enters them in the sub-tableau + // as well as updating the bimapnotifier for the sub-tableau + // if successful. + virtual void EqRawSolve(); + virtual void EqRawSolveComplex(); + numT EvalBasicVar(unsigned vi); + numT EvalBasicVarComplex(unsigned vi); + virtual void InEqRawSolve(); + virtual void InEqRawSolveComplex(); + + virtual int SelectExitVar (unsigned vi); + // see superclass for doc + + virtual int SelectExitVarComplex(int vi); + // Select the pivot row for pivot variable vi (slack parameter) + // maintaining Basic Feasible Solved Form. + // Returns fInvalidConstraintIndex if no such pivot is possible. + // This version implement's Bland's anticycling rule. +}; + +inline QcCompPivotSystem::QcCompPivotSystem() + : QcLinInEqSystem(*new QcCompPivotTableau(0, 0, fNotifier)), + fTableau((QcCompPivotTableau &)QcLinInEqSystem::fTableau) +{ +} + +inline QcCompPivotSystem::QcCompPivotSystem(int hintRows, int hintCols) + : QcLinInEqSystem(*new QcCompPivotTableau(hintRows, hintCols, fNotifier)), + fTableau((QcCompPivotTableau &)QcLinInEqSystem::fTableau) +{ +} + +inline QcCompPivotSystem::QcCompPivotSystem(QcCompPivotTableau &tab) + : QcLinInEqSystem(tab), + fTableau(tab) +{ +} + +#endif diff --git a/src/kits/interface/qoca/QcCompPivotTableau.cc b/src/kits/interface/qoca/QcCompPivotTableau.cc new file mode 100644 index 0000000000..f31d094a5d --- /dev/null +++ b/src/kits/interface/qoca/QcCompPivotTableau.cc @@ -0,0 +1,239 @@ +// $Id: QcCompPivotTableau.cc,v 1.12 2001/01/31 07:37:13 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcCompPivotTableau.hh" +#include "qoca/QcConstraintIndexIterator.hh" +#include "qoca/QcTableauColIterator.hh" +#include "qoca/QcDenseTableauColIterator.hh" + +int QcCompPivotTableau::AddArtificial(numT coeff) +{ + int vi = IncreaseColumns(); + SetColCondition(vi, QcLinInEqColState::fArtificial); + SetConstrained(vi, true); + + QcConstraintIndexIterator cIt(*this); + + while (!cIt.AtEnd()) { + fCoreTableau->fSF.SetValue (cIt.getIndex(), vi, coeff); + cIt.Increment(); + } + + fAI = vi; + return vi; +} + +int QcCompPivotTableau::AddDesValVar(void) +{ + int vi = IncreaseColumns(); + SetColCondition(vi, QcLinInEqColState::fDesire); + SetConstrained(vi, false); + return vi; +} + +numT QcCompPivotTableau::GetComplexRHS(int ci) const +{ + numT crhs = QcLinInEqTableau::GetRHS(ci); + + for (unsigned vi = 0; (int) vi < GetColumns(); vi++) { + if (IsDesire(vi)) + crhs -= GetValue(ci, vi) * GetDesireValue(vi); + } + + return QcUtility::Zeroise(crhs); +} + +void QcCompPivotTableau::Print(ostream &os) const +{ + QcLinInEqTableau::Print(os); + os << "Complex RHS:" << endl; + int rows = GetRows(); + + for (int i = 0; i < rows; i++) + os << "CRHS[" << i << "] = " << GetComplexRHS(i) << endl; + + os << "Begin Eq: " << fBeginEq << endl; +} + +void QcCompPivotTableau::Restart(void) +{ + QcLinInEqTableau::Restart(); + fAI = QcTableau::fInvalidVariableIndex; + fBeginEq = QcTableau::fInvalidConstraintIndex; +} + +bool QcCompPivotTableau::RestrictedPivot(unsigned ci, unsigned vi) +{ + qcAssertPre( ci < getNRows()); + qcAssertPre( vi < getNColumns()); + qcAssertPre( !fCoreTableau->GetMRowDeleted( ci)); + qcAssertPre( !IsRedundant( ci)); + qcAssertPre( GetRowCondition( ci) != QcLinEqRowState::fInvalid); + + numT p = GetValue( ci, vi); // GetValue returns the raw coefficient + + if (QcUtility::IsZero( p)) // so this test is required. + return false; + + // If ci is regular then remove it from the basis. + if (GetRowCondition( ci) == QcLinEqRowState::fRegular) + Unsolve(ci); + // Note that fARowIndex[ci] can be left as qcInvalidCIndex, + // hence check below. + + // From this point, until the pivot is completed, + // the conditions MRowIndex(fARowIndex(ci))==ci and + // ARowIndex(MRowIndex(ci2))==ci2 may not hold. Since it is + // Pivot that causes a row to become regular, and these conditions + // do not hold for regular rows, this is a consequence of the + // change of state. We could introduce another row state for this + // phase, but that seems a bit over the top. Just check that all + // tableau methods that Pivot calls from here on do not assume the + // conditions. I.E. don't call: DecreaseRows, Eliminate, RemoveEq, + // CompactRows, Restore, or AddRow. And of course if IsSolved is + // called with checks enabled it may report an assert violation. + + // From this point the pivot must succeed. + // So can now wipe fARowIndex and fMRowIndex + if (GetARowIndex(ci) != QcTableau::fInvalidConstraintIndex) + { + SetMRowIndex( GetARowIndex( ci), QcTableau::fInvalidConstraintIndex); + SetARowIndex( ci, QcTableau::fInvalidConstraintIndex); + } + + #ifdef qcSafetyChecks + qcAssert(GetARowIndex(ci) == QcTableau::fInvalidConstraintIndex); + qcAssert(GetRowCondition(ci) == QcLinEqRowState::fNormalised); + qcAssert(GetBasicVar(ci) == QcTableau::fInvalidVariableIndex); + qcAssert(IsBasicIn(vi) == QcTableau::fInvalidConstraintIndex); + #endif + + // Scale the pivot row so pivot coeff is 1.0 + fCoreTableau->fSF.ScaleRow( ci, recip( p)); + // FractionRow may be used here rather than ScaleRow(ci,recip(p)) + // so that we don't introduce rounding errors at the cost of + // efficiency (FractionRow uses division so is less efficient). + +#ifdef qcUseSafeIterator + // Eliminate the new basic variable from all the other rows. + for (QcDenseTableauColIterator varCoeffs( *this, vi); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + /* Process only regular rows. Redundant and deleted rows would not + be affected in any case. Undetermined rows are not in solved + form so should not be included. By checking here we can allow + rows to be added without requiring an immediate pivot and also + enable a full resolve by setting all the rows to normalised and + fM to identity. */ + if (varCoeffs.GetIndex() >= fBeginEq) + break; + + if ((GetRowCondition( varCoeffs.getIndex()) == QcLinEqRowState::fRegular) + || ((GetRowCondition( varCoeffs.getIndex()) == QcLinEqRowState::fNormalised) + && (varCoeffs.getIndex() != ci))) + { + // Excludes (varCoeffs.fIndex == ci) since + // (GetRowCondition(ci) != QcLinEqRowState::fRegular). + fCoreTableau->fSF.AddScaledRow( varCoeffs.getIndex(), ci, + -varCoeffs.getValue()); + } + + } +#else /* !qcUseSafeIterator */ + // Eliminate the new basic variable from all the other rows. + { + vector coeffCache; + + for(QcTableauColIterator varCoeffs( *this, vi); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + unsigned coeff_ix = varCoeffs.getIndex(); + + /* Process only regular rows. Redundant and deleted rows would + not be affected in any case. Undetermined rows are not + in solved form so should not be included. By checking here + we can allow rows to be added without requiring an + immediate pivot and also enable a full resolve by + setting all the rows to normalised and fM to identity. */ + if((int( coeff_ix) < fBeginEq) + && (GetRowCondition( coeff_ix) == QcLinEqRowState::fRegular + || (GetRowCondition( coeff_ix) == QcLinEqRowState::fNormalised + && (coeff_ix != ci)))) + /* Excludes (coeff_ix == ci) since + * (GetRowCondition(ci) != QcLinEqRowState::fRegular). + */ + coeffCache.push_back( QcSparseCoeff( varCoeffs.getValue(), + coeff_ix)); + } + + for (vector::iterator cIt = coeffCache.begin(); + cIt != coeffCache.end(); + cIt++) + { + QcSparseCoeff &coeff = (*cIt); + unsigned const coeff_ix = coeff.getIndex(); + + fCoreTableau->fSF.AddScaledRow( coeff_ix, ci, + -coeff.getValue()); + } + } +#endif + + SetBasic(vi, true); + SetBasicIn(vi, ci); + SetBasicVar(ci, vi); + SetRowCondition(ci, QcLinEqRowState::fRegular); + + return true; +} + +void QcCompPivotTableau::SetArtificial(numT coeff) +{ + QcConstraintIndexIterator cIt(*this); + + while (!cIt.AtEnd()) { + fCoreTableau->fSF.SetValue (cIt.getIndex(), fAI, coeff); + cIt.Increment(); + } +} + +void QcCompPivotTableau::SetRowState(int bvi, int ci, int rs) +{ + // Need to reverse the sign of all the row coefficients if the coefficients + // for the variable to make basic is -1.0. + if (QcUtility::IsNegative(GetValue(ci, bvi))) + fCoreTableau->fSF.NegateRow( ci); + + SetBasic(bvi, true); + SetBasicIn(bvi, ci); + SetBasicVar(ci, bvi); + SetRowCondition(ci, rs); +} + + diff --git a/src/kits/interface/qoca/QcCompPivotTableau.hh b/src/kits/interface/qoca/QcCompPivotTableau.hh new file mode 100644 index 0000000000..9bbdeef1d5 --- /dev/null +++ b/src/kits/interface/qoca/QcCompPivotTableau.hh @@ -0,0 +1,108 @@ +// $Id: QcCompPivotTableau.hh,v 1.7 2000/12/15 01:20:05 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcCompPivotTableauH +#define __QcCompPivotTableauH + +#include "qoca/QcLinInEqTableau.hh" + +class QcCompPivotTableau : public QcLinInEqTableau +{ +protected: + int fAI; + int fBeginEq; + + //------------------------------------------------------------------------// + // Constructor. // + //------------------------------------------------------------------------// +public: + QcCompPivotTableau(int hintRows, int hintCols, QcBiMapNotifier &n); + + //------------------------------------------------------------------------// + // Query functions. // + //------------------------------------------------------------------------// + + /** @postcondition (ret == fInvalidConstraintIndex) + || ((unsigned) retgetNRows()) + **/ + int GetBeginEq() const + { + qcAssertPost ((fBeginEq == fInvalidConstraintIndex) + || ((unsigned) fBeginEq <= getNRows())); + return fBeginEq; + } + + numT GetComplexRHS(int ci) const; + + //------------------------------------------------------------------------// + // Manipulation functions. // + //------------------------------------------------------------------------// + virtual int AddArtificial(numT coeff); + virtual int AddDesValVar(); + virtual void Restart(); + // Erase everything ready to start afresh. + + /** The parameters indicate a solved form coeff. Pivot can only be applied to + a normalised or regular constraint. + +

getValue(ci, vi) is allowed to be zero, in which case does + nothing and returns false. + +

This pivot function only work on restricted rows which ends on + fBeginEq. + + @precondition ci < getNRows() + @precondition vi < getNColumns() + @precondition !IsRedundant(ci) + **/ + bool RestrictedPivot(unsigned ci, unsigned vi); + + /** In each constraint, set the coefficient of the artificial variable to + coeff. */ + void SetArtificial(numT coeff); + + void SetBeginEq() + { fBeginEq = GetRows(); } + + void SetRowState(int bvi, int ci, int rs); + + //------------------------------------------------------------------------// + // Utility functions. // + //------------------------------------------------------------------------// + virtual void Print(ostream &os) const; +}; + +inline QcCompPivotTableau::QcCompPivotTableau(int hintRows, int hintCols, + QcBiMapNotifier &n) + : QcLinInEqTableau(*new QcCoreTableau(hintRows, hintCols, + *new QcLinInEqRowColStateVector()), + n), + fAI(fInvalidVariableIndex), + fBeginEq(fInvalidConstraintIndex) +{ +} + +#endif diff --git a/src/kits/interface/qoca/QcConstraint.hh b/src/kits/interface/qoca/QcConstraint.hh new file mode 100644 index 0000000000..ebdca97810 --- /dev/null +++ b/src/kits/interface/qoca/QcConstraint.hh @@ -0,0 +1,322 @@ +// $Id: QcConstraint.hh,v 1.11 2001/01/10 05:01:33 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcConstriantH +#define __QcConstriantH + +#include "qoca/QcDefines.hh" +#include "qoca/QcConstraintRep.hh" +#include "qoca/QcLinPoly.hh" + +/** This class provides the only mechanism to create constraints and the + constructors and the constructors return a handle. See + QcNullableElement for comments on assignment semantics etc. +**/ +class QcConstraint +{ +public: + friend class QcNullableElement; + + //-----------------------------------------------------------------------// + // Constructors // + //-----------------------------------------------------------------------// + QcConstraint(QcConstraintRep &r); + QcConstraint(QcConstraintRep *p); + QcConstraint(); + QcConstraint(const char *name); + QcConstraint(const char *name, const QcLinPoly &p); + QcConstraint(const char *name, const QcLinPoly &p, QcConstraintRep::TOp op); + QcConstraint(const char *name, const QcLinPoly &p, QcConstraintRep::TOp op, + numT rhs); + QcConstraint(QcConstraint const &other); + QcConstraint(QcNullableElement const &other); + + ~QcConstraint() + { Decrease(); } + + void assertInvar() const + { + qcAssertInvar(fRep != NULL); + fRep->assertInvar(); + } + + //-----------------------------------------------------------------------// + // Data structure access functions // + //-----------------------------------------------------------------------// + QcConstraintRep const *pointer() const + { return fRep; } + + QcConstraintRep *pointer() + { return fRep; } + +#if 0 + const QcConstraintRep &Rep() const + { return *fRep; } +#endif + + //-----------------------------------------------------------------------// + // Query functions // + //-----------------------------------------------------------------------// + long Counter() const + { return fRep->Counter(); } + + const char *Name() const + { return fRep->Name(); } + + QcConstraintRep::TId Id() const + { return fRep->Id(); } + + const QcLinPoly& LinPoly() const + { return fRep->LinPoly(); } + + QcConstraintRep::TOp Operator() const + { return fRep->Operator(); } + + QcConstraintRep::TOp getRelation() const + { return fRep->Operator(); } + + numT RHS() const + { return fRep->RHS(); } + + numT getRHS() const + { return fRep->RHS(); } + + bool hasVar (QcFloatRep const *v) const + { return fRep->LinPoly().hasVar (v); } + + unsigned getNVars() const + { return fRep->LinPoly().getNTerms(); } + + QcFloat const &getVar (unsigned i) const + { return fRep->LinPoly().GetTerm (i).GetVariable(); } + + int getVarId (unsigned i) const + { return getVar(i).Id(); } + + bool operator <(const QcConstraint &other) const + { return *fRep < *other.fRep; } + + bool operator ==(const QcConstraint &other) const + { return (fRep == other.fRep); } + + bool operator !=(const QcConstraint &other) const + { return (fRep != other.fRep); } + + //-----------------------------------------------------------------------// + // Set and Get member functions // + //-----------------------------------------------------------------------// + void SetLinPoly(QcLinPoly &p) + { fRep->SetLinPoly(p); } + + void SetRHS(numT rhs) + { fRep->SetRHS(rhs); } + + void SetOperator(QcConstraintRep::TOp op) + { fRep->SetOperator(op); } + + void SetName(char const * const n) + { fRep->SetName(n); } + + void makeEq(QcLinPoly *p, numT rhs) + { + fRep->SetLinPoly(*p); + fRep->SetOperator(QcConstraintRep::coEQ); + fRep->SetRHS(rhs); + } + + void makeLe(QcLinPoly *p, numT rhs) + { + fRep->SetLinPoly(*p); + fRep->SetOperator(QcConstraintRep::coLE); + fRep->SetRHS(rhs); + } + + void makeGe(QcLinPoly *p, numT rhs) + { + fRep->SetLinPoly(*p); + fRep->SetOperator(QcConstraintRep::coGE); + fRep->SetRHS(rhs); + } + + void Decrease(); + // Called when number of references decreases. + + bool FreeName() + // Deallocates old name string. + { return fRep->FreeName(); } + + void Increase() const + // Call when number of references increases. + { fRep->Increase(); } + + QcConstraint &operator=(const QcConstraint &other); + // N.B. checked self assignment, x = x ok + + /** Returns true iff this constraint is satisfied or + QcUtility.isZero(LHS - RHS). The current implementation + ignores the possibility of NaN or infinity problems. */ + bool isSatisfied() const + { return fRep->isSatisfied(); } + + //------------------------------------------------------------------------// + // Utility functions // + //------------------------------------------------------------------------// + void Print(ostream &os) const + { fRep->Print(os); } + + bool isDead() const + { return fRep == 0; } + +protected: + QcConstraintRep *fRep; +}; + +inline QcConstraint::QcConstraint(QcConstraintRep &r) + : fRep(&r) +{ +} + +inline QcConstraint::QcConstraint (QcConstraintRep *p) + : fRep (p) +{ +} + +inline QcConstraint::QcConstraint() + : fRep(new QcConstraintRep()) +{ +} + +inline QcConstraint::QcConstraint(const char *name) + : fRep(new QcConstraintRep(name)) +{ +} + +inline QcConstraint::QcConstraint(const char *name, const QcLinPoly &p) + : fRep(new QcConstraintRep(name, p)) +{ +} +inline QcConstraint::QcConstraint(const char *name, const QcLinPoly &p, + QcConstraintRep::TOp op) + : fRep(new QcConstraintRep(name, p, op)) +{ +} + +inline QcConstraint::QcConstraint(const char *name, const QcLinPoly &p, + QcConstraintRep::TOp op, numT rhs) + : fRep(new QcConstraintRep(name, p, op, rhs)) + +{ +} + +inline QcConstraint::QcConstraint(const QcConstraint &other) + : fRep(other.fRep) +{ + Increase(); +} + +inline QcConstraint::QcConstraint(QcNullableElement const &other) + : fRep(other.fRep) +{ + Increase(); +} + +#ifndef qcSafetyChecks +inline void QcConstraint::Decrease() +{ + fRep->Decrease(); + + if (fRep->Counter() == 0) + delete fRep; + fRep = 0; +} +#else +inline void QcConstraint::Decrease() +{ + fRep->Decrease(); + + if (fRep->Counter() < 0) + throw QcWarning( + "QcConstraint::Decrease: invalid count (already free?)"); + else if (fRep->Counter() == 0) { + if (fRep->Magic() == qcConstraintMagic1 && FreeName()) { + delete fRep; + } else + throw QcWarning( + "QcConstraint::Decrease detected constraint corruption"); + } + fRep = 0; +} +#endif + +inline QcConstraint &QcConstraint::operator=(const QcConstraint &other) +{ + other.fRep->Increase(); + Decrease(); + fRep = other.fRep; + return *this; +} + +#ifndef QOCA_NO_FANCY_OPERATORS +inline QcConstraint operator ==(const QcLinPoly &lhs, numT rhs) +{ + return QcConstraint("", lhs, QcConstraintRep::coEQ, rhs); +} + +inline QcConstraint operator <=(const QcLinPoly &lhs, numT rhs) +{ + return QcConstraint("", lhs, QcConstraintRep::coLE, rhs); +} + +inline QcConstraint operator >=(const QcLinPoly &lhs, numT rhs) +{ + return QcConstraint("", lhs, QcConstraintRep::coGE, rhs); +} + +inline QcConstraint operator ==(const QcLinPolyTerm &lhs, numT rhs) +{ + return QcConstraint("", QcLinPoly(lhs), QcConstraintRep::coEQ, rhs); +} + +inline QcConstraint operator <=(const QcLinPolyTerm &lhs, numT rhs) +{ + return QcConstraint("", QcLinPoly(lhs), QcConstraintRep::coLE, rhs); +} + +inline QcConstraint operator >=(const QcLinPolyTerm &lhs, numT rhs) +{ + return QcConstraint("", QcLinPoly(lhs), QcConstraintRep::coGE, rhs); +} +#endif /* QOCA_NO_FANCY_OPERATORS */ + +#ifndef qcNoStream +inline ostream &operator<<(ostream &os, const QcConstraint &c) +{ + c.Print(os); + return os; +} +#endif + +#endif /* !__QcConstriantH */ diff --git a/src/kits/interface/qoca/QcConstraintBiMap.hh b/src/kits/interface/qoca/QcConstraintBiMap.hh new file mode 100644 index 0000000000..c62dfe419b --- /dev/null +++ b/src/kits/interface/qoca/QcConstraintBiMap.hh @@ -0,0 +1,35 @@ +// $Id: QcConstraintBiMap.hh,v 1.4 2000/12/11 07:44:13 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcConstraintBiMapH +#define __QcConstraintBiMapH + +#include "qoca/QcAliasedBiMap.hh" +#include "qoca/QcNullableConstraint.hh" + +typedef QcAliasedBiMap QcConstraintBiMap; + +#endif /* !__QcConstraintBiMapH */ diff --git a/src/kits/interface/qoca/QcConstraintIndexIterator.hh b/src/kits/interface/qoca/QcConstraintIndexIterator.hh new file mode 100644 index 0000000000..8bb1201498 --- /dev/null +++ b/src/kits/interface/qoca/QcConstraintIndexIterator.hh @@ -0,0 +1,76 @@ +// $Id: QcConstraintIndexIterator.hh,v 1.5 2000/11/29 01:58:42 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcConstraintIndexIteratorH +#define __QcConstraintIndexIteratorH + +class QcConstraintIndexIterator +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcConstraintIndexIterator (const QcLinEqTableau &tab); + + + bool AtEnd() const + { return (fCurrent == 0); } + + unsigned getIndex() const + { + qcAssertPre (!AtEnd()); + unsigned ret = fCurrent->fIndex; + qcAssertPost ((int) ret >= 0); + return ret; + } + + void Increment(); + void Reset(); + +private: + QcQuasiRowStateVector const &fRowState; + QcQuasiRowState const *fCurrent; +}; + +inline +QcConstraintIndexIterator::QcConstraintIndexIterator (const QcLinEqTableau &tab) + : fRowState(tab.GetRowState()) +{ + Reset(); +} + +inline void QcConstraintIndexIterator::Increment() +{ + qcAssertPre (!AtEnd()); + fCurrent = fCurrent->getNextUndeletedRow(); +} + +inline void QcConstraintIndexIterator::Reset() +{ + fCurrent = fRowState.fRowList; +} + +#endif diff --git a/src/kits/interface/qoca/QcConstraintRep.cc b/src/kits/interface/qoca/QcConstraintRep.cc new file mode 100644 index 0000000000..649faa9ecc --- /dev/null +++ b/src/kits/interface/qoca/QcConstraintRep.cc @@ -0,0 +1,129 @@ +// $Id: QcConstraintRep.cc,v 1.7 2000/12/06 05:32:56 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcConstraintRep.hh" + +QcConstraintRep::TId QcConstraintRep::fNextValidId = 1; +const QcConstraintRep::TId QcConstraintRep::fInvalidId = 0; + +bool QcConstraintRep::FreeName() +{ + bool ok = true; + + if (fName != 0) { // check for magic4 + char const *magic2 = qcConstraintMagic2; + + for (int i = 0; i < qcConstraintMagic2Len; i++) + ok &= (fName[i] == magic2[i]); + + if (ok) { + delete[] fName; + fName = 0; + } + } + + return ok; +} + +void QcConstraintRep::Initialize(const char *n, const QcLinPoly &lp, TOp op) +{ + fMagic = qcConstraintMagic1; + fLinPoly = lp; + qcAssertExternalPre(VALID_OP(op)); + fOperator = op; + Reset(); + fName = 0; + SetName(n); +} + +#if qcCheckInternalInvar +void QcConstraintRep::assertInvar() const +{ + qcAssertInvar(fMagic == qcConstraintMagic1); + qcAssertInvar(fCounter >= 0); + qcAssertInvar(fId > 0); + fLinPoly.assertInvar(); + qcAssertInvar(VALID_OP(fOperator)); + qcAssertInvar(fName == 0 || memcmp(fName, qcConstraintMagic2, qcConstraintMagic2Len) == 0); +} +#endif + +void QcConstraintRep::Print(ostream &os) const +{ + if (fName != 0) + os << Name(); + + os << "#" << fId + << "(" << fLinPoly << ", "; + + switch (fOperator) { + case coEQ: os << "=="; break; + //case coLT: os << "<"; break; + case coLE: os << "<="; break; + //case coGT: os << ">"; break; + case coGE: os << ">="; break; + } + + os << ", " << fRHS << ")"; +} + +void QcConstraintRep::SetName(const char *n) + // Set name sets the field fRep->Name to point to a heap allocated + // string with a hidden magic number field at the front. + // The magic number is qcConstraintMagic2 without the '\0' terminator. + // N.B. Although is pretty standard, for portability + // we try to avoid using it here as we have no other need for it. +{ + int len = 0; + char const *magic2 = qcConstraintMagic2; + + // find length of source string + while (n[len] != '\0') + len++; + + qcAssertPost(n[len] == '\0'); + #ifdef qcSafetyChecks + if (len > 1000) + throw QcWarning("QcConstraintRep::SetName name over 1000 chars long"); + #endif + + if (!FreeName()) { // Deallocate existing name string + // If FreeName fails, leave old string and allocate a new one + throw QcWarning("QcConstraintRep::SetName: failed to free old name string"); + } + + fName = new char[len + qcConstraintMagic2Len + 1]; + // allocate for magic+string + + for (int i = 0; i < qcConstraintMagic2Len; i++) + fName[i] = magic2[i]; + + for (int i = 0; i <= len; i++) + fName[i + qcConstraintMagic2Len] = n[i]; + + qcAssertPost(fName[len + qcConstraintMagic2Len] == '\0'); +} diff --git a/src/kits/interface/qoca/QcConstraintRep.hh b/src/kits/interface/qoca/QcConstraintRep.hh new file mode 100644 index 0000000000..4898c7ce1f --- /dev/null +++ b/src/kits/interface/qoca/QcConstraintRep.hh @@ -0,0 +1,347 @@ +// $Id: QcConstraintRep.hh,v 1.9 2001/01/04 05:20:11 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcConstriantRepH +#define __QcConstriantRepH + +#include "qoca/QcDefines.hh" +#include "qoca/QcLinPoly.hh" + +#define qcConstraintMagic1 45919 +#define qcConstraintMagic2 "Qoca constraint:" +#define qcConstraintMagic2Len 16 + // The length of qcConstraintMagic2 without the terminal '\0' + +class QcConstraintRep +{ +public: + typedef long TId; + // It is intended that this be signed. Negative values are not + // allocated and are reserved for future (unknown) usage. The value 0 + // is reserved as an invalid identifier. + + enum TOp { + coEQ, // == + coLE, // <= + coGE // >= + }; + enum deprecated_TOp_vals { + coLT = coLE, // < (implemented as <=) + coGT = coGE // > (implemented as >=) + }; + + /** The highest valid operator number. */ + static const int coLastOp = coGE; + +public: + //-----------------------------------------------------------------------// + // Constructors // + //-----------------------------------------------------------------------// + QcConstraintRep(); + QcConstraintRep(const QcLinPoly &lp); + QcConstraintRep(const QcLinPoly &lp, const TOp op); + QcConstraintRep(const QcLinPoly &lp, const TOp op, numT rhs); + QcConstraintRep(const char *name); + QcConstraintRep(const char *name, const QcLinPoly &lp); + QcConstraintRep(const char *name, const QcLinPoly &lp, TOp op); + QcConstraintRep(const char *name, const QcLinPoly &lp, TOp op, numT rhs); + + virtual ~QcConstraintRep() + { delete [] fName; } + + //-----------------------------------------------------------------------// + // Data Structure access functions. // + //-----------------------------------------------------------------------// + const QcLinPoly &LinPoly() const + { return fLinPoly; } + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + long Counter() const + { return fCounter; } + + TId Id() const + { return fId; } + + TOp Operator() const + { return fOperator; } + + TOp getRelation() const + { return fOperator; } + + bool hasVar (QcFloatRep const *v) const + { return LinPoly().hasVar (v); } + + unsigned getNVars() const + { return LinPoly().getNTerms(); } + + QcFloat const &getVar (unsigned i) const + { return LinPoly().GetTerm (i).GetVariable(); } + + QcFloatRep *getVarPtr( unsigned i) + { + return LinPoly().GetTerm( i).getVariable(); + } + +#if 0 + QcFloat &getVar (unsigned i) + { return LinPoly().GetTerm (i).GetVariable(); } +#endif + + int getVarId (unsigned i) const + { return getVar(i).Id(); } + + numT RHS() const + { return fRHS; } + + long Magic() const + { return fMagic; } + + const char *Name() const; + + bool operator<(const QcConstraintRep &other) const + // The comparisons are for when QcConstraintRep is used as an + // identifier and compares instances not structure. + // General pointer inequality comparisons are not reliable + // (see the C++ ARM section 5.9), fId is provided for this. + + /* [pjm:] Another reason for comparing ids rather than pointers is for + weighted constraints, where we generate a new constraint object + with the same id. The ids need to be the same so that + changeRHS,removeConstraint work. See + QcSolver::AddConstraint(QcConstraint c, numT weight) for where + these half-copies are created. */ + { return (fId < other.fId); } + +#if 0 + bool operator==(const QcConstraintRep &other) const + { return (fId == other.fId); } + + bool operator!=(const QcConstraintRep &other) const + { return (fId != other.fId); } +#endif + + void assertInvar() const; + + //-----------------------------------------------------------------------// + // Manipulation functions // + //-----------------------------------------------------------------------// + virtual void SetLinPoly(QcLinPoly &p) + { fLinPoly = p; } + + virtual void SetRHS(numT rhs) + { fRHS = rhs; } + + virtual void SetOperator(TOp op) + { fOperator = op; } + + virtual void SetName(const char *n); + + void Decrease() + // Called when number of references decreases + { + fCounter--; + qcAssertPre(fCounter >= 0); + } + + void Drop() + { + Decrease(); + if (fCounter != 0) + return; + dbg(assertInvar()); + delete this; + } + + bool FreeName(); + // Deallocates old name string checking magic4. + // Returns success indicator. + + void Increase() + // Call when number of references increases + { fCounter++; } + + void Reset(); // Set variables to defaults + + /** Returns true iff this constraint is satisfied or + QcUtility.isZero(LHS - RHS). The current implementation + ignores the possibility of NaN or infinity problems. */ + bool isSatisfied() const; + + //-----------------------------------------------------------------------// + // Utility functions // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; + +protected: + static TId fNextValidId; + static const TId fInvalidId; + // InvalidId is currently set to 0. + // All negative values are reserved for future use. + + void Initialize(const char *n, const QcLinPoly& lp, const TOp op); + // Allocate the representation record, set indicated values, set + // other representation variables to default values and call Reset. + +private: + long fMagic; // To detect corruption. + long fCounter; // Reference count. + TId fId; // Used as index key and for operator <. + QcLinPoly fLinPoly; // The constraint variable coeffs. + TOp fOperator; // The relation. + numT fRHS; // The RHS value. + char *fName; // 0 or a heap allocated string with hidden + // prefix. +}; + +#ifdef QOCA_INTERNALS +# if defined(qcCheckPre) || defined(qcCheckPost) +# define VALID_OP(_op) ((_op) >= 0 && (_op) <= coLastOp) +# endif +#endif + +inline QcConstraintRep::QcConstraintRep() + : fRHS( 0) +{ + Initialize("", QcLinPoly(), coEQ); +} + +inline QcConstraintRep::QcConstraintRep(const QcLinPoly &lp) + : fRHS( 0) +{ + Initialize("", lp, coEQ); +} + +inline QcConstraintRep::QcConstraintRep(const QcLinPoly &lp, TOp op) + : fRHS( 0) +{ + Initialize("", lp, op); +} + +inline QcConstraintRep::QcConstraintRep(const QcLinPoly &lp, TOp op, numT rhs) + : fRHS( rhs) +{ + Initialize("", lp, op); +} + +inline QcConstraintRep::QcConstraintRep(char const *name) + : fRHS( 0) +{ + Initialize(name, QcLinPoly(), coEQ); +} + +inline QcConstraintRep::QcConstraintRep(const char *name, const QcLinPoly &lp) + : fRHS( 0) +{ + Initialize(name, lp, coEQ); +} + +inline QcConstraintRep::QcConstraintRep(char const *name, const QcLinPoly &lp, + TOp op) + : fRHS( 0) +{ + Initialize(name, lp, op); +} + +inline QcConstraintRep::QcConstraintRep(const char *name, const QcLinPoly &lp, + TOp op, numT rhs) + : fRHS( rhs) +{ + Initialize(name, lp, op); +} + + +inline const char *QcConstraintRep::Name() const +{ + if (fName == 0) + return 0; + + return (fName + qcConstraintMagic2Len); +} + +inline void QcConstraintRep::Reset() +{ + fCounter = 1; + fId = fNextValidId++; + qcAssertInvar(fNextValidId > 0); +} + +/** Returns true iff this constraint is satisfied or + QcUtility.isZero(LHS - RHS). The current implementation + ignores the possibility of NaN or infinity problems. */ +inline bool QcConstraintRep::isSatisfied() const +{ + numT x = fLinPoly.getValue() - fRHS; + + if (QcUtility::IsZero (x)) + return true; + + switch (fOperator) { + case coEQ: + return false; + + case coLE: + return x < 0; + + case coGE: + return x > 0; + } + qcDurchfall("fOp " + fOperator); + abort(); +} + +#if !qcCheckInternalInvar +inline void QcConstraintRep::assertInvar() const +{ } +#endif + +#ifndef qcNoStream +inline ostream &operator<<(ostream &os, const QcConstraintRep &r) +{ + r.Print(os); + return os; +} +#endif + +struct QcConstraintRep_hash +{ + size_t operator()(QcConstraintRep const *c) const + { + return (size_t) c->Id(); + } +}; + +struct QcConstraintRep_equal +{ + size_t operator()(QcConstraintRep const *c1, + QcConstraintRep const *c2) const + { + return c1->Id() == c2->Id(); + } +}; + +#endif /* !__QcConstriantRepH */ diff --git a/src/kits/interface/qoca/QcCoreTableau.cc b/src/kits/interface/qoca/QcCoreTableau.cc new file mode 100644 index 0000000000..7bdb3cc9c5 --- /dev/null +++ b/src/kits/interface/qoca/QcCoreTableau.cc @@ -0,0 +1,251 @@ +// $Id: QcCoreTableau.cc,v 1.12 2001/01/30 01:32:07 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcCoreTableau.hh" +#include "qoca/QcRowAdaptor.hh" + +unsigned QcCoreTableau::AddRow(QcRowAdaptor &varCoeffs, numT rhs) +{ + unsigned r = 0; // Row of fA, col of fM, int for original constraint + int quasiRow; // Row of fM, int for solved form constraint + + // Look for a deleted row or create a new row if one not found + while (r < fRows && !GetARowDeleted(r)) + r++; + + if (r == fRows) { + dbg(unsigned r1 =) + IncreaseRows(); + assert( r == r1); + quasiRow = GetMRowIndex(r); + qcAssert( quasiRow == (int) r); // Currently IncreaseRows ensures this + } else { + quasiRow = GetMRowIndex(r); + SetARowDeleted(r, false); + SetMRowDeleted(quasiRow, false); + } + + qcAssert(GetRawRHS(r) == 0.0); + + // Load the new values into the fA matrix and RHS + SetRawRHS(r, rhs); + fSF.SetRHS(quasiRow, rhs); + + while (!varCoeffs.AtEnd()) { + qcAssert(varCoeffs.getIndex() < fColumns); + #ifdef qcSafetyChecks + if (QcUtility::IsZero( varCoeffs.getValue())) + throw QcWarning(qcPlace, "AddRow: Zero coeff supplied"); + #endif + fSF.SetValue(quasiRow, varCoeffs.getIndex(), varCoeffs.getValue()); + varCoeffs.Increment(); + } + + return r; +} + +#ifndef NDEBUG +void +QcCoreTableau::assertInvar() const +{ + // A few important basic checks + assert( fAllocRows >= fRows && + fAllocColumns >= fColumns); + + // Check matrices and vectors are the right size + assert( (fRowColState.fRowState->GetSize() == fRows) + && (fOrigRowState.GetSize() == fRows)); + + // Now check a few integrity constraints for row state data + for (unsigned r = 0; r < fRows; r++) + { + // First consider r as indexing rows of fM + { + int rARowIx = GetARowIndex( r); + assert( (rARowIx == QcTableau::fInvalidConstraintIndex) + || ((unsigned) rARowIx < fRows)); + if (GetMRowDeleted( r)) + { + assert( (r == (unsigned) GetMRowIndex( rARowIx)) + && GetARowDeleted( rARowIx)); + } + } + + // Now consider r as indexing rows of fA (and hence columns of fM) + { + int rMRowIx = GetMRowIndex( r); + assert( (rMRowIx == QcTableau::fInvalidConstraintIndex) + || ((unsigned) rMRowIx < fRows)); + if (GetARowDeleted( r)) + { + assert( (r == (unsigned) GetARowIndex( rMRowIx)) + && GetMRowDeleted( rMRowIx)); + } + } + } +} +#endif + +int QcCoreTableau::DeleteRow(unsigned ci) +{ + int quasiRow = GetMRowIndex(ci); + qcAssert(GetARowIndex(quasiRow) == (int) ci); + SetMRowDeleted(quasiRow, true); + SetARowDeleted(ci, true); + fSF.ZeroRow(quasiRow); + SetRawRHS(ci, 0.0); + return quasiRow; +} + +unsigned QcCoreTableau::IncreaseColumns() +{ + qcAssert(fColumns <= fAllocColumns); + + if (fColumns == fAllocColumns) { + fAllocColumns += (fAllocColumns == 0) ? 1 : fAllocColumns; + fSF.Reserve(fAllocRows, fAllocColumns); + fRowColState.fColState->Reserve(fAllocColumns); + } + + fColumns++; + fSF.Resize(fRows, fColumns); + fRowColState.fColState->Resize(fColumns); + + // Set the default data values for the newly added column. + fSF.ZeroColumn(fColumns - 1); + + return fColumns - 1; +} + +unsigned QcCoreTableau::IncreaseRows() // Add an extra row +{ + assert( fRows <= fAllocRows); + + if (fRows == fAllocRows) { + fAllocRows += (fAllocRows == 0) ? 1 : fAllocRows; + fSF.Reserve(fAllocRows, fAllocColumns); + fRowColState.fRowState->Reserve(fAllocRows); + fOrigRowState.Reserve(fAllocRows); + } + + fRows++; + fSF.Resize(fRows, fColumns); + fRowColState.fRowState->Resize(fRows); + fOrigRowState.Resize(fRows); + + // Set the default data values for the newly added row. + fSF.ZeroRow(fRows - 1); + return fRows - 1; +} + +void QcCoreTableau::Initialize(unsigned hintRows, unsigned hintCols) +{ + qcAssertPre ((int) hintRows >= 0); + qcAssertPre ((int) hintCols >= 0); + + fAllocRows = hintRows; + fAllocColumns = hintCols; + fSF.Reserve(hintRows, hintCols); + fRowColState.Reserve(hintRows, hintCols); + fOrigRowState.Reserve(hintRows); + fRows = 0; + fColumns = 0; +} + +void QcCoreTableau::Print(ostream &os) const +{ + os << "QcCoreTableau with " << fRows << " rows and " + << fColumns << " cols." << endl; + os << "==========================================================" << endl; + os << "Raw RHS: "; + + for (unsigned i = 0; i < fRows; i++) + os << "\t" << GetRawRHS(i); + + os << endl; + os << "Deleted rows of fM are: "; + + for (unsigned i = 0; i < fRows; i++) + if (GetMRowDeleted(i)) + os << "\t" << i; + + os << endl; + os << "Deleted rows of fA are: "; + + for (unsigned i = 0; i < fRows; i++) + if (GetARowDeleted(i)) + os << "\t" << i; + + os << endl << "Quasi RowState: "; + fRowColState.fRowState->Print(os); + fOrigRowState.Print(os); +} + +void QcCoreTableau::Restart() +{ + fRows = 0; + fColumns = 0; + fSF.Restart(); + fRowColState.Restart(); + fOrigRowState.Resize(0); +} + +void QcCoreTableau::Restore() +{ + unsigned co; // original constraint index (row of fA) + unsigned cs; // solved form constraint index (row of fM) + + // Reset constraint state information + for (cs = 0, co = 0; cs < fRows; cs++, co++) { + // Find next undeleted constraint + while (cs < fRows && GetMRowDeleted(cs)) + ++cs; + + while (co < fRows && GetARowDeleted(co)) + ++co; + + if (co < fRows) { + qcAssert(cs < fRows); + qcAssert(!GetARowDeleted(co)); + qcAssert(!GetMRowDeleted(cs)); + fSF.ZeroRow(cs); + fSF.SetRHS(cs, fOrigRowState.GetRHS(co)); + SetMRowIndex(co, cs); + SetARowIndex(cs, co); + // N.B. We permit Reset to change the co<->cs relationship for + // a previously invalid constraint. As long as they + // are empty it doesn't matter which are used. + } else + break; + } + + // Fix row and column linked lists. + fRowColState.fRowState->FixLinkage(); + fRowColState.fColState->FixLinkage(); + + dbg(assertInvar()); +} diff --git a/src/kits/interface/qoca/QcCoreTableau.hh b/src/kits/interface/qoca/QcCoreTableau.hh new file mode 100644 index 0000000000..89f3ee3c52 --- /dev/null +++ b/src/kits/interface/qoca/QcCoreTableau.hh @@ -0,0 +1,278 @@ +// $Id: QcCoreTableau.hh,v 1.13 2001/01/30 01:32:07 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// + + +#ifndef __QcCoreTableauH +#define __QcCoreTableauH + +#include "qoca/QcSolvedFormMatrix.hh" +#include "qoca/QcQuasiRowColStateVector.hh" +#include "qoca/QcOrigRowStateVector.hh" +#include "qoca/QcUtility.hh" + +class QcRowAdaptor; + +/** At this level it is important to understand the relationship between rows + and columns of fM and fA in the quasi representation. Each solved form + constraint coefficient is represented in a decomposed form. Rows of fM + correspond to constraints and a CIndex constraint iterator Index field + indicates which row of fM this is. For each constraint there is a row of fA + and both a row and a column of fM. However, once a constraint has been + assigned a basic variable (via Pivot), there is no association between the + corresponding row of fM and any particular row of fA. The constraint coeff + (ci,vi) is the dot product of a row of fM and a column of fA (ignoring + deleted entries). The column is given by vi directly. The row of fM is + ci->MRowIndex. The QuasiRowState structure provides information about rows + of fA as well as rows of fM. For example ARowDeleted. + + ARowDeleted(ci) means row ci of fA, row MRowIndex(ci) of fM and column ci of + fM corrrespond to a deleted constraint. ARowDeleted(ci) ⇒ + MRowDeleted(MRowIndex(ci)). +**/ +class QcCoreTableau +{ +public: + /** Solved form. */ + QcSolvedFormMatrix fSF; + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcCoreTableau( QcQuasiRowColStateVector &rcs); + QcCoreTableau( unsigned hintRows, unsigned hintCols, + QcQuasiRowColStateVector &rcs); + + virtual ~QcCoreTableau() { } + +#ifndef NDEBUG + void assertInvar() const; + + void assertDeepInvar() const + { + assertInvar(); + fSF.assertDeepInvar(); + } + + virtual void vAssertDeepInvar() const + { + assertDeepInvar(); + } +#endif + + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + + /** Get RHS for solved form constraint ci. + If GetMRowDeleted(ci)) then return 0. + + @precondition ci < getNRows() + **/ + virtual numT GetRHS(unsigned ci) const; + + /** Get coefficient for variable vi in constraint ci. + If GetMRowDeleted(ci)) then return 0. + +

(One reason that GetRHS and GetValue work for deleted constraints + (returning 0) is to satisfy the RowCol interface.) + + @precondition ci < getNRows() + @precondition vi < getNColumns() + **/ + virtual numT GetValue(unsigned ci, unsigned vi) const; + + unsigned GetAllocRows() const + { return fAllocRows; } + + unsigned GetAllocCols() const + { return fAllocColumns; } + + unsigned GetColumns() const + { return fColumns; } + + bool GetARowDeleted(unsigned ci) const + { return fOrigRowState.GetARowDeleted(ci); } + + int GetARowIndex(unsigned ci) const + { return fRowColState.fRowState->GetARowIndex(ci); } + + bool GetMRowDeleted(unsigned ci) const + { return fRowColState.fRowState->GetMRowDeleted(ci); } + + int GetMRowIndex(unsigned ci) const + { return fOrigRowState.GetMRowIndex(ci); } + + numT GetRawRHS(unsigned ci) const // The orginal constraint RHS + { return fOrigRowState.GetRHS(ci); } // Don't confuse this with GetRHS + + QcQuasiRowColStateVector &GetRowColState() const + { return fRowColState; } + + unsigned GetRows() const + { return fRows; } + + bool IsValidOCIndex(int ci) const + { return ((unsigned) ci < fRows && !GetARowDeleted(ci)); } + + bool IsValidCIndex(int ci) const + { return ((unsigned) ci < fRows && !GetMRowDeleted(ci)); } + + bool IsValidVIndex(int vi) const + { return ((unsigned) vi < fColumns); } + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + + /** Add a new row, allocating any new columns indicated. + + @return The new row index. + **/ + virtual unsigned AddRow(QcRowAdaptor &varCoeffs, numT rhs); + + virtual void AddScaledRow(unsigned destRow, unsigned srcRow, numT factor) + { fSF.AddScaledRow(destRow, srcRow, factor); } + + virtual void ChangeRHS(unsigned ci, numT rhs) + // Change the RHS of the constraint ci. + { SetRawRHS(ci, rhs); } + + virtual int DeleteRow(unsigned ci); + // Deletes a row given an original constraint index by setting all + // the coefficients to zero and marking the row as deleted. + // Derived classes use this method to delete constraints + // which are found to be inconsistant after a successful AddEq + // (i.e. unable to successfully pivot). + + virtual unsigned IncreaseColumns(); // Creates a new non-basic variable + + virtual unsigned IncreaseRows(); // Creates a new redundant constraint + virtual void Initialize(unsigned hintRows, unsigned hintCols); + // Call this after construction. + +#if 0 + virtual void LinkRow(unsigned ci) + // Add row ci to the row list. + { fRowColState.fRowState->LinkRow(ci); } +#endif + + /** Force the RHS of row ci to be non-negative, by negating the + row iff its RHS was negative. + + @precondition ci < getNRows() + **/ + virtual void Normalize(unsigned ci); + + virtual void Restart(); // Erase everything ready to start afresh. + virtual void Restore(); + // The tableau is reinitialised as if all the original constraints + // had been added to a fresh tableau using AddEq but with no + // Elimination or Pivoting having been done. + + virtual void ScaleRow(unsigned row, numT factor) + { fSF.ScaleRow(row, factor); } + + virtual void CopyColumn(unsigned destCol, unsigned srcCol) + { fSF.CopyColumn(destCol, srcCol); } + + void SetARowDeleted(unsigned ci, bool d) + { fOrigRowState.SetARowDeleted(ci, d); } + + void SetARowIndex(unsigned ci, int i) + { fRowColState.fRowState->SetARowIndex(ci, i); } + + void SetMRowDeleted(unsigned ci, bool d) + { fRowColState.fRowState->SetMRowDeleted(ci, d); } + + void SetMRowIndex(unsigned ci, int i) + { fOrigRowState.SetMRowIndex(ci, i); } + + void SetRawRHS(unsigned ci, numT rhs) // The orginal constraint RHS + { fOrigRowState.SetRHS(ci, rhs); } + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; + +protected: + QcQuasiRowColStateVector &fRowColState; + QcOrigRowStateVector fOrigRowState; // 0..fRow-1 + unsigned fRows; + unsigned fColumns; + unsigned fAllocRows; + unsigned fAllocColumns; +}; + +inline QcCoreTableau::QcCoreTableau(QcQuasiRowColStateVector &rcs) + : fRowColState(rcs) +{ +} + +inline QcCoreTableau::QcCoreTableau(unsigned hintRows, unsigned hintCols, + QcQuasiRowColStateVector &rcs) + : fRowColState(rcs) +{ + Initialize(hintRows, hintCols); +} + +inline numT QcCoreTableau::GetRHS(unsigned ci) const +{ + qcAssertPre (ci < fRows); + + if (GetMRowDeleted(ci)) + return 0.0; + + return fSF.GetRHS(ci); +} + +inline numT QcCoreTableau::GetValue(unsigned ci, unsigned vi) const +{ + qcAssertPre (ci < fRows); + qcAssertPre (vi < fColumns); + + if (GetMRowDeleted(ci)) + return 0.0; + + return fSF.GetValue(ci, vi); +} + +inline void QcCoreTableau::Normalize(unsigned ci) +{ + if (QcUtility::IsNegative(GetRHS(ci))) + fSF.NegateRow( ci); +} + +#ifndef qcNoStream +inline ostream &operator<<(ostream &os, const QcCoreTableau &t) +{ + t.Print(os); + return os; +} +#endif + +#endif diff --git a/src/kits/interface/qoca/QcDefines.hh b/src/kits/interface/qoca/QcDefines.hh new file mode 100644 index 0000000000..719c196615 --- /dev/null +++ b/src/kits/interface/qoca/QcDefines.hh @@ -0,0 +1,190 @@ +// $Id: QcDefines.hh,v 1.16 2001/01/31 07:37:13 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDefinesH +#define __QcDefinesH + +#define qcQuantum 64 +#define qcHashTableInitCapacity 256 +#define qcVectorInitCapacity 256 +#define qcMatrixInitRowCapacity 256 +#define qcMatrixInitColCapacity 256 +#define qcTableauInitRowCapacity 256 +#define qcTableauInitColCapacity 256 +#define qcMaxLoopCycles 10000 +#define qcOneMegaBytes 1048576 +#define qcOneKiloBytes 1024 + +#ifdef USE_RATIONALS +# define NUMT_IS_PJM_MPQ 1 +#else +# define NUMT_IS_DOUBLE 1 +#endif +#include + +#define qcCheckInput 1 + +/* Simply #defining qcOneDirectionalSparseMatrix (i.e. use + singly-linked lists for the sparse matrices) without any other + changes is probably a bad idea, due to removal costs. However, + using one directional linked lists for the row iterating linked + lists is just about feasible, since usually we reach the element by + traversing the row linked lists anyway, so we should already have a + pointer to the previous element as an auto variable. + + Alternatively, don't immediately unlink things. (In this case, do + consider whether it's safe to unlink from one list without + unlinking from the other.) */ +//#define qcOneDirectionalSparseMatrix + +//#define qcDenseQuasiInverse + +// Note: currently still crashes if defined. +//#define qcSafetyChecks 1 + +/* qcUseSafeIterator is of limited use; consider removing the code used ifdef + qcUseSafeIterator. Use it if you don't trust the sparse iterators. However, + note that it doesn't actually test the correctness of the sparse iterator, it + just uses a dense one instead. Note that if sparse iterators are erroneous, + then the program will probably still go wrong. */ +//#define qcUseSafeIterator + +#ifndef NDEBUG +# define qcCheckPre 1 +# define qcCheckPost 1 +# define qcCheckInternalPre 1 +# define qcCheckInternalPost 1 +#endif +#define qcRealTableauCoeff +#define qcRealTableauRHS +#define qcUseExceptions + +#ifdef qcUseExceptions +# include "qoca/QcException.hh" +#endif + +#define qcInvalidInt -1 + // Used in QcBimap.h and must be the value used for invalid + // int and int for this reason. + +#define FUNCTION_H + // STL function.h creates problems due to dumb template operators. + +#include + +#if qcCheckInternalPre || qcCheckInternalPost +# define qcCheckInternalInvar 1 +#endif + +#ifndef NDEBUG +# define qcBoundsChecks 1 +#endif + +#ifdef qcSafetyChecks +# define qcBoundsChecks 1 +# define QcAssertions 1 +#endif + +#if defined(qcSafetyChecks) || qcCheckPre || qcCheckPost || qcCheckInternalPre || qcCheckInternalPost +# include +#endif + +#ifdef NDEBUG +# define dbg(_expr) +#else +# define dbg(_expr) _expr +#endif + +#define showplace() do { cout << "DBG: " << __FILE__ << ':' << __LINE__ << endl; } while(false) + +#define qcPlace __FILE__,__LINE__ + +#ifdef QcAssertions +//# define qcAssert(i) ((i)? 0: (throw QcWarning(qcPlace, "Assertion failed"), 0)) +# define qcAssert(i) assert(i) +#else +# define qcAssert(i) +#endif + +#if qcCheckPre +/* TODO: We could prepend a "Pre..." / "Post..." string. */ +# define qcAssertExternalPre(_p) assert(_p) +# define qcAssertPre(_p) assert(_p) +# define qcAssertExpensivePre(_p) assert(_p) +# define dbgPre(_expr) _expr +#else +# define qcAssertExternalPre(_p) do { } while(0) +# define qcAssertPre(_p) do { } while(0) +# define dbgPre(_expr) +#endif +#if qcCheckPost +# define qcAssertExternalPost(_p) assert(_p) +# define qcAssertPost(_p) assert(_p) +# define dbgPost(_expr) _expr +#else +# define qcAssertExternalPost(_p) do { } while(0) +# define qcAssertPost(_p) do { } while(0) +# define dbgPost(_expr) +#endif + +#if qcCheckInternalPre +# define qcDurchfall(_s) assert(0 && "Durchfall on " _s) +#else +# define qcDurchfall(_s) do { } while(0) +#endif + +#if qcCheckInternalInvar +# define qcAssertInvar(_p) assert(_p) +#else +# define qcAssertInvar(_p) do { } while(0) +#endif + +#ifndef UNUSED +# define UNUSED(_var) ((void) (_var)) +#endif + +#define CAST(_newtype, _expr) \ + (\ + assert (dynamic_cast<_newtype> (_expr) != 0), \ + (_newtype) (_expr) \ + ) + +#ifndef qcNoStream +# include +#endif + +/* TODO: Maybe use autoconf to detect this. (OTOH, I imagine that + most such primitive environments would be non-Un*x anyway.) */ +#ifdef qcDefineBool +# include // Use this while using STL and no built in bool +#endif + + // This is needed if we use the STL provided with Borland C++ +#ifdef __BCPLUSPLUS__ +# define RWSTD_NO_NAMESPACE +#endif + +#endif diff --git a/src/kits/interface/qoca/QcDelCoreTableau.cc b/src/kits/interface/qoca/QcDelCoreTableau.cc new file mode 100644 index 0000000000..e7a3780bca --- /dev/null +++ b/src/kits/interface/qoca/QcDelCoreTableau.cc @@ -0,0 +1,452 @@ +// $Id: QcDelCoreTableau.cc,v 1.16 2001/01/31 10:03:35 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcSparseMatrixRowIterator.hh" +#include "qoca/QcDenseMatrixColIterator.hh" +#include "qoca/QcDelCoreTableau.hh" +#include "qoca/QcRowAdaptor.hh" + +unsigned QcDelCoreTableau::AddRow(QcRowAdaptor &varCoeffs, numT rhs) +{ + unsigned r = 0; // Row of fA, col of fM, int for original constraint + int quasiRow; // Row of fM, int for solved form constraint + + // Look for a deleted row or create a new row if one not found + while (r < fRows && !GetARowDeleted(r)) + r++; + + if (r == fRows) { + r = IncreaseRows(); + quasiRow = GetMRowIndex(r); + qcAssert(quasiRow == (int) r); // Currently IncreaseRows ensures this + } else { + quasiRow = GetMRowIndex(r); + fM.SetValue(quasiRow, r, 1.0); + SetARowDeleted(r, false); + SetMRowDeleted(quasiRow, false); + } + + #ifdef qcSafetyChecks + for (unsigned j = 0; j < fColumns; j++) + qcAssert(fA.GetValue(r, j) == 0); + qcAssert(GetRawRHS(r) == 0.0); + + for (unsigned i = 0; i < fRows; i++) { + if (i != r) + qcAssert(fM.GetValue(quasiRow, i) == 0.0); // quasiRow of fM + if ((int) i != quasiRow) + qcAssert(fM.GetValue(i, r) == 0.0); // column r of fM + } + qcAssert(fM.GetValue(quasiRow, r) == 1); + #endif + + // Load the new values into the fA matrix and RHS + SetRawRHS(r, rhs); + fSF.SetRHS(quasiRow, rhs); + + while (!varCoeffs.AtEnd()) { + assert( varCoeffs.getIndex() < fColumns); + #ifdef qcSafetyChecks + if (QcUtility::IsZero( varCoeffs.getValue())) + throw QcWarning(qcPlace, "AddRow: Zero coeff supplied"); + #endif + fA.SetValue(r, varCoeffs.getIndex(), varCoeffs.getValue()); + fSF.SetValue(quasiRow, varCoeffs.getIndex(), varCoeffs.getValue()); + varCoeffs.Increment(); + } + + return r; +} + +void QcDelCoreTableau::ChangeRHS(unsigned ci, numT rhs) +{ +#ifdef qcRealTableauRHS + numT diff = rhs - GetRawRHS( ci); + + if(!QcUtility::IsZero( diff)) + { +# ifdef qcDenseQuasiInverse + QcDenseMatrixColIterator colIt( fM, ci); +# else + QcSparseMatrixColIterator colIt( fM, ci); +# endif + + assert( GetRows() == fM.getNRows()); + for(; !colIt.AtEnd(); colIt.Increment()) + { + unsigned i = colIt.getIndex(); + + if(!GetMRowDeleted( i)) + fSF.IncreaseRHS( i, colIt.getValue() * diff); + } + } +#endif + + QcCoreTableau::ChangeRHS( ci, rhs); +} + +void QcDelCoreTableau::DecreaseColumns(QcBiMapNotifier ¬e) + // Get rid of last column provided the variable is not used. +{ + qcAssert(fColumns > 0); + qcAssert(IsFree(fColumns - 1)); + fColumns--; + fA.Resize(fRows, fColumns); + fRowColState.fColState->Resize(fColumns); + note.DropVariable(fColumns); + fSF.Resize(fRows, fColumns); +} + +void QcDelCoreTableau::DecreaseRows(QcBiMapNotifier ¬e) + // Get rid of the last row - provided it is a deleted row for + // both original and solved form constraint. + // N.B. The deleted solved form and original constaint need + // not correspond to each other. +{ + qcAssert(fRows > 0); + qcAssert(GetARowDeleted(fRows - 1)); + qcAssert(GetMRowDeleted(fRows - 1)); + int AIndex = GetARowIndex(fRows - 1); + int MIndex = GetMRowIndex(fRows - 1); + + // If the last (deleted) original and solved form constraints + // don't correspond then swap the indices around so there will + // be no invalid indices after this routine finishes. + if (AIndex != (int) fRows - 1) { + qcAssert(MIndex != (int) fRows - 1); + SetMRowIndex(AIndex, MIndex); + SetARowIndex(MIndex, AIndex); + } + + fRows--; + fM.Resize(fRows, fRows); + fA.Resize(fRows, fColumns); + fSF.Resize(fRows, fColumns); + fRowColState.fRowState->Resize(fRows); + fOrigRowState.Resize(fRows); + note.DropConstraint(fRows); +} + +numT QcDelCoreTableau::GetRHSVirtual(unsigned ci) const + // See note for GetValue member +{ + qcAssertPre (ci < fRows); + + if (GetMRowDeleted(ci)) + return 0.0; + + numT sum = 0.0; + + for (unsigned i = 0; i < fRows; i++) + sum += fM.GetValue(ci, i) * GetRawRHS(i); + + return QcUtility::Zeroise(sum); +} + +numT QcDelCoreTableau::GetValueVirtual(unsigned ci, unsigned vi) const +{ + qcAssertPre( ci < fRows); + qcAssertPre( vi < fColumns); + + numT sum( 0); + + if (GetMRowDeleted( ci)) + return sum; + + for (QcSparseMatrixColIterator varcol( fA, vi); + !varcol.AtEnd(); + varcol.Increment()) + { + sum += (fM.GetValue( ci, varcol.getIndex()) + * varcol.getValue()); + } + return QcUtility::Zeroise(sum); +} + +unsigned QcDelCoreTableau::IncreaseColumns() + // Add and extra column +{ + qcAssert(fColumns <= fAllocColumns); + + if (fColumns == fAllocColumns) { + fAllocColumns += (fAllocColumns == 0) ? 8 : fAllocColumns; + fA.Reserve(fAllocRows, fAllocColumns); + fSF.Reserve(fAllocRows, fAllocColumns); + fRowColState.fColState->Reserve(fAllocColumns); + } + + fColumns++; + fA.Resize(fRows, fColumns); + fRowColState.fColState->Resize(fColumns); + fSF.Resize(fRows, fColumns); + + // Set the default data values for the newly added column + fA.ZeroColumn(fColumns - 1); + fSF.ZeroColumn(fColumns - 1); + + return fColumns - 1; +} + +unsigned QcDelCoreTableau::IncreaseRows() + // Add an extra row +{ + qcAssert(fRows <= fAllocRows); + + if (fRows == fAllocRows) { + fAllocRows += (fAllocRows == 0) ? 8 : fAllocRows; + fA.Reserve(fAllocRows, fAllocColumns); + fM.Reserve(fAllocRows, fAllocRows); + fSF.Reserve(fAllocRows, fAllocColumns); + fRowColState.fRowState->Reserve(fAllocRows); + fOrigRowState.Reserve(fAllocRows); + } + + fRows++; // logically, these 3 lines are where the + fA.Resize(fRows, fColumns); // number of rows increases, the optimiser + fM.Resize(fRows, fRows); // should cache the (fRows-1) that follow. + fSF.Resize(fRows, fColumns); + fRowColState.fRowState->Resize(fRows); + fOrigRowState.Resize(fRows); + + // Set the default data values for the newly added row + fA.ZeroRow(fRows - 1); + fM.ZeroRow(fRows - 1); + fM.ZeroColumn(fRows - 1); + fM.SetValue(fRows - 1, fRows - 1, 1.0); + fSF.ZeroRow(fRows - 1); + return fRows - 1; +} + +bool QcDelCoreTableau::IsValidSolvedForm() const +{ + /* effic: Use iterators. */ + for (unsigned i = 0; i < fRows; i++) + { + for (unsigned j = 0; j < fColumns; j++) + { + // TODO: Should be numRefT. + numT val_ij( GetValue( i, j)); + numT virt_val_ij( GetValueVirtual( i, j)); + if (QcUtility::IsZero( val_ij) + ? !QcUtility::IsZero( virt_val_ij) + : !QcUtility::IsVaguelyZero( virt_val_ij - val_ij)) + return false; + } + + numT rhs_i( GetRHS( i)); + numT virt_rhs_i( GetRHSVirtual( i)); + if (QcUtility::IsZero( rhs_i) + ? !QcUtility::IsZero( virt_rhs_i) + : !QcUtility::IsVaguelyZero( virt_rhs_i - rhs_i)) + return false; + } + + return true; +} + +void QcDelCoreTableau::Print(ostream &os) const +{ + os << "QcDelCoreTableau with " << fRows << " rows and "; + os << fColumns << " cols." << endl; + os << "==========================================================" << endl; + os << "Quasi Inverse Matrix:" << endl << fM << endl; + os << "Constraint Matrix:" << endl << fA << endl; + os << "Raw RHS: "; + + for (unsigned i = 0; i < fRows; i++) + os << "\t" << GetRawRHS(i); + + os << endl; + os << "Deleted rows of fM are: "; + + for (unsigned i = 0; i < fRows; i++) + if (GetMRowDeleted(i)) + os << "\t" << i; + + os << endl; + os << "Deleted rows of fA are: "; + + for (unsigned i = 0; i < fRows; i++) + if (GetARowDeleted(i)) + os << "\t" << i; + + os << endl << "Quasi RowState: "; + fRowColState.fRowState->Print(os); + os << "Quasi OrigRowState: "; + fOrigRowState.Print(os); +} + +void QcDelCoreTableau::PivotQuasiInverse(unsigned row, unsigned col) +{ +#ifdef qcRealTableauCoeff + numT p = fM.GetValue(row, col); + qcAssertPre( !QcUtility::IsZero(p)); + + ScaleRow( row, recip( p)); + +# ifdef qcDenseQuasiInverse + for (QcDenseMatrixColIterator colCoeffs( fM, col); + !colCoeffs.AtEnd(); + colCoeffs.Increment()) + { + if (colCoeffs.getIndex() != row) + AddScaledRow( colCoeffs.getIndex(), row, -colCoeffs.getValue()); + } +# elif defined(qcUseSafeIterator) + for (unsigned i = 0; i < fM.GetRows(); i++) + { + if (i != (unsigned) row) + AddScaledRow( i, row, -fM.GetValue( i, col)); + } +# else + /* Sparse column iterators are not guaranteed to be sane if the underlying + matrix gets modified (here by AddScaledRow), so we cache the column + coefficients in advance. */ + { + vector coeffCache; + + for (QcSparseMatrixColIterator colIt( fM, col); + !colIt.AtEnd(); + colIt.Increment()) + { + unsigned i = colIt.getIndex(); + if(i != row) + coeffCache.push_back( QcSparseCoeff( colIt.getValue(), i)); + } + + for (vector::iterator colIt = coeffCache.begin(); + colIt != coeffCache.end(); + colIt++) + AddScaledRow( colIt->getIndex(), row, -colIt->getValue()); + } +# endif +#else /* !qcRealTableauCoeff */ + fM.Pivot( row, col); +#endif +} + +void QcDelCoreTableau::Restart() +{ + fRows = 0; + fColumns = 0; + fM.Resize(0, 0); + fA.Resize(0, 0); + fSF.Restart(); + fRowColState.Restart(); + fOrigRowState.Resize(0); +} + +void QcDelCoreTableau::Restore() +{ + unsigned co; // original constraint index (row of fA) + unsigned cs; // solved form constraint index (row of fM) + + // Reset constraint state information + for (cs = 0, co = 0; cs < fRows; cs++, co++) + { + // Find next undeleted constraint + while (cs < fRows && GetMRowDeleted(cs)) + ++cs; + + while (co < fRows && GetARowDeleted(co)) + ++co; + + if (co < fRows) + { + qcAssert( cs < fRows); + qcAssert( !GetARowDeleted( co)); + qcAssert( !GetMRowDeleted( cs)); + fM.ZeroRow( cs); + fM.ZeroColumn( co); + fM.SetValue( cs, co, 1.0); + fSF.CopyCoeffRow( cs, fA, co); + fSF.SetRHS( cs, fOrigRowState.GetRHS( co)); + SetMRowIndex( co, cs); + SetARowIndex( cs, co); + // N.B. We permit Reset to change the co<->cs relationship for + // a previously invalid constraint. As long as they + // are empty it doesn't matter which are used. + } + else + break; + } + + // Fix row and column linked lists. + fRowColState.fRowState->FixLinkage(); + fRowColState.fColState->FixLinkage(); + + dbg(assertInvar()); +} + +void QcDelCoreTableau::TransitiveClosure(vector &vars) const +{ + /* effic: Should use a todo set. Using a todo set is probably O(n), whereas + the current method is probably O(n**2). */ + bool checkAgain = true; + + if (fColumns == 0 || fRows == 0) + return; + + QcSparseMatrixColIterator varCol(fA, 0); + QcSparseMatrixRowIterator varRow(fA, 0); + static vector fScatchFlags; + fScatchFlags.resize(fColumns); + + for (unsigned int i = 0; i < fScatchFlags.size(); i++) + fScatchFlags[i] = false; + + for (unsigned int i = 0; i < vars.size(); i++) + fScatchFlags[vars[i]] = true; + + while (checkAgain) + { + checkAgain = false; + + for (unsigned int i = 0; i < fScatchFlags.size(); i++) + { + if (fScatchFlags[i]) + { + for (varCol.SetToBeginOf( i); + !varCol.AtEnd(); + varCol.Increment()) + { + for (varRow.SetToBeginOf( varCol.GetIndex()); + !varRow.AtEnd(); + varRow.Increment()) + { + if (!fScatchFlags[varRow.GetIndex()]) + { + fScatchFlags[varRow.GetIndex()] = true; + vars.push_back( varRow.GetIndex()); + checkAgain = true; + } + } + } + } + } + } +} diff --git a/src/kits/interface/qoca/QcDelCoreTableau.hh b/src/kits/interface/qoca/QcDelCoreTableau.hh new file mode 100644 index 0000000000..0563cfef3f --- /dev/null +++ b/src/kits/interface/qoca/QcDelCoreTableau.hh @@ -0,0 +1,252 @@ +// $Id: QcDelCoreTableau.hh,v 1.9 2001/01/30 01:32:07 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// MRowIndex and ARowIndex record associations between rows of fA and fM // +// which are used when a constraint is deleted or not yet in the basis (means // +// the fM[*,Index] is a unit vector, element fM[MRowIndex,Index] is 1.0 and // +// and the other elements are zero). MRowIndex is the row of fM // +// corresponding to column fM[*,Index] of fM and row fA[Index,*] of fA. // +// ARowIndex is the row of fA corresponding to row fM[Index,*]. Unused // +// entries in ARowIndex and MRowIndex are set to -1. Hence MRowIndex and // +// ARowIndex are used to represent inverse indexing functions on a partial // +// domain. // +// EXCEPTION: this rule is currently violated by Pivot. // +// // +// QcDelCoreTableau and QcCoreTableau are only ever used as part of a // +// tableau, but it is not a tableau itself. Deriving a tableau from it // +// requires the use of multiple inheritance. Currently we are trying to // +// avoid multiple inheritance due to the increased risk running into compiler // +// bugs and to facilitate conversion to Java. // +//============================================================================// + +#ifndef __QcDelCoreTableauH +#define __QcDelCoreTableauH + +#include "qoca/QcCoreTableau.hh" +#include "qoca/QcDenseMatrix.hh" +#include "qoca/QcBiMapNotifier.hh" +#include "qoca/QcSparseMatrixColIterator.hh" +#include "qoca/QcQuasiRowColStateVector.hh" +#include "qoca/QcSparseCoeff.hh" + +class QcDelCoreTableau : public QcCoreTableau +{ +public: + #ifdef qcDenseQuasiInverse + QcDenseMatrix fM; // fRows x fRows + #else + QcSparseMatrix fM; // fRows x fRows + #endif + + QcSparseMatrix fA; // fRows x fCols + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcDelCoreTableau(QcQuasiRowColStateVector &rcs) : QcCoreTableau(rcs) {} + QcDelCoreTableau(unsigned hintRows, unsigned hintCols, QcQuasiRowColStateVector &rcs) + : QcCoreTableau(rcs) + { Initialize(hintRows, hintCols); } + +#ifndef NDEBUG + void assertInvar() const; + void assertDeepInvar() const; + + virtual void vAssertDeepInvar() const + { + assertDeepInvar(); + } +#endif + + //-----------------------------------------------------------------------// + // Enquiry methods. // + //-----------------------------------------------------------------------// + virtual numT GetRHS(unsigned ci) const; + // Get RHS for solved form constraint ci. + virtual numT GetRHSVirtual(unsigned ci) const; + virtual numT GetValue(unsigned ci, unsigned vi) const; + // Get coefficient for variable vi in constraint ci. + // GetVal and GetRHS can be used to access the coefficients + // of deleted constraints (zero is returned). This behaviour is + // required to satisfy the RowCol interface amongst other reasons. + + /** Returns (fM × fA)[ci, vi], i.e. \sum_i fM[ci, i] × + fA[i, vi]. As with GetValue, deleted rows are treated like + zeroes. + + @precondition ci < fRows + @precondition ci < fColumns + @postcondition isZeroized( ret) + **/ + virtual numT GetValueVirtual(unsigned ci, unsigned vi) const; + + bool IsFree(unsigned vi) const + // Indicates if a particular variable is in use (i.e. has a + // non-zero coefficient in any solved form (or original) constraint. + { return QcSparseMatrixColIterator(fA, vi).AtEnd(); } + + bool IsValidSolvedForm() const; + // For debugging purposes to ensure that the real solved form is + // consistant with the virtual solved form. + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + virtual unsigned AddRow(QcRowAdaptor &varCoeffs, numT rhs); + // Add a new row, allocating any new columns indicated. + // The new row index is returned. + virtual void AddScaledRow(unsigned destRow, unsigned srcRow, numT factor); + virtual void ChangeRHS(unsigned ci, numT rhs); + // Change the RHS of the constraint ci. + + virtual void DecreaseColumns(QcBiMapNotifier ¬e); + // Get rid of the last (empty) column. + virtual void DecreaseRows(QcBiMapNotifier ¬e); + // Get rid of the last (deleted) row. + virtual int DeleteRow(unsigned ci); + // Deletes a row given an original constraint index by setting all + // the coefficients to zero and marking the row as deleted. + // Derived classes use this method to delete constraints + // which are found to be inconsistant after a successful AddEq + // (i.e. unable to successfully pivot) and also used to remove a + // constraint after is has been removed from the basis. + virtual unsigned IncreaseColumns(); + // Creates a new non-basic variable. + virtual unsigned IncreaseRows(); + // Creates a new redundant constraint. + virtual void Initialize(unsigned hintRows, unsigned hintCols); + // Call this after construction + virtual void Normalize(unsigned ci); + // Normalize the corresponding row fM and fSF if the rhs is negative. + // This makes rhs positive. + virtual void PivotQuasiInverse(unsigned row, unsigned col); + // Pivot on the quasi inverse matrix. + virtual void Restart(); // Erase everything ready to start afresh. + virtual void Restore(); + // The tableau is reinitialised as if all the original constraints + // had been added to a fresh tableau using AddEq but with no + // Elimination or Pivoting having been done. + virtual void ScaleRow(unsigned row, numT factor); + virtual void CopyColumn(unsigned destCol, unsigned srcCol); + + void TransitiveClosure(vector &vars) const; + // Compute the transitive closure of a set of variables, using the + // relation "belong to the same original constraint". + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; +}; + +inline void QcDelCoreTableau::AddScaledRow(unsigned destRow, unsigned srcRow, + numT factor) +{ + QcCoreTableau::AddScaledRow(destRow, srcRow, factor); + fM.AddScaledRow(destRow, srcRow, factor); +} + +#ifndef NDEBUG +inline void +QcDelCoreTableau::assertInvar() const +{ + assert( (fA.GetRows() == fRows) + && (fA.GetColumns() == fColumns) + && (fM.GetRows() == fRows) + && (fM.GetColumns() == fRows)); +} + +inline void +QcDelCoreTableau::assertDeepInvar() const +{ + QcCoreTableau::assertDeepInvar(); + fA.assertDeepInvar(); + fM.assertDeepInvar(); +} +#endif + +inline int QcDelCoreTableau::DeleteRow(unsigned ci) +{ + int quasiRow = QcCoreTableau::DeleteRow(ci); + fM.ZeroColumn(ci); + fM.ZeroRow(quasiRow); + fA.ZeroRow(ci); + return quasiRow; +} + +inline numT QcDelCoreTableau::GetRHS(unsigned ci) const +{ + #ifdef qcRealTableauRHS + return QcCoreTableau::GetRHS(ci); + #else + return GetRHSVirtual(ci); + #endif +} + +inline numT QcDelCoreTableau::GetValue(unsigned ci, unsigned vi) const +{ + #ifdef qcRealTableauCoeff + return QcCoreTableau::GetValue(ci, vi); + #else + return GetValueVirtual(ci, vi); + #endif +} + +inline void QcDelCoreTableau::Initialize(unsigned hintRows, unsigned hintCols) +{ + QcCoreTableau::Initialize(hintRows, hintCols); + fM.Reserve(hintRows, hintRows); + fA.Reserve(hintRows, hintCols); +} + +inline void QcDelCoreTableau::Normalize(unsigned ci) +{ + if (QcUtility::IsNegative(GetRHS(ci))) { + fM.NegateRow(ci); + fSF.NegateRow(ci); + } +} + +inline void QcDelCoreTableau::ScaleRow(unsigned row, numT factor) +{ + QcCoreTableau::ScaleRow(row, factor); + fM.ScaleRow(row, factor); +} + +inline void QcDelCoreTableau::CopyColumn(unsigned destCol, unsigned srcCol) +{ + QcCoreTableau::CopyColumn( destCol, srcCol); + fA.CopyColumn( destCol, srcCol); +} + +#ifndef qcNoStream +inline ostream &operator<<(ostream &os, const QcDelCoreTableau &t) +{ + t.Print(os); + return os; +} +#endif + +#endif diff --git a/src/kits/interface/qoca/QcDelLinEqSystem.hh b/src/kits/interface/qoca/QcDelLinEqSystem.hh new file mode 100644 index 0000000000..364f8a7556 --- /dev/null +++ b/src/kits/interface/qoca/QcDelLinEqSystem.hh @@ -0,0 +1,109 @@ +// $Id: QcDelLinEqSystem.hh,v 1.6 2001/01/30 01:32:07 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDelLinEqSystemH +#define __QcDelLinEqSystemH + +#include "qoca/QcLinEqSystem.hh" +#include "qoca/QcDelLinEqTableau.hh" + +/** Version of QcLinEqSystem that allows removeConstraint. + +

Note that this interface needs to be read in conjuction with that of + QcSolver. +**/ +class QcDelLinEqSystem : public QcLinEqSystem +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcDelLinEqSystem(); + QcDelLinEqSystem(unsigned hintRows, unsigned hintCols); + QcDelLinEqSystem(QcLinEqTableau &tab); + + //-----------------------------------------------------------------------// + // Variable management methods (see QcSolver.java for descriptions) // + //-----------------------------------------------------------------------// + virtual bool RemoveVar(QcFloat &v); + + //-----------------------------------------------------------------------// + // Enquiry functions for variables // + //-----------------------------------------------------------------------// + virtual bool IsFree(QcFloat const &v) const + { return fTableau.IsFree(fVBiMap.Index(v)); } + + //-----------------------------------------------------------------------// + // High Level Edit Variable Interface for use by solver clients. // + // The methods addEditVar and endEdit are more efficient than the ones // + // inherited from Solver since variable weights have no effect on // + // QcLinEqSystem::Resolve. // + //-----------------------------------------------------------------------// + virtual void TransitiveClosure(vector &vars) + { fTableau.TransitiveClosure(vars); } + + //-----------------------------------------------------------------------// + // Constraint management methods // + //-----------------------------------------------------------------------// + virtual bool RemoveConstraint(QcConstraint &c); +}; + +inline QcDelLinEqSystem::QcDelLinEqSystem() + : QcLinEqSystem(*new QcDelLinEqTableau(0, 0, fNotifier)) +{ +} + +inline QcDelLinEqSystem::QcDelLinEqSystem(unsigned hintRows, unsigned hintCols) + : QcLinEqSystem(*new QcDelLinEqTableau(hintRows, hintCols, fNotifier)) +{ +} + +inline QcDelLinEqSystem::QcDelLinEqSystem(QcLinEqTableau &tab) + : QcLinEqSystem(tab) +{ +} + +inline bool QcDelLinEqSystem::RemoveVar(QcFloat &v) +{ + int ix = fVBiMap.safeIndex(v); + if (ix >= 0) + return fTableau.RemoveVarix( ix); + else + return false; +} + +inline bool QcDelLinEqSystem::RemoveConstraint(QcConstraint &c) +{ + int ix = fOCBiMap.safeIndex(c); + if (ix < 0) + return false; + + fTableau.RemoveEq(ix); + fEditVarsSetup = false; + return true; +} + +#endif diff --git a/src/kits/interface/qoca/QcDelLinEqTableau.cc b/src/kits/interface/qoca/QcDelLinEqTableau.cc new file mode 100644 index 0000000000..f79f54d0af --- /dev/null +++ b/src/kits/interface/qoca/QcDelLinEqTableau.cc @@ -0,0 +1,174 @@ +// $Id: QcDelLinEqTableau.cc,v 1.9 2001/01/31 07:37:13 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include "qoca/QcDefines.hh" +#include "qoca/QcDelLinEqTableau.hh" +#ifdef qcDenseQuasiInverse +# include +#else +# include +#endif + +numT QcDelLinEqTableau::GetValueVirtual(int ci, int vi) const +{ + // Short cut evaluations + switch (GetRowCondition(ci)) { + case QcLinEqRowState::fRedundant: + return 0.0; + case QcLinEqRowState::fNormalised: + if (IsBasic(vi)) + return 0.0; + break; + case QcLinEqRowState::fRegular: + if (IsBasic(vi)) { + if (vi == GetBasicVar(ci)) + return numT( 1u); + else + return 0.0; + } + break; + case QcLinEqRowState::fInvalid: + break; + } + + return CAST(QcDelCoreTableau *, fCoreTableau)->GetValueVirtual(ci,vi); +} + +int QcDelLinEqTableau::RemoveEq(unsigned ci) +{ + numT max = 0.0; // Maximal absolute value of coeff + int maxIndex = QcTableau::fInvalidConstraintIndex; + bool foundRedund = false; + int pivotRow; + +#ifndef NDEBUG + if ((int) ci < 0 || (int) ci >= GetRows() || fCoreTableau->GetARowDeleted(ci)) { + throw QcWarning(qcPlace, + "RemoveEq: invalid original constraint index", ci, GetRows() - 1); + return QcTableau::fInvalidConstraintIndex; + } else if (fCoreTableau->GetMRowIndex(ci) != QcTableau::fInvalidConstraintIndex) { + qcAssert(IsUndetermined(fCoreTableau->GetMRowIndex(ci))); + throw QcWarning(qcPlace, "RemoveEq for undetermined constraint"); + return QcTableau::fInvalidConstraintIndex; + } else if (!IsSolved()) + throw QcWarning(qcPlace, + "RemoveEq called when tableau not in solved form"); +#endif + + // First look for a suitable redundant constraint, meanwhile + // keep track of the maximal size quasiColCoeff. + #ifdef qcDenseQuasiInverse + QcDenseMatrixColIterator quasiColCoeffs( + CAST(QcDelCoreTableau *, fCoreTableau)->fM, ci); + #else + QcSparseMatrixColIterator quasiColCoeffs( + CAST(QcDelCoreTableau *, fCoreTableau)->fM, ci); + #endif + + while (!quasiColCoeffs.AtEnd()) { // N.B. This loop contains a break + qcAssert(!QcUtility::IsZero(quasiColCoeffs.getValue())); + + if (IsRedundant(quasiColCoeffs.getIndex())) { + foundRedund = true; + break; + } else { + #ifdef qcSafetyChecks + qcAssert(GetBasicVar(quasiColCoeffs.GetIndex()) + != QcTableau::fInvalidVariableIndex); + if (GetRowCondition(quasiColCoeffs.GetIndex()) + == QcLinEqRowState::fNormalised) + throw QcWarning(qcPlace, + "RemoveEq called with normalised constraint"); + else + qcAssert(GetRowCondition(quasiColCoeffs.GetIndex()) + == QcLinEqRowState::fRegular); + #endif + numT absValue = fabs (quasiColCoeffs.getValue()); + if (absValue > max) + { + max = absValue; + maxIndex = quasiColCoeffs.getIndex(); + } + // Note that the ratio used in IPL 55 (1995) page 112 is + // directly related to the inverse of max since the RHS + // value is constant and we take the absolute value of max. + } + quasiColCoeffs.Increment(); + } + + #ifdef qcSafetyChecks + if (foundRedund) + qcAssert(IsRedundant(quasiColCoeffs.GetIndex())); + else + qcAssert(max != 0.0 && maxIndex != QcTableau::fInvalidConstraintIndex); + #endif + + // Best to abort rather than use an invalid index + if (!foundRedund && maxIndex == QcTableau::fInvalidConstraintIndex) + return QcTableau::fInvalidConstraintIndex; + + // delete selected row from fM, column ci from fM, row ci from fA + if (foundRedund) { + pivotRow = quasiColCoeffs.GetIndex(); + SetRowCondition(pivotRow, QcLinEqRowState::fNormalised); + } else + pivotRow = maxIndex; + + CAST(QcDelCoreTableau *, fCoreTableau)->PivotQuasiInverse(pivotRow, ci); + + if (!foundRedund) + Unsolve(pivotRow); // removes pivotRow from the basis + + // The situation now simulates that of a newly added row after + // Eliminate has been called, but before a Pivot. + SetMRowIndex(ci, pivotRow); + SetARowIndex(pivotRow, ci); + DeleteRow(ci); + fNotifier.DropConstraint(ci); + return pivotRow; +} + +bool QcDelLinEqTableau::RemoveVarix(unsigned vi) +{ + if (!IsFree(vi)) + return false; + + qcAssert(!IsBasic(vi)); + qcAssert(IsBasicIn(vi) == QcTableau::fInvalidConstraintIndex); + + unsigned lastColumn = getNColumns() - 1; + if (vi != lastColumn) { // Swap column vi with last column + fCoreTableau->CopyColumn( vi, lastColumn); + fRowColState->SwapColumns( vi, lastColumn); + fNotifier.SwapVariables( vi, lastColumn); + } + + qcAssert(!IsBasic( lastColumn)); + qcAssert(IsBasicIn( lastColumn) == QcTableau::fInvalidConstraintIndex); + DecreaseColumns(fNotifier); + return true; +} diff --git a/src/kits/interface/qoca/QcDelLinEqTableau.hh b/src/kits/interface/qoca/QcDelLinEqTableau.hh new file mode 100644 index 0000000000..86ade3c20e --- /dev/null +++ b/src/kits/interface/qoca/QcDelLinEqTableau.hh @@ -0,0 +1,128 @@ +// $Id: QcDelLinEqTableau.hh,v 1.9 2001/01/30 01:32:07 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDelLinEqTableauH +#define __QcDelLinEqTableauH + +#include "qoca/QcLinEqTableau.hh" + +class QcDelLinEqTableau : public QcLinEqTableau +{ +public: + //-----------------------------------------------------------------------// + // Constructors. // + //-----------------------------------------------------------------------// + QcDelLinEqTableau(unsigned hintRows, unsigned hintCols, QcBiMapNotifier &n); + QcDelLinEqTableau(QcCoreTableau &tab, QcBiMapNotifier &n); + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + virtual bool IsFree(unsigned vi) const + // Indicates if a particular variable is in use (i.e. has a + // non-zero coefficient in any solved form (or original) constraint. + { return CAST(QcDelCoreTableau *, fCoreTableau)->IsFree(vi); } + + numT GetRHSVirtual(int ci) const + { return CAST(QcDelCoreTableau *, fCoreTableau)->GetRHSVirtual(ci); } + + numT GetValueVirtual(int ci, int vi) const; + // This is the similar to getValue except that it will always obtain + // value from computation of the quasi-inverse and orignial constraint + // coefficients. Whereas getValue obtain value directly from the + // solved form if the real tableau is used. + + bool IsValidSolvedForm() const + // For debugging purposes to ensure that the real solved form is + // consistant with the virtual solved form. + { return CAST(QcDelCoreTableau *, fCoreTableau)->IsValidSolvedForm(); } + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + virtual void DecreaseRows(QcBiMapNotifier ¬e) + // Get rid of the last (deleted) row + { CAST(QcDelCoreTableau *, fCoreTableau)->DecreaseRows(note); } + + virtual void DecreaseColumns(QcBiMapNotifier ¬e) + // Get rid of the last (empty) column + { CAST(QcDelCoreTableau *, fCoreTableau)->DecreaseColumns(note); } + + virtual int RemoveEq(unsigned ci); + // RemoveEq removes an original constraint with index ci from + // the solved form without disturbing the solution. This requires + // removal of one of the solved form constraints. The index of + // the removed solved form constraint is returned or InvalidCIndex + // if there is a serious error (e.g. ci invalid). For the current + // implementation: after a row is removed the CIndex values for + // particular rows are unchanged. + // The notifier is told to drop the constraint index. + + virtual bool RemoveVarix(unsigned vi); + // Removes a free variable from the tableau, returns false if not free. + + //-----------------------------------------------------------------------// + // Utility function. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; + + virtual void TransitiveClosure(vector &vars) + { CAST(QcDelCoreTableau *, fCoreTableau)->TransitiveClosure(vars); } + +protected: + //-----------------------------------------------------------------------// + // Constructors. // + //-----------------------------------------------------------------------// + QcDelLinEqTableau(QcBiMapNotifier &n); +}; + +inline QcDelLinEqTableau::QcDelLinEqTableau(unsigned hintRows, unsigned hintCols, + QcBiMapNotifier &n) + : QcLinEqTableau(*new QcDelCoreTableau(hintRows, hintCols, + *new QcLinEqRowColStateVector()), + n) +{ +} + +inline QcDelLinEqTableau::QcDelLinEqTableau(QcCoreTableau &tab, QcBiMapNotifier &n) + : QcLinEqTableau(tab, n) +{ +} + +inline QcDelLinEqTableau::QcDelLinEqTableau(QcBiMapNotifier &n) + : QcLinEqTableau(n) +{ +} + +inline void QcDelLinEqTableau::Print(ostream &os) const +{ + QcLinEqTableau::Print(os); + fCoreTableau->Print(os); + os << endl << "Consistant: " + << (IsValidSolvedForm() ? "yes" : "no") << endl; +} + +#endif /* !__QcDelLinEqTableauH */ diff --git a/src/kits/interface/qoca/QcDelLinInEqSystem.hh b/src/kits/interface/qoca/QcDelLinInEqSystem.hh new file mode 100644 index 0000000000..171083a04f --- /dev/null +++ b/src/kits/interface/qoca/QcDelLinInEqSystem.hh @@ -0,0 +1,80 @@ +// $Id: QcDelLinInEqSystem.hh,v 1.4 2000/11/23 06:44:20 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDelLinInEqSystemH +#define __QcDelLinInEqSystemH + +#include "qoca/QcLinInEqSystem.hh" +#include "qoca/QcDelLinInEqTableau.hh" + +class QcDelLinInEqSystem : public QcLinInEqSystem +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcDelLinInEqSystem(); + QcDelLinInEqSystem(unsigned hintRows, unsigned hintCols); + + //-----------------------------------------------------------------------// + // Variable management methods (see solver.h for descriptions) // + //-----------------------------------------------------------------------// + virtual bool RemoveVar(QcFloat &v) + { return QcDelLinEqSystem::RemoveVar(v); } + + //-----------------------------------------------------------------------// + // Constraint management methods // + //-----------------------------------------------------------------------// + virtual bool RemoveConstraint(QcConstraint &c); +}; + +inline QcDelLinInEqSystem::QcDelLinInEqSystem() + : QcLinInEqSystem(*new QcDelLinInEqTableau(0, 0, fNotifier)) +{ +} + +inline QcDelLinInEqSystem::QcDelLinInEqSystem(unsigned hintRows, unsigned hintCols) + : QcLinInEqSystem(*new QcDelLinInEqTableau(hintRows, hintCols, fNotifier)) +{ +} + +inline bool QcDelLinInEqSystem::RemoveConstraint(QcConstraint &c) +{ + bool present = fOCBiMap.IdentifierPresent(c); + + if (present) + fTableau.RemoveEq(fOCBiMap.Index(c)); + #ifdef qcSafetyChecks + else + throw QcWarning( + "QcDelLinEqSystem::RemoveConstraint: invalid QcConstraint"); + #endif + + fEditVarsSetup = false; + return present; +} + +#endif diff --git a/src/kits/interface/qoca/QcDelLinInEqTableau.cc b/src/kits/interface/qoca/QcDelLinInEqTableau.cc new file mode 100644 index 0000000000..aca9193a14 --- /dev/null +++ b/src/kits/interface/qoca/QcDelLinInEqTableau.cc @@ -0,0 +1,177 @@ +// $Id: QcDelLinInEqTableau.cc,v 1.9 2001/01/30 01:32:07 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcDelLinInEqTableau.hh" +#include "qoca/QcSparseMatrixRowIterator.hh" +#include "qoca/QcDenseMatrixColIterator.hh" + +int QcDelLinInEqTableau::AddGtEq(QcRowAdaptor &varCoeffs, numT rhs) +{ + int r = AddEq(varCoeffs, rhs); + + // Add new slack variable with coeff -1.0 + unsigned vi = NewVariable(); + SetColCondition(vi, QcLinInEqColState::fSlack | + QcLinInEqColState::fStructural); + SetConstrained(vi, true); + CAST(QcDelCoreTableau *, fCoreTableau)->fA.SetValue(r, vi, -1.0); + fCoreTableau->fSF.SetValue(GetMRowIndex(r), vi, -1.0); + + return r; +} + +int QcDelLinInEqTableau::AddLtEq(QcRowAdaptor &varCoeffs, numT rhs) +{ + int r = AddEq(varCoeffs, rhs); + + // Add new slack variable with coeff 1.0 + unsigned vi = NewVariable(); + SetColCondition(vi, QcLinInEqColState::fSlack | + QcLinInEqColState::fStructural); + SetConstrained(vi, true); + CAST(QcDelCoreTableau *, fCoreTableau)->fA.SetValue(r, vi, 1.0); + fCoreTableau->fSF.SetValue(GetMRowIndex(r), vi, 1.0); + + return r; +} + +int QcDelLinInEqTableau::RemoveEq(unsigned ci) +{ + numT min = INT_MAX; // Maximal absolute value of coeff + int minIndex = QcTableau::fInvalidConstraintIndex; + bool foundRedund = false; + int pivotRow; + + if ((int) ci < 0 || (int) ci >= GetRows() || fCoreTableau->GetARowDeleted(ci)) { + throw QcWarning(qcPlace, + "RemoveEq: invalid original constraint index", ci, GetRows() - 1); + return QcTableau::fInvalidConstraintIndex; + } else if (fCoreTableau->GetMRowIndex(ci) != QcTableau::fInvalidConstraintIndex) { + qcAssert(IsUndetermined(fCoreTableau->GetMRowIndex(ci))); + throw QcWarning(qcPlace, "RemoveEq for undetermined constraint"); + return QcTableau::fInvalidConstraintIndex; + } + #ifdef qcSafetyChecks + else if (!IsSolved()) + throw QcWarning(qcPlace, + "RemoveEq called when tableau not in solved form"); + #endif + + // First look for a suitable redundant constraint, meanwhile + // keep track of the maximal size quasiColCoeff. + #ifdef qcDenseQuasiInverse + QcDenseMatrixColIterator quasiColCoeffs( + CAST(QcDelCoreTableau *, fCoreTableau)->fM, ci); + #else + QcSparseMatrixColIterator quasiColCoeffs( + CAST(QcDelCoreTableau *, fCoreTableau)->fM, ci); + #endif + + while (!quasiColCoeffs.AtEnd()) { // N.B. This loop contains a break + qcAssert(!QcUtility::IsZero(quasiColCoeffs.GetValue())); + + if (IsRedundant(quasiColCoeffs.GetIndex())) { + foundRedund = true; + break; + } else { + qcAssert(GetBasicVar(quasiColCoeffs.GetIndex()) != + QcTableau::fInvalidVariableIndex); + #ifdef qcSafetyChecks + if (GetRowCondition(quasiColCoeffs.GetIndex()) == + QcLinEqRowState::fNormalised) + throw QcWarning(qcPlace, + "RemoveEq called with normalised constraint"); + else + qcAssert(GetRowCondition(quasiColCoeffs.GetIndex()) == + QcLinEqRowState::fRegular); + #endif + numT ratio = fabs(GetRHS(quasiColCoeffs.getIndex()) / + quasiColCoeffs.getValue()); + + if (ratio < min) { + min = ratio; + minIndex = quasiColCoeffs.getIndex(); + } + // Note that the ratio used in IPL 55 (1995) page 112 is + // directly related to the inverse of max since the RHS + // value is constant and we take the absolute value of max. + } + quasiColCoeffs.Increment(); + } + + #ifdef qcSafetyChecks + if (foundRedund) + qcAssert(IsRedundant(quasiColCoeffs.getIndex())); + else + qcAssert(minIndex != QcTableau::fInvalidConstraintIndex); + #endif + + // Best to abort rather than use an invalid index + if (!foundRedund && minIndex == QcTableau::fInvalidConstraintIndex) + return QcTableau::fInvalidConstraintIndex; + + // delete selected row from fM, column ci from fM, row ci from fA + if (foundRedund) { + pivotRow = quasiColCoeffs.GetIndex(); + SetRowCondition(pivotRow, QcLinEqRowState::fNormalised); + } else + pivotRow = minIndex; + + CAST(QcDelCoreTableau *, fCoreTableau)->PivotQuasiInverse(pivotRow, ci); + + if (!foundRedund) + Unsolve(pivotRow); // removes pivotRow from the basis + + // The situation now simulates that of a newly added row after + // Eliminate has been called, but before a Pivot. + SetMRowIndex(ci, pivotRow); + SetARowIndex(pivotRow, ci); + + // Removing the original constraint from the constraint matrix. First must + // remove any associated slack variables. + deque slackList; + QcSparseMatrixRowIterator var(CAST(QcDelCoreTableau *, fCoreTableau)->fA, ci); + + while (!var.AtEnd()) { + // It is very important to put index to the front because larger index + // should be deleted first so to avoid invaliding the index of the rest + // of the slack variables. + if (IsSlack(var.GetIndex())) + slackList.push_front(var.GetIndex()); + var.Increment(); + } + + DeleteRow(ci); + fNotifier.DropConstraint(ci); + + // Remove the slack variables if there are any. + for (deque::iterator slack = slackList.begin(); + slack != slackList.end(); ++slack) + RemoveVarix(*slack); + + return pivotRow; +} diff --git a/src/kits/interface/qoca/QcDelLinInEqTableau.hh b/src/kits/interface/qoca/QcDelLinInEqTableau.hh new file mode 100644 index 0000000000..855ed3ecdc --- /dev/null +++ b/src/kits/interface/qoca/QcDelLinInEqTableau.hh @@ -0,0 +1,78 @@ +// $Id: QcDelLinInEqTableau.hh,v 1.8 2001/01/30 01:32:07 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDelLinInEqTableauH +#define __QcDelLinInEqTableauH + +#include "qoca/QcLinInEqTableau.hh" +#include "qoca/QcLinInEqRowColStateVector.hh" + +class QcDelLinInEqTableau : public QcLinInEqTableau +{ +public: + //-----------------------------------------------------------------------// + // Constructors. // + //-----------------------------------------------------------------------// + QcDelLinInEqTableau(unsigned hintRows, unsigned hintCols, QcBiMapNotifier &n); + QcDelLinInEqTableau(QcCoreTableau &tab, QcBiMapNotifier &n); + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + virtual int AddGtEq(QcRowAdaptor &varCoeffs, numT rhs); + // Similar to addLtEq, only uses a negative slack variable coeff. + + virtual int AddLtEq(QcRowAdaptor &varCoeffs, numT rhs); + // AddLessEq does the same as AddEq but also introduces a new + // slack variable so the varCoeffs will represent a less than or + // equal to constraint. The slack variable is added after + // any other new regular variables. + + virtual int RemoveEq(unsigned ci); + // Eliminate the original constraint ci from the solved form and + // delete it. Returns the associated solved form constraint removed. + // If the operation cannot be performed for some reason InvalidCIndex + // is returned. + + virtual bool RemoveVarix(unsigned vi) + // Removes a free variable from the tableau, returns false if not free. + { return QcDelLinEqTableau::RemoveVarix( vi); } +}; + +inline QcDelLinInEqTableau::QcDelLinInEqTableau(unsigned hintRows, unsigned hintCols, + QcBiMapNotifier &n) + : QcLinInEqTableau(*new QcDelCoreTableau(hintRows, hintCols, + *new QcLinInEqRowColStateVector()), + n) +{ +} + +inline QcDelLinInEqTableau::QcDelLinInEqTableau(QcCoreTableau &tab, QcBiMapNotifier &n) + : QcLinInEqTableau(tab, n) +{ +} + +#endif /* !__QcDelLinInEqTableauH */ diff --git a/src/kits/interface/qoca/QcDenseMatrix.cc b/src/kits/interface/qoca/QcDenseMatrix.cc new file mode 100644 index 0000000000..f2d60d67c9 --- /dev/null +++ b/src/kits/interface/qoca/QcDenseMatrix.cc @@ -0,0 +1,252 @@ +// $Id: QcDenseMatrix.cc,v 1.12 2001/01/30 01:32:07 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcDenseMatrix.hh" +#include "qoca/QcDenseMatrixColIterator.hh" + +QcDenseMatrix::~QcDenseMatrix() +{ + if (fAllocColumns != 0) + for (unsigned i = 0; i < fAllocRows; i++) + delete[] fElements[i]; + + if (fAllocRows != 0) + delete[] fElements; +} + +#if 0 /* unused */ +void QcDenseMatrix::AddRow(unsigned destRow, unsigned srcRow) +{ + qcAssertPre (srcRow < fRows); + qcAssertPre (destRow < fRows); + + for (unsigned i = 0; i < fColumns; i++) + fElements[destRow][i] += fElements[srcRow][i]; +} +#endif + +bool QcDenseMatrix::AddScaledRow(unsigned destRow, unsigned srcRow, numT factor) +{ + qcAssertPre( QcUtility::isFinite( factor)); + qcAssertPre( srcRow < fRows); + qcAssertPre( destRow < fRows); + + if (QcUtility::IsZero( factor)) + return false; + + for (unsigned i = 0; i < fColumns; i++) + fElements[destRow][i] += fElements[srcRow][i] * factor; + + return true; +} + +void QcDenseMatrix::FractionRow(unsigned row, numT factor) +{ + qcAssertPre (row < fRows); + + if (QcUtility::IsOne(factor)) + return; + + for (unsigned i = 0; i < fColumns; i++) + fElements[row][i] /= factor; +} + +void QcDenseMatrix::Pivot(unsigned row, unsigned col) +{ + qcAssertPre( row < getNRows()); + qcAssertPre( col < getNColumns()); + + numT p = fElements[row][col]; + qcAssertPre( !QcUtility::IsZero( p)); + + ScaleRow( row, recip( p)); + + for (QcDenseMatrixColIterator colItr( *this, col); + !colItr.AtEnd(); + colItr.Increment()) + { + if (colItr.getIndex() != row) + AddScaledRow( colItr.getIndex(), row, -colItr.getValue()); + } + +#ifdef qcCheckInternalPost + qcAssertPost( QcUtility::IsOne( GetValue( row, col))); + for (unsigned i = getNRows(); i--;) + if (i != row) + qcAssertPost( QcUtility::IsZero( GetValue( i, col))); +#endif +} + +void QcDenseMatrix::Reserve(unsigned rows, unsigned cols) +{ + numT **e; + numT *e1 = 0; + + qcAssert(fAllocRows >= fRows); + qcAssert(fAllocColumns >= fColumns); + + // Add new columns to existing rows + if (cols > fAllocColumns) { + // Extend rows which need copying of values + for (unsigned i = 0; i < fRows; i++) { + if (fAllocColumns > 0) + e1 = fElements[i]; + + fElements[i] = new numT[cols]; + memcpy(fElements[i], e1, sizeof(numT) * fColumns); + + if (fAllocColumns > 0) + delete [] e1; + } + + // Extend rows which are presently allocated but unused + for (unsigned i = fRows; i < fAllocRows; i++) { + if (fAllocColumns > 0) + delete[] fElements[i]; + fElements[i] = new numT[cols]; + } + fAllocColumns = cols; + } + + // Copy existing and Allocate new rows + if (rows > fAllocRows) { + e = new numT*[rows]; // Allocate a new row vector + + // Copy old rows. + if (fAllocRows > 0) { + memcpy(e, fElements, sizeof(numT) * fAllocRows); + delete[] fElements; // free the old row vector + } + + fElements = e; // matrix now uses the new row vector + + // Allocate new rows + for (unsigned i = fAllocRows; i < rows; i++) + fElements[i] = new numT[fAllocColumns]; + + fAllocRows = rows; + } + + qcAssertPost (fAllocRows >= rows); + qcAssertPost (fAllocColumns >= cols); + dbg(assertInvar()); +} + +void QcDenseMatrix::Resize(unsigned rows, unsigned cols) +{ + if (rows > fAllocRows || cols > fAllocColumns) + Reserve(rows, cols); + + // Initialise newly exposed columns of existing rows + for (unsigned i = 0; i < fRows; i++) + for (unsigned j = fColumns; j < cols; j++) + fElements[i][j] = 0.0; + + // Initialise newly exposed rows + for (unsigned i = fRows; i < rows; i++) + for (unsigned j = 0; j < cols; j++) + fElements[i][j] = 0.0; + + fRows = rows; + fColumns = cols; + dbg(assertInvar()); +} + +bool QcDenseMatrix::ScaleRow(unsigned row, numT factor) +{ + if (QcUtility::IsOne( factor)) + return false; + + for (unsigned i = 0; i < fColumns; i++) + fElements[row][i] *= factor; + + return true; +} + +void QcDenseMatrix::SwapColumns(unsigned c1, unsigned c2) +{ + numT temp; + + for (unsigned i = 0; i < fRows; i++) { + temp = fElements[i][c1]; + fElements[i][c1] = fElements[i][c2]; + fElements[i][c2] = temp; + } +} + +#ifdef KEEP_DENSE_SHADOW +void QcDenseMatrix::CopyColumn(unsigned destCol, unsigned srcCol) +{ + qcAssertPre( destCol < getNColumns()); + qcAssertPre( srcCol < getNColumns()); + + for (unsigned i = 0; i < fRows; i++) + fElements[i][destCol] = fElements[i][srcCol]; +} + +void QcDenseMatrix::CopyRow(unsigned destRow, + QcDenseMatrix const &srcMatrix, unsigned srcRow) +{ + qcAssertPre( destRow < getNRows()); + qcAssertPre( srcRow < getNRows()); + + for (unsigned j = 0; j < fColumns; j++) + fElements[destRow][j] = srcMatrix.fElements[srcRow][j]; +} +#endif + +#if 0 /* unused */ +void QcDenseMatrix::SwapRows(unsigned r1, unsigned r2) +{ + numT temp; + + for (unsigned i = 0; i < fColumns; i++) { + temp = fElements[r1][i]; + fElements[r1][i] = fElements[r2][i]; + fElements[r2][i] = temp; + } +} +#endif /* unused */ + +void QcDenseMatrix::Zero() +{ + for (unsigned i = 0; i < fRows; i++) + for (unsigned j = 0; j < fColumns; j++) + fElements[i][j] = 0.0; +} + +void QcDenseMatrix::ZeroColumn(unsigned col) +{ + for (unsigned i = 0; i < fRows; i++) + fElements[i][col] = 0.0; +} + +void QcDenseMatrix::ZeroRow(unsigned row) +{ + for (unsigned i = 0; i < fColumns; i++) + fElements[row][i] = 0.0; +} diff --git a/src/kits/interface/qoca/QcDenseMatrix.hh b/src/kits/interface/qoca/QcDenseMatrix.hh new file mode 100644 index 0000000000..5a2a5cf4de --- /dev/null +++ b/src/kits/interface/qoca/QcDenseMatrix.hh @@ -0,0 +1,115 @@ +// $Id: QcDenseMatrix.hh,v 1.10 2001/01/30 01:32:07 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDenseMatrixH +#define __QcDenseMatrixH + +#include "qoca/QcDefines.hh" +#ifdef qcBoundsChecks +# include // NAN +#endif +#include "qoca/QcMatrix.hh" + +class QcDenseMatrixIterator; + +class QcDenseMatrix : public QcMatrix +{ +public: + numT **fElements; + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcDenseMatrix(); + virtual ~QcDenseMatrix(); + + //-----------------------------------------------------------------------// + // Enquiry functions. // + //-----------------------------------------------------------------------// + virtual numT GetValue(unsigned row, unsigned col) const; + + //-----------------------------------------------------------------------// + // Matrix size management functions. // + //-----------------------------------------------------------------------// + virtual void Reserve(unsigned rows, unsigned cols); + // Ensure that future resizes up to these limits will take + // place in constant time - i.e. preallocate if necessary. + virtual void Resize(unsigned rows, unsigned cols); + // Change the size of the used part of the array up or down. + // Increases may take time up to O(rows * cols). + + //-----------------------------------------------------------------------// + // Basic matrix data management functions. // + //-----------------------------------------------------------------------// + + //virtual void IncreaseValue(unsigned row, unsigned col, numT inc) + // { fElements[row][col] += inc; } + + virtual void SetValue(unsigned row, unsigned col, numT val); + virtual void SwapColumns(unsigned c1, unsigned c2); + +#ifdef KEEP_DENSE_SHADOW + void CopyColumn(unsigned destCol, unsigned srcCol); + void CopyRow(unsigned destRow, QcDenseMatrix const &srcMatrix, unsigned srcRow); +#endif + //virtual void SwapRows(unsigned r1, unsigned r2); + + virtual void Zero(); + virtual void ZeroColumn(unsigned col); + virtual void ZeroRow(unsigned row); + + //-----------------------------------------------------------------------// + // Numerical computation functions. // + //-----------------------------------------------------------------------// + //virtual void AddRow(unsigned destRow, unsigned srcRow); + virtual bool AddScaledRow(unsigned destRow, unsigned srcRow, numT factor); + virtual void FractionRow(unsigned row, numT factor); + virtual void Pivot(unsigned row, unsigned col); + virtual bool ScaleRow(unsigned row, numT factor); +}; + +inline QcDenseMatrix::QcDenseMatrix() + : QcMatrix(), fElements(0) +{ +} + +inline numT QcDenseMatrix::GetValue(unsigned row, unsigned col) const +{ + qcAssertPre (row < fRows); + qcAssertPre (col < fColumns); + + return fElements[row][col]; +} + +inline void QcDenseMatrix::SetValue(unsigned row, unsigned col, numT val) +{ + qcAssertPre (row < fRows); + qcAssertPre (col < fColumns); + + fElements[row][col] = val; +} + +#endif /* !__QcDenseMatrixH */ diff --git a/src/kits/interface/qoca/QcDenseMatrixColIterator.hh b/src/kits/interface/qoca/QcDenseMatrixColIterator.hh new file mode 100644 index 0000000000..97107c9c91 --- /dev/null +++ b/src/kits/interface/qoca/QcDenseMatrixColIterator.hh @@ -0,0 +1,71 @@ +// $Id: QcDenseMatrixColIterator.hh,v 1.5 2000/11/24 12:16:21 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDenseMatrixColIteratorH +#define __QcDenseMatrixColIteratorH + +#include "qoca/QcDenseMatrixIterator.hh" +#include "qoca/QcUtility.hh" + +class QcDenseMatrixColIterator : public QcDenseMatrixIterator +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcDenseMatrixColIterator(const QcDenseMatrix &m, unsigned col); + + //-----------------------------------------------------------------------// + // Iteration functions. // + //-----------------------------------------------------------------------// + virtual void Advance(); + virtual bool AtEnd() const + // Returns true iff the iterator is past the end of its row or column. + { return fIndex == fMatrix.getNRows(); } +}; + +inline QcDenseMatrixColIterator::QcDenseMatrixColIterator( + const QcDenseMatrix &m, unsigned col) + : QcDenseMatrixIterator(m, col) +{ + qcAssertPre (col < m.getNColumns()); + + Reset(); +} + +inline void QcDenseMatrixColIterator::Advance() +{ + qcAssertPre (fIndex <= fMatrix.getNRows()); + + while (fIndex < fMatrix.getNRows()) { + fValue = fMatrix.fElements[fIndex][fVector]; + if (!QcUtility::IsZero(fValue)) + break; + fIndex++; + } +} + +#endif /* !__QcDenseMatrixColIteratorH */ diff --git a/src/kits/interface/qoca/QcDenseMatrixIterator.hh b/src/kits/interface/qoca/QcDenseMatrixIterator.hh new file mode 100644 index 0000000000..bc2353c41f --- /dev/null +++ b/src/kits/interface/qoca/QcDenseMatrixIterator.hh @@ -0,0 +1,72 @@ +// $Id: QcDenseMatrixIterator.hh,v 1.5 2000/11/24 12:16:21 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDenseMatrixIteratorH +#define __QcDenseMatrixIteratorH + +#include "qoca/QcMatrixIterator.hh" +#include "qoca/QcDenseMatrix.hh" + +class QcDenseMatrixIterator : public QcMatrixIterator +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcDenseMatrixIterator(const QcDenseMatrix &m, unsigned vec); + + //-----------------------------------------------------------------------// + // Iteration functions. // + //-----------------------------------------------------------------------// + virtual void Advance() = 0; + virtual void Increment(); + virtual void Reset(); + +protected: + const QcDenseMatrix &fMatrix; +}; + +inline QcDenseMatrixIterator::QcDenseMatrixIterator(const QcDenseMatrix &m, + unsigned vec) + : QcMatrixIterator(vec), fMatrix(m) +{ +} + +inline void QcDenseMatrixIterator::Increment() +{ + qcAssertPre (!AtEnd()); + + fIndex++; + Advance(); +} + +inline void QcDenseMatrixIterator::Reset() +{ + fIndex = 0; + Advance(); +} + +#endif diff --git a/src/kits/interface/qoca/QcDenseMatrixRowIterator.hh b/src/kits/interface/qoca/QcDenseMatrixRowIterator.hh new file mode 100644 index 0000000000..501e52bf9e --- /dev/null +++ b/src/kits/interface/qoca/QcDenseMatrixRowIterator.hh @@ -0,0 +1,69 @@ +// $Id: QcDenseMatrixRowIterator.hh,v 1.5 2001/01/30 01:32:07 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDenseMatrixRowIteratorH +#define __QcDenseMatrixRowIteratorH + +#include "qoca/QcDenseMatrixIterator.hh" + +class QcDenseMatrixRowIterator : public QcDenseMatrixIterator +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcDenseMatrixRowIterator(const QcDenseMatrix &m, unsigned row); + + //-----------------------------------------------------------------------// + // Iteration functions. // + //-----------------------------------------------------------------------// + virtual void Advance(); + virtual bool AtEnd() const + { return fIndex == fMatrix.getNColumns(); } +}; + +inline QcDenseMatrixRowIterator::QcDenseMatrixRowIterator( + const QcDenseMatrix &m, unsigned row) + : QcDenseMatrixIterator(m, row) +{ + qcAssertPre (row < m.getNRows()); + + Reset(); +} + +inline void QcDenseMatrixRowIterator::Advance() +{ + qcAssertPre (fIndex <= fMatrix.getNColumns()); + + while (fIndex < fMatrix.getNColumns()) { + fValue = fMatrix.fElements[fVector][fIndex]; + if (!QcUtility::IsZero( fValue)) + break; + fIndex++; + } +} + +#endif diff --git a/src/kits/interface/qoca/QcDenseTableauColIterator.hh b/src/kits/interface/qoca/QcDenseTableauColIterator.hh new file mode 100644 index 0000000000..03da50c496 --- /dev/null +++ b/src/kits/interface/qoca/QcDenseTableauColIterator.hh @@ -0,0 +1,71 @@ +// $Id: QcDenseTableauColIterator.hh,v 1.5 2000/11/24 12:24:47 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDenseTableauColIteratorH +#define __QcDenseTableauColIteratorH + +#include "qoca/QcDenseTableauIterator.hh" + +class QcDenseTableauColIterator : public QcDenseTableauIterator +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + + /** @precondition col < tab.getNColumns() */ + QcDenseTableauColIterator (const QcLinEqTableau &tab, unsigned col); + + //-----------------------------------------------------------------------// + // Iteration functions. // + //-----------------------------------------------------------------------// + virtual void Advance(); +}; + +inline QcDenseTableauColIterator::QcDenseTableauColIterator( + const QcLinEqTableau &tab, unsigned col) + : QcDenseTableauIterator(tab, col, tab.getNRows()) +{ + qcAssertPre (col < fTableau.getNColumns()); + + Reset(); + dbg(assertInvar()); +} + +inline void QcDenseTableauColIterator::Advance() +{ + assert (fIndex <= fEnd); + assert (fVector < fTableau.getNColumns()); + assert (fEnd <= fTableau.getNRows()); + while (fIndex < fEnd) { + fValue = fTableau.GetValue(fIndex, fVector); + if (!QcUtility::IsZero(fValue)) + break; + fIndex++; + } + dbg(assertInvar()); +} +#endif diff --git a/src/kits/interface/qoca/QcDenseTableauIterator.hh b/src/kits/interface/qoca/QcDenseTableauIterator.hh new file mode 100644 index 0000000000..8d226530f0 --- /dev/null +++ b/src/kits/interface/qoca/QcDenseTableauIterator.hh @@ -0,0 +1,118 @@ +// $Id: QcDenseTableauIterator.hh,v 1.6 2000/12/06 05:32:56 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDenseTableauIteratorH +#define __QcDenseTableauIteratorH + +#include "qoca/QcLinEqTableau.hh" +#include "qoca/QcIterator.hh" + +class QcDenseTableauIterator : public QcIterator +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcDenseTableauIterator(const QcLinEqTableau &tab, + unsigned vec, unsigned end); + +#ifndef NDEBUG + void assertInvar() const + { + assert (fIndex <= fEnd); + } +#endif + + //-----------------------------------------------------------------------// + // Enquiry functions. // + //-----------------------------------------------------------------------// + int GetIndex() const + { return (int) fIndex; } + + unsigned getIndex() const + { return fIndex; } + + numT GetValue() const + { + qcAssertPre (!AtEnd()); + return fValue; + } + + numT getValue() const + { + qcAssertPre (!AtEnd()); + return fValue; + } + + //------------------------------------------------------------------------// + // Iteration functions. // + //------------------------------------------------------------------------// + virtual void Advance() = 0; + virtual void Increment(); + virtual void Reset(); + virtual void SetToBeginOf(unsigned i); + virtual bool AtEnd() const + { return fIndex == fEnd; } + +protected: + unsigned fIndex; + numT fValue; + unsigned fVector; + unsigned fEnd; + const QcLinEqTableau &fTableau; +}; + +inline QcDenseTableauIterator::QcDenseTableauIterator( + const QcLinEqTableau &tab, unsigned vec, unsigned end) + : fIndex (0), + fValue(), + fVector (vec), + fEnd (end), + fTableau (tab) +{ + dbg(assertInvar()); +} + +inline void QcDenseTableauIterator::Increment() +{ + qcAssertPre (!AtEnd()); + fIndex++; + Advance(); +} + +inline void QcDenseTableauIterator::Reset() +{ + fIndex = 0; + Advance(); +} + +inline void QcDenseTableauIterator::SetToBeginOf(unsigned i) +{ + fVector = i; + Reset(); +} + +#endif diff --git a/src/kits/interface/qoca/QcDenseTableauRowIterator.hh b/src/kits/interface/qoca/QcDenseTableauRowIterator.hh new file mode 100644 index 0000000000..ae112b4066 --- /dev/null +++ b/src/kits/interface/qoca/QcDenseTableauRowIterator.hh @@ -0,0 +1,72 @@ +// $Id: QcDenseTableauRowIterator.hh,v 1.5 2000/11/24 12:24:47 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDenseTableauRowIteratorH +#define __QcDenseTableauRowIteratorH + +#include "qoca/QcDenseTableauIterator.hh" + +class QcDenseTableauRowIterator : public QcDenseTableauIterator +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + + /** @precondition row < tab.getNRows() */ + QcDenseTableauRowIterator (const QcLinEqTableau &tab, unsigned row); + + //-----------------------------------------------------------------------// + // Iteration functions. // + //-----------------------------------------------------------------------// + virtual void Advance(); +}; + +inline QcDenseTableauRowIterator::QcDenseTableauRowIterator( + const QcLinEqTableau &tab, unsigned row) + : QcDenseTableauIterator(tab, row, tab.getNColumns()) +{ + qcAssertPre (row < fTableau.getNRows()); + + Reset(); + dbg(assertInvar()); +} + +inline void QcDenseTableauRowIterator::Advance() +{ + assert (fIndex <= fEnd); + assert (fVector < fTableau.getNRows()); + assert (fEnd <= fTableau.getNColumns()); + while (fIndex < fEnd) { + fValue = fTableau.GetValue(fVector, fIndex); + if (!QcUtility::IsZero(fValue)) + break; + fIndex++; + } + dbg(assertInvar()); +} + +#endif diff --git a/src/kits/interface/qoca/QcDesireValueStore.hh b/src/kits/interface/qoca/QcDesireValueStore.hh new file mode 100644 index 0000000000..2e97e646cd --- /dev/null +++ b/src/kits/interface/qoca/QcDesireValueStore.hh @@ -0,0 +1,72 @@ +// $Id: QcDesireValueStore.hh,v 1.4 2000/12/11 07:48:23 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcDesireValueStoreH +#define __QcDesireValueStoreH + +#include + +class QcDesireValueStore +{ +public: + //-----------------------------------------------------------------------// + // Constructors + //-----------------------------------------------------------------------// + + /* Used by vector as default initializer. */ + QcDesireValueStore() + : fVariablePtr( 0), + fDesValue() + { } + + QcDesireValueStore( QcFloatRep *vr) + : fVariablePtr( vr), + fDesValue( vr->DesireValue()) + { } + + //-----------------------------------------------------------------------// + // Manipulation function. // + //-----------------------------------------------------------------------// + void Restore() + { fVariablePtr->SuggestValue( fDesValue); } + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + void Print(ostream &os) const; + +private: + QcFloatRep *fVariablePtr; + numT fDesValue; +}; + +inline void QcDesireValueStore::Print(ostream &os) const +{ + fVariablePtr->Print( os); + os << ":" << fDesValue; +} + +#endif /* !__QcDesireValueStoreH */ diff --git a/src/kits/interface/qoca/QcEnables.H b/src/kits/interface/qoca/QcEnables.H new file mode 100644 index 0000000000..17b55d0c3d --- /dev/null +++ b/src/kits/interface/qoca/QcEnables.H @@ -0,0 +1,8 @@ +#ifndef QcEnables_H +#define QcEnables_H + +//#define NDEBUG 1 + +//#define QC_USING_NLPSOLVER 1 + +#endif /* !QcEnables_H */ diff --git a/src/kits/interface/qoca/QcEnables.H.in b/src/kits/interface/qoca/QcEnables.H.in new file mode 100644 index 0000000000..9276548683 --- /dev/null +++ b/src/kits/interface/qoca/QcEnables.H.in @@ -0,0 +1,8 @@ +#ifndef QcEnables_H +#define QcEnables_H + +@QC_NDEBUG_COM@#define NDEBUG 1 + +@NLPSOLVER_COM@#define QC_USING_NLPSOLVER 1 + +#endif /* !QcEnables_H */ diff --git a/src/kits/interface/qoca/QcException.hh b/src/kits/interface/qoca/QcException.hh new file mode 100644 index 0000000000..d35191d148 --- /dev/null +++ b/src/kits/interface/qoca/QcException.hh @@ -0,0 +1,224 @@ +// $Id: QcException.hh,v 1.3 2000/11/21 04:26:12 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcExceptionH +#define __QcExceptionH + +#include +#include "qoca/QcDefines.hh" + +#ifndef qcNoStream +#include +#endif + +//#ifdef DEBUG +//void QcBreak(int); // For trapping warnings when using debugger +//#else +#define QcBreak(x) +//#endif + +#ifdef qcUseExceptions +class QcError +{ +public: + QcError(const char *m) + : fMessage(m), fFile(0), fLine(-1), fIndex(-1), fRange(-1) + { QcBreak(1); } + + QcError(const char *f, int ln) + : fMessage("Assertion failed"), fFile(f), fLine(ln), fIndex(-1), + fRange(-1) + { QcBreak(2); } + + QcError(const char *f, int ln, const char *m) + : fMessage(m), fFile(f), fLine(ln), fIndex(-1), fRange(-1) + { QcBreak(3); } + + QcError(const char *m, int i, int r) + : fMessage(m), fFile(0), fLine(-1), fIndex(i), fRange(r) + { QcBreak(4); } + + QcError(const char *f, int ln, const char *m, int i, int r) + : fMessage(m), fFile(f), fLine(ln), fIndex(i), fRange(r) + { QcBreak(5); } + +private: + const char *fMessage; + const char *fFile; + const int fLine; + const int fIndex; + const int fRange; +}; +#endif + +#ifdef qcUseExceptions +class QcWarning : public QcError +{ +public: + QcWarning(const char *m) + : QcError(m) + { } + + QcWarning(const char *file, int line, const char *m) + : QcError(file, line, m) + { } + + QcWarning(const char *m, int i, int r) + : QcError(m, i, r) + { } + + QcWarning(const char *file, int line, int i, int r) + : QcError(file, line, 0, i, r) + { } + + QcWarning(const char *file, int line, const char *m, int i, int r) + : QcError(file, line, m, i, r) + { } +}; +#else +#define throw +class QcWarning +{ +public: + QcWarning(const char *m); + QcWarning(const char *file, int line, const char *m); + QcWarning(const char *m, int i, int r); + QcWarning(const char *file, int line, int i, int r); + QcWarning(const char *file, int line, const char *m, int i, int r); +}; + +inline QcWarning::QcWarning(const char *m) +{ + cout << "Warning: " << m << endl; + QcBreak(1); +} + +inline Warning::Warning(const char *file, int line, const char *m) +{ + cout << "Warning: " << m; + cout << ", at line " << line << " of " << file << endl; + QcBreak(2); +} + +inline Warning::Warning(const char *m, int i, int r) +{ + cout << "Warning: " << m + << ", index " << i << ", range (0," << r << ")" << endl; + QcBreak(3); +} + +inline Warning::Warning(const char *file, int line, int i, int r) +{ + cout << "Warning: out of bounds, index " << i << ", range (0,"; + cout << r << ") at line " << line << " of " << file << endl; + QcBreak(4); +} + +inline Warning::Warning(const char *file, int line, const char *m, int i, int r) +{ + cout << "Warning: " << m << ", index " << i << ", range (0,"; + cout << r << ") at line " << line << " of " << file << endl; + QcBreak(5); +} +#endif + +#ifdef qcUseExceptions +class QcFatal : public QcError +{ +public: + QcFatal(const char *m) + : QcError(m) + { } + + QcFatal(const char *file, int line, const char *m) + : QcError(file, line, m) + { } + + QcFatal(const char *m, int i, int r) + : QcError(m, i, r) + { } + + QcFatal(const char *file, int line, int i, int r) + : QcError(file, line, 0, i, r) + { } + + QcFatal(const char *file, int line, const char *m, int i, int r) + : QcError(file, line, m, i, r) + { } +}; +#else +#define throw +class QcFatal +{ +public: + QcFatal(const char *m); + QcFatal(const char *file, int line, const char *m); + QcFatal(const char *m, int i, int r); + QcFatal(const char *file, int line, int i, int r); + QcFatal(const char *file, int line, const char *m, int i, int r); +}; + +inline QcFatal::QcFatal(const char *m) +{ + cout << "QcFatal error: " << m << endl; + QcBreak(6); + exit(1); +} + +inline QcFatal::QcFatal(const char *file, int line, const char *m) +{ + cout << "QcFatal error: " << m; + cout << ", at line " << line << " of " << file << endl; + QcBreak(7); + exit(1); +} + +inline QcFatal::QcFatal(const char *m, int i, int r) +{ + cout << "QcFatal error: " << m + << ", index " << i << ", range (0," << r << ")" << endl; + QcBreak(8); + exit(1); +} + +inline QcFatal::QcFatal(const char *file, int line, int i, int r) +{ + cout << "QcFatal error: out of bounds, index " << i << ", range (0,"; + cout << r << ") at line " << line << " of " << file << endl; + QcBreak(9); + exit(1); +} + +inline QcFatal::QcFatal(const char *file, int line, const char *m, int i, int r) +{ + cout << "QcFatal error: " << m << ", index " << i << ", range (0,"; + cout << r << ") at line " << line << " of " << file << endl; + QcBreak(10); + exit(1); +} +#endif + +#endif diff --git a/src/kits/interface/qoca/QcFixedFloat.hh b/src/kits/interface/qoca/QcFixedFloat.hh new file mode 100644 index 0000000000..c6c8ac6765 --- /dev/null +++ b/src/kits/interface/qoca/QcFixedFloat.hh @@ -0,0 +1,69 @@ +// $Id: QcFixedFloat.hh,v 1.5 2000/12/11 05:46:48 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcFixedFloatH +#define __QcFixedFloatH + +#include "qoca/QcDefines.hh" +#include "qoca/QcFixedFloatRep.hh" +#include "qoca/QcFloat.hh" + +class QcFixedFloat : public QcFloat +{ +public: + //-----------------------------------------------------------------------// + // Constructor // + //-----------------------------------------------------------------------// + QcFixedFloat(bool restricted = false); + QcFixedFloat(const char *name, bool restricted = false); + QcFixedFloat(const char *name, numT desval, bool restricted = false); + QcFixedFloat(const char *name, numT desval, numT w, + bool restricted = false); +}; + +inline QcFixedFloat::QcFixedFloat(bool restricted) + : QcFloat(*new QcFixedFloatRep(restricted)) +{ +} + +inline QcFixedFloat::QcFixedFloat(const char *name, bool restricted) + : QcFloat(*new QcFixedFloatRep(name, restricted)) +{ +} + +inline QcFixedFloat::QcFixedFloat(const char *name, numT desval, + bool restricted) + : QcFloat(*new QcFixedFloatRep(name, desval, restricted)) +{ +} + +inline QcFixedFloat::QcFixedFloat(const char *name, numT desval, numT w, + bool restricted) + : QcFloat(*new QcFixedFloatRep(name, desval, w, restricted)) +{ +} + +#endif diff --git a/src/kits/interface/qoca/QcFixedFloatRep.H b/src/kits/interface/qoca/QcFixedFloatRep.H new file mode 100644 index 0000000000..fc84ca5c03 --- /dev/null +++ b/src/kits/interface/qoca/QcFixedFloatRep.H @@ -0,0 +1,77 @@ +// Generated automatically from QcFixedFloatRep.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcFixedFloatRepDCL +#define QcFixedFloatRepDCL +#line 1 "QcFixedFloatRep.ch" +// $Id: QcFixedFloatRep.ch,v 1.7 2000/12/12 09:59:27 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include + + +#define qcDefaultFixedWeight 5000.0 + +class QcFixedFloatRep + : public QcFloatRep +{ +public: + + +//-----------------------------------------------------------------------// +// Constructor // +//-----------------------------------------------------------------------// +QcFixedFloatRep(bool restricted); +QcFixedFloatRep(const char *name, bool restricted); +QcFixedFloatRep(const char *name, numT desval, bool restricted); +QcFixedFloatRep(const char *name, numT desval, numT w, bool restricted); + + +//-----------------------------------------------------------------------// +// Manipulatiom functions. // +//-----------------------------------------------------------------------// + +virtual void RestDesVal(); +#line 57 "QcFixedFloatRep.ch" +virtual bool RestDesVal_changed(); +#line 63 "QcFixedFloatRep.ch" +virtual void SetToEditWeight(); +#line 68 "QcFixedFloatRep.ch" +virtual void SetToStayWeight(); +#line 72 "QcFixedFloatRep.ch" +}; + + +#line 113 "QcFixedFloatRep.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcFixedFloatRepDCL */ diff --git a/src/kits/interface/qoca/QcFixedFloatRep.cc b/src/kits/interface/qoca/QcFixedFloatRep.cc new file mode 100644 index 0000000000..25333e896b --- /dev/null +++ b/src/kits/interface/qoca/QcFixedFloatRep.cc @@ -0,0 +1,78 @@ +// Generated automatically from QcFixedFloatRep.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcFixedFloatRep.hh" +#line 1 "QcFixedFloatRep.ch" +// $Id: QcFixedFloatRep.ch,v 1.7 2000/12/12 09:59:27 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include + + + +#define qcDefaultFixedWeight 5000.0 + + + + + + + +#line 48 "QcFixedFloatRep.ch" +//-----------------------------------------------------------------------// +// Manipulatiom functions. // +//-----------------------------------------------------------------------// + +void QcFixedFloatRep::RestDesVal() +{ +} + + +bool QcFixedFloatRep::RestDesVal_changed() +{ + return false; +} + + +void QcFixedFloatRep::SetToEditWeight() +{ +} + + +void QcFixedFloatRep::SetToStayWeight() +{ +} + + + + +#line 113 "QcFixedFloatRep.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcFixedFloatRep.ch b/src/kits/interface/qoca/QcFixedFloatRep.ch new file mode 100644 index 0000000000..41ade76f4d --- /dev/null +++ b/src/kits/interface/qoca/QcFixedFloatRep.ch @@ -0,0 +1,120 @@ +// $Id: QcFixedFloatRep.ch,v 1.7 2000/12/12 09:59:27 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +//o[d] #include +//o[i] #include + +#define qcDefaultFixedWeight 5000.0 + +//ho class QcFixedFloatRep +//ho : public QcFloatRep +//ho { +//ho public: + +//begin o[d] +//-----------------------------------------------------------------------// +// Constructor // +//-----------------------------------------------------------------------// +QcFixedFloatRep(bool restricted); +QcFixedFloatRep(const char *name, bool restricted); +QcFixedFloatRep(const char *name, numT desval, bool restricted); +QcFixedFloatRep(const char *name, numT desval, numT w, bool restricted); +//end o[d] + +//-----------------------------------------------------------------------// +// Manipulatiom functions. // +//-----------------------------------------------------------------------// +//cf +virtual void RestDesVal() +{ +} + +//cf +virtual bool RestDesVal_changed() +{ + return false; +} + +//cf +virtual void SetToEditWeight() +{ +} + +//cf +virtual void SetToStayWeight() +{ +} + +//ho }; + +//begin o[i] +inline QcFixedFloatRep::QcFixedFloatRep(bool restricted) + : QcFloatRep("", 0.0, qcDefaultFixedWeight, qcDefaultFixedWeight, + restricted) +{ +#if qcReportAlloc + cerr << "inited fixed " << this << endl; +#endif +} + +inline QcFixedFloatRep::QcFixedFloatRep(const char *name, bool restricted) + : QcFloatRep(name, 0.0, qcDefaultFixedWeight, qcDefaultFixedWeight, + restricted) +{ +#if qcReportAlloc + cerr << "inited fixed " << this << endl; +#endif +} + +inline QcFixedFloatRep::QcFixedFloatRep(const char *name, numT desval, + bool restricted) + : QcFloatRep(name, desval, qcDefaultFixedWeight, + qcDefaultFixedWeight, restricted) +{ +#if qcReportAlloc + cerr << "inited fixed " << this << endl; +#endif +} + +inline QcFixedFloatRep::QcFixedFloatRep(const char *name, numT desval, + numT w, bool restricted) + : QcFloatRep(name, desval, w, w, restricted) +{ +#if qcReportAlloc + cerr << "inited fixed " << this << endl; +#endif +} +//end o[i] + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcFixedFloatRep.hh b/src/kits/interface/qoca/QcFixedFloatRep.hh new file mode 100644 index 0000000000..260c7c676c --- /dev/null +++ b/src/kits/interface/qoca/QcFixedFloatRep.hh @@ -0,0 +1,97 @@ +// Generated automatically from QcFixedFloatRep.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcFixedFloatRep.H" +#ifndef QcFixedFloatRepIFN +#define QcFixedFloatRepIFN +#line 1 "QcFixedFloatRep.ch" +// $Id: QcFixedFloatRep.ch,v 1.7 2000/12/12 09:59:27 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include + +#include + +#define qcDefaultFixedWeight 5000.0 + + + + + + + +#line 48 "QcFixedFloatRep.ch" +//-----------------------------------------------------------------------// +// Manipulatiom functions. // +//-----------------------------------------------------------------------// + +#line 75 "QcFixedFloatRep.ch" +inline QcFixedFloatRep::QcFixedFloatRep::QcFixedFloatRep(bool restricted) + : QcFloatRep("", 0.0, qcDefaultFixedWeight, qcDefaultFixedWeight, + restricted) +{ +#if qcReportAlloc + cerr << "inited fixed " << this << endl; +#endif +} + +inline QcFixedFloatRep::QcFixedFloatRep::QcFixedFloatRep(const char *name, bool restricted) + : QcFloatRep(name, 0.0, qcDefaultFixedWeight, qcDefaultFixedWeight, + restricted) +{ +#if qcReportAlloc + cerr << "inited fixed " << this << endl; +#endif +} + +inline QcFixedFloatRep::QcFixedFloatRep::QcFixedFloatRep(const char *name, numT desval, + bool restricted) + : QcFloatRep(name, desval, qcDefaultFixedWeight, + qcDefaultFixedWeight, restricted) +{ +#if qcReportAlloc + cerr << "inited fixed " << this << endl; +#endif +} + +inline QcFixedFloatRep::QcFixedFloatRep::QcFixedFloatRep(const char *name, numT desval, + numT w, bool restricted) + : QcFloatRep(name, desval, w, w, restricted) +{ +#if qcReportAlloc + cerr << "inited fixed " << this << endl; +#endif +} + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcFixedFloatRepIFN */ diff --git a/src/kits/interface/qoca/QcFloat.hh b/src/kits/interface/qoca/QcFloat.hh new file mode 100644 index 0000000000..55d726a5b5 --- /dev/null +++ b/src/kits/interface/qoca/QcFloat.hh @@ -0,0 +1,373 @@ +// $Id: QcFloat.hh,v 1.15 2000/12/14 02:28:54 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// This class provides the only mechanism to create cfloats and the // +// constructors return a handle. The semantics of cfloat handles are sharing // +// on assignment with automatic destruction when the last handle is lost. // +// The handles are implemented to use a representation that fits in a single // +// word. Handles are therefore quite efficient to pass by value. Pass // +// handles by reference where efficiency is critical. It is intended that // +// clients be able to derive classes from QcFloat and be able to // +// override most public methods. // +//============================================================================// + +#ifndef __QcFloatH +#define __QcFloatH + +#if HAVE_LROUND || HAVE_LRINT || HAVE_ROUND +# define _ISOC9X_SOURCE 1 +#endif +#if HAVE_LROUND || HAVE_LRINT || HAVE_ROUND || HAVE_RINT +# include +#endif +#include "qoca/QcDefines.hh" +#include "qoca/QcFloatRep.hh" +#include "qoca/QcNullableElement.hh" +#include "qoca/QcNomadicFloatRep.hh" + +#define subclassOfNullable 0 +class QcFloat +#if subclassOfNullable + : QcNullableElement +#endif +{ +public: + friend class QcNullableElement; + + //-----------------------------------------------------------------------// + // Constructors // + //-----------------------------------------------------------------------// + explicit QcFloat(QcFloatRep *ptr); + explicit QcFloat(QcFloatRep &rep); + explicit QcFloat(bool restricted = false); + explicit QcFloat(const char *name, bool restricted = false); + QcFloat(const char *name, numT desval, bool restricted = false); + QcFloat(const char *name, numT desval, numT sw, numT ew, + bool restricted = false); + QcFloat(const QcFloat &other); + //QcFloat(QcNullableElement const &other); + + ~QcFloat() + { Decrease(); } + + void assertInvar() const + { + qcAssertInvar(fRep != 0); + fRep->assertInvar(); + } + + //-----------------------------------------------------------------------// + // Data structure access functions // + //-----------------------------------------------------------------------// + QcFloatRep *pointer() const + { return fRep; } + +#if 0 + const QcFloatRep &Rep() const + { return *fRep; } + + const QcFloatRep &getRep() const + { return *fRep; } +#endif + + +#if NUMT_IS_DOUBLE +# ifdef HAVE_LROUND +# define Round(_x) lround (_x) +# elif HAVE_LRINT +# define Round(_x) lrint (_x) +# elif HAVE_ROUND +# define Round(_x) ((long) round (_x)) +# elif HAVE_RINT +# define Round(_x) ((long) rint (_x)) +# else +private: + static inline long Round (double x) + { + return long (x > 0.0 + ? x + 0.5 + : x - 0.5); + } +public: +# endif +#elif NUMT_IS_PJM_MPQ +# define Round(_x) ((_x).get_lround()) +#else +# error "Unknown numT" +#endif + + + //-----------------------------------------------------------------------// + // Query functions // + //-----------------------------------------------------------------------// + long Counter() const + { return (long)fRep->Counter(); } + + numT DesireValue() const + { return fRep->DesireValue(); } + + numT EditWeight() const + { return fRep->EditWeight(); } + + QcFloatRep::TId Id() const + { return fRep->Id(); } + + QcFloatRep::TId getId() const + { return fRep->Id(); } + + long IntDesireValue() const + { return Round(fRep->DesireValue()); } + + long IntValue() const + { return Round(fRep->Value()); } + + bool IsRestricted() const + { return fRep->IsRestricted(); } + + const char *Name() const + { return fRep->Name(); } + + numT StayWeight() const + { return fRep->StayWeight(); } + + numT Weight() const + { return fRep->Weight(); } + + numT Value() const + { return GetValue(); } + numT GetValue() const + { return fRep->Value(); } + + bool operator <(const QcFloat &other) const + { return *fRep < *other.fRep; } + + /* FIXME: Is it a problem that these compare pointers whereas `<' compares ids? + E.g. is it possible that (a != b) && !(a < b) && !(b < a)? */ + bool operator ==(const QcFloat &other) const + { return (fRep == other.fRep); } + + bool operator !=(const QcFloat &other) const + { return (fRep != other.fRep); } + +#if 0 + operator int() const + { return (int) Round( fRep->Value()); } +#endif + + bool isDead() const + { return fRep == 0; } + + //-----------------------------------------------------------------------// + // Manipulation functions // + //-----------------------------------------------------------------------// +private: + /** Deallocates old name string. */ + bool FreeName() + { return fRep->FreeName(); } + + /** Called when number of references decreases. */ + void Decrease(); + + /** Call when number of references increases. */ + void Increase() + { +#if qcReportAlloc + cerr << "f: " << &fRep << " increasing " << fRep << endl; +#endif + fRep->Increase(); + } + +public: + void SetWeight(numT w) + { fRep->SetWeight(w); } + + void SetValue(numT v) + { fRep->SetValue(v); } + + void SuggestValue(numT dv) + { fRep->SuggestValue(dv); } + + void SetName(const char *n) + { fRep->SetName(n); } + + void SetToEditWeight() + { fRep->SetToEditWeight(); } + + void SetToStayWeight() + { fRep->SetToStayWeight(); } + + void SetVariable() + { fRep->SetToGoal(); } + + /** Old name for RestDesVal. */ + void RestVariable() + { fRep->RestDesVal(); } + + void RestDesVal() + { fRep->RestDesVal(); } + + bool RestDesVal_changed() + { return fRep->RestDesVal_changed(); } + + QcFloat &operator=(const QcFloat &other); + // N.B. checked self assignment, x = x ok + + //-----------------------------------------------------------------------// + // Utility functions // + //-----------------------------------------------------------------------// + void Print(ostream &os) const + { fRep->Print(os); } + +protected: + QcFloatRep *fRep; +}; + +inline QcFloat::QcFloat(QcFloatRep *ptr) + : fRep (ptr) +{ +#if qcReportAlloc + cerr << "f: " << &fRep << " constructing from rep " << fRep << endl; +#endif + Increase(); +} + +inline QcFloat::QcFloat(QcFloatRep &rep) + : fRep(&rep) +{ +#if qcReportAlloc + cerr << "f: " << &fRep << " constructing from rep " << fRep << endl; +#endif + Increase(); +} + +inline QcFloat::QcFloat(bool restricted) + : fRep(new QcNomadicFloatRep(restricted)) +{ +#if qcReportAlloc + cerr << "f: " << &fRep << " created QcFloatRep " << fRep << endl; +#endif +} + +inline QcFloat::QcFloat(const char *name, bool restricted) + : fRep(new QcNomadicFloatRep(name, restricted)) +{ +#if qcReportAlloc + cerr << "f: " << &fRep << " created QcFloatRep " << fRep << endl; +#endif +} + +inline QcFloat::QcFloat(const char *name, numT desval, bool restricted) + : fRep(new QcNomadicFloatRep(name, desval, restricted)) +{ +#if qcReportAlloc + cerr << "f: " << &fRep << " created QcFloatRep " << fRep << endl; +#endif +} + +inline QcFloat::QcFloat(const char *name, numT desval, numT sw, numT ew, + bool restricted) + : fRep(new QcNomadicFloatRep(name, desval, sw, ew, restricted)) +{ +#if qcReportAlloc + cerr << "f: " << &fRep << " created QcFloatRep " << fRep << endl; +#endif +} + +inline QcFloat::QcFloat(const QcFloat &other) + : fRep(other.fRep) +{ +#if qcReportAlloc + cerr << "f: " << &fRep << " constructed from QcFloatRep " << fRep << endl; +#endif + Increase(); +} + +#if 0 +inline QcFloat::QcFloat(QcNullableElement const &other) + : fRep(other.fRep) +{ +# if qcReportAlloc + cerr << "f: " << &fRep << " constructed from QcFloatRep " << fRep << endl; +# endif + Increase(); +} +#endif + +#ifndef qcSafetyChecks +inline void QcFloat::Decrease() +{ +# if qcReportAlloc + cerr << "f: " << &fRep << " decreasing " << fRep << endl; +# endif +# if 0 + if (fRep == 0) + return; +# endif + fRep->Decrease(); + + if (fRep->Counter() == 0) + delete fRep; + fRep = 0; +} +#else /* qcSafetyChecks */ +inline void QcFloat::Decrease() +{ +# if qcReportAlloc + cout << "Decreasing " << fRep << endl; +# endif +# if 0 + if (fRep == 0) + return; +# endif + fRep->Decrease(); + + if (fRep->Counter() == 0) { + fRep->assertInvar(); + if (fRep->Magic() == qcFloatMagic1 && fRep->FreeName()) { + delete fRep; + } else + throw QcWarning("QcFloat::Decrease detected cfloat corruption"); + } + fRep = 0; +} +#endif /* qcSafetyChecks */ + +inline QcFloat &QcFloat::operator=(const QcFloat &other) +{ + other.fRep->Increase(); + Decrease(); + fRep = other.fRep; + return *this; +} + +#ifndef qcNoStream +inline ostream &operator<<(ostream &os, const QcFloat &cf) +{ + cf.Print(os); + return os; +} +#endif + +#endif /* !__QcFloatH */ diff --git a/src/kits/interface/qoca/QcFloatRep.H b/src/kits/interface/qoca/QcFloatRep.H new file mode 100644 index 0000000000..b792f39fb4 --- /dev/null +++ b/src/kits/interface/qoca/QcFloatRep.H @@ -0,0 +1,285 @@ +// Generated automatically from QcFloatRep.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcFloatRepDCL +#define QcFloatRepDCL +#line 1 "QcFloatRep.ch" +// $Id: QcFloatRep.ch,v 1.13 2001/01/10 05:01:51 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include "qoca/QcUtility.hh" + + +#define qcFloatMagic1 18732 +#define qcFloatMagic2 "Qoca var:" +#define qcMagic2Len 9 + // The length of magic2 without the terminal '\0' + + + +class QcFloatRep +{ +public: + +/** It is intended that TId be signed. Negative values are not + allocated and are reserved for future (unknown) usage. The value 0 + is reserved as an invalid identifier. */ +typedef long TId; + +public: + //-----------------------------------------------------------------------// + // Constructors // + //-----------------------------------------------------------------------// + +QcFloatRep (const char *name, numT desval, numT sw, numT ew, + bool restricted); +#line 74 "QcFloatRep.ch" +#ifndef NDEBUG +bool isQcFloatRep() const +{ return fMagic == qcFloatMagic1; } +#endif + +virtual ~QcFloatRep() +{ +#if qcReportAlloc + cout << "destroying " << this << endl; +#endif + qcAssertPre( isQcFloatRep()); + qcAssertPre ((fName == 0) + || memcmp (fName, qcFloatMagic2, + qcMagic2Len) == 0); + delete [] fName; + fMagic = 0; +} + + +//-----------------------------------------------------------------------// +// Set and Get member functions // +//-----------------------------------------------------------------------// + +long Counter() const +{ + qcAssertPre( isQcFloatRep()); + return fCounter; +} + +numT EditWeight() const +{ + qcAssertPre( isQcFloatRep()); + return fEditWeight; +} + +long Magic() const +{ return fMagic; } + +numT StayWeight() const +{ + qcAssertPre( isQcFloatRep()); + return fStayWeight; +} + +numT Value() const +{ + qcAssertPre( isQcFloatRep()); + return fValue; +} + +numT Weight() const +{ + qcAssertPre( isQcFloatRep()); + return fWeight; +} + +numT DesireValue() const +{ + qcAssertPre( isQcFloatRep()); + return fDesireValue; +} + +bool IsRestricted() const +{ + qcAssertPre( isQcFloatRep()); + return fRestricted; +} + +TId Id() const +{ + qcAssertPre( isQcFloatRep()); + return fId; +} + +/** Called when number of references decreases. */ +void Decrease() +{ + qcAssertPre( isQcFloatRep()); + fCounter--; + qcAssertPre (fCounter >= 0); +} + +/** Call when number of references increases. */ +void Increase() +{ + qcAssertPre( isQcFloatRep()); + fCounter++; +} + + + + +inline char const *Name() const; +#line 176 "QcFloatRep.ch" +virtual void SetWeight (numT w); +#line 183 "QcFloatRep.ch" +virtual void SetValue (numT v); +#line 194 "QcFloatRep.ch" +/** Set the goal value of this variable to dv. + +

Note that many solvers ignore SuggestValue on variables that are not edit + variables. +**/ +void +SuggestValue (numT dv); +#line 206 "QcFloatRep.ch" +/** Sets field fName to point to a heap-allocated string with a hidden + magic number field at the front. (The magic number is qcFloatMagic2 without + the '\0' terminator.) + +

(The Java version doesn't bother with a magic number, presumably because + of lack of pointers. The Java version consists of `fName = n'.) +**/ +void SetName (char const *n); +#line 248 "QcFloatRep.ch" +inline void SetToGoal(); +#line 255 "QcFloatRep.ch" +virtual void SetToEditWeight() = 0; + +virtual void SetToStayWeight() = 0; + + +/** Do RestDesVal, then return true iff the goal value changed. */ +virtual bool RestDesVal_changed() = 0; + +/** For nomadic variables, set the goal value to equal the actual + (solved) value; does nothing for "fixed" (non-nomadic) variables. +**/ +virtual void RestDesVal() = 0; + + + +/** Called just before delete, to detect pointer corruption. */ +virtual void assertInvar() const; + +#line 296 "QcFloatRep.ch" +/** Deallocates old name string checking magic2. + Returns success indicator. +**/ +bool FreeName(); +#line 321 "QcFloatRep.ch" +/** Set variables to defaults (including getting a new fId). */ +inline void Reset(); +#line 330 "QcFloatRep.ch" +bool operator<(const QcFloatRep &other) const + // The comparisons are for when QcFloatRep is used + // as an identifier and compares instances not structure. + // General pointer inequality comparisons are not reliable + // (see the C++ ARM section 5.9), fId is provided for this. +{ + qcAssertPre( isQcFloatRep()); + qcAssertPre( other.isQcFloatRep()); + + return fId < other.fId; +} + +#if 0 +bool operator==(const QcFloatRep &other) const +{ return fId == other.fId; } + +bool operator!=(const QcFloatRep &other) const +{ return fId != other.fId; } +#endif + + + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// + + +virtual void Print (ostream &os) const; +#line 372 "QcFloatRep.ch" +protected: + static TId fNextValidId; + static const TId fInvalidId = 0; + // fInvalidId is currently set to 0. All negative values are reserved + // for future use. + +private: + TId fId; // Used as index key and for operator<. + long fMagic; // To detect corruption. + long fCounter; // Reference count. + numT fStayWeight; + numT fEditWeight; +protected: + numT fValue; + numT fWeight; + numT fDesireValue; +private: + char *fName; // 0 or a heap allocated string with hidden prefix. + bool fRestricted; + +}; + + + +struct QcFloatRep_hash +{ + size_t operator()(QcFloatRep const *v) const + { + return (size_t) v->Id(); + } +}; + +struct QcFloatRep_equal +{ + size_t operator()(QcFloatRep const *v1, + QcFloatRep const *v2) const + { + return v1->Id() == v2->Id(); + } +}; + + + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcFloatRepDCL */ diff --git a/src/kits/interface/qoca/QcFloatRep.cc b/src/kits/interface/qoca/QcFloatRep.cc new file mode 100644 index 0000000000..5a8d9f1d35 --- /dev/null +++ b/src/kits/interface/qoca/QcFloatRep.cc @@ -0,0 +1,204 @@ +// Generated automatically from QcFloatRep.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcFloatRep.hh" +#line 1 "QcFloatRep.ch" +// $Id: QcFloatRep.ch,v 1.13 2001/01/10 05:01:51 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include "qoca/QcUtility.hh" + + +#line 48 "QcFloatRep.ch" + //-----------------------------------------------------------------------// + // Constructors // + //-----------------------------------------------------------------------// + +QcFloatRep::QcFloatRep (const char *name, numT desval, numT sw, numT ew, + bool restricted) + : fStayWeight( sw), + fEditWeight( ew), + fValue( 0), /* perhaps should be desval; but perhaps not too important so + long as it is understood that Solve needs to be called. */ + fWeight( sw), + fDesireValue( desval) +{ + qcAssertExternalPre( sw >= 0); + qcAssertExternalPre( ew >= 0); +#if qcReportAlloc + cerr << "initing " << this << endl; +#endif + fMagic = qcFloatMagic1; + Reset(); + fRestricted = restricted; + fName = 0; + SetName( name); +} + + +#line 93 "QcFloatRep.ch" +//-----------------------------------------------------------------------// +// Set and Get member functions // +//-----------------------------------------------------------------------// + +#line 176 "QcFloatRep.ch" +void QcFloatRep::SetWeight (numT w) +{ + qcAssertPre( isQcFloatRep()); + fWeight = w; +} + + +void QcFloatRep::SetValue (numT v) +{ + qcAssertPre( isQcFloatRep()); +#ifdef qcSafetyChecks + if (fRestricted && QcUtility::IsNegative(v)) + throw QcWarning("Restricted float made negative"); +#endif + + fValue = v; +} + + +#line 199 "QcFloatRep.ch" +void +QcFloatRep::SuggestValue (numT dv) +{ + qcAssertPre( isQcFloatRep()); + fDesireValue = dv; +} + + +#line 213 "QcFloatRep.ch" +void QcFloatRep::SetName (char const *n) +{ + qcAssertPre( isQcFloatRep()); + /* Note: Although is pretty standard, for portability we try + to avoid using it here as we have no other need for it. */ + int len = 0; + char const *magic2 = qcFloatMagic2; + + // find length of source string + while (n[len] != '\0') + len++; + + qcAssertPost (n[len] == '\0'); +#ifdef qcSafetyChecks + if (len > 1000) + throw QcWarning("QcFloatRep::SetName name over 1000 chars long"); +#endif + + /* Deallocate existing name string. If FreeName fails, leave old string + and allocate a new one. */ + if (!FreeName()) + throw QcWarning("QcFloatRep::SetName: failed to free old name string"); + + fName = new char[len + qcMagic2Len + 1]; // allocate for magic+string + + for (int i = 0; i < qcMagic2Len; i++) + fName[i] = magic2[i]; + + for (int i=0; i <= len; i++) + fName[i + qcMagic2Len] = n[i]; + + qcAssertPost (fName[len + qcMagic2Len] == '\0'); +} + +#line 279 "QcFloatRep.ch" +#if qcCheckInternalPre +void QcFloatRep::assertInvar() const +{ + qcAssertInvar (fId > 0); + qcAssertInvar (Magic() == qcFloatMagic1); + qcAssertInvar (fCounter >= 0); + qcAssertInvar (fStayWeight >= 0); + qcAssertInvar (fEditWeight >= 0); + qcAssertInvar (fWeight >= 0); + qcAssertInvar ((fName == 0) + || (memcmp (fName, qcFloatMagic2, qcMagic2Len) + == 0)); +} +#endif + + + + +#line 299 "QcFloatRep.ch" +bool QcFloatRep::FreeName() +{ + qcAssertPre( isQcFloatRep()); + bool ok = true; + + if (fName != 0) + { // check for magic2 + char const *magic2 = qcFloatMagic2; + + for (int i = 0; i < qcMagic2Len; i++) + ok &= (fName[i] == magic2[i]); + + if (ok) + { + delete[] fName; + fName = 0; + } + } + + return ok; +} + + +#line 352 "QcFloatRep.ch" +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// + + +void QcFloatRep::Print (ostream &os) const +{ + qcAssertPre( isQcFloatRep()); + + if (fName != 0) + os << Name(); + + os << "#" << fId + << "(" << fValue << ", " + << fDesireValue << ", " + << fWeight + << ")"; +} + + +#line 414 "QcFloatRep.ch" +QcFloatRep::TId QcFloatRep::fNextValidId = 1; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcFloatRep.ch b/src/kits/interface/qoca/QcFloatRep.ch new file mode 100644 index 0000000000..5e2ed073bc --- /dev/null +++ b/src/kits/interface/qoca/QcFloatRep.ch @@ -0,0 +1,423 @@ +// $Id: QcFloatRep.ch,v 1.13 2001/01/10 05:01:51 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include "qoca/QcUtility.hh" + +//begin o[d] +#define qcFloatMagic1 18732 +#define qcFloatMagic2 "Qoca var:" +#define qcMagic2Len 9 + // The length of magic2 without the terminal '\0' +//end o[d] + + +//ho class QcFloatRep +//ho { +//ho public: + +/** It is intended that TId be signed. Negative values are not + allocated and are reserved for future (unknown) usage. The value 0 + is reserved as an invalid identifier. */ +typedef long TId; + +//ho public: + //-----------------------------------------------------------------------// + // Constructors // + //-----------------------------------------------------------------------// +//cf +QcFloatRep (const char *name, numT desval, numT sw, numT ew, + bool restricted) + : fStayWeight( sw), + fEditWeight( ew), + fValue( 0), /* perhaps should be desval; but perhaps not too important so + long as it is understood that Solve needs to be called. */ + fWeight( sw), + fDesireValue( desval) +{ + qcAssertExternalPre( sw >= 0); + qcAssertExternalPre( ew >= 0); +#if qcReportAlloc + cerr << "initing " << this << endl; +#endif + fMagic = qcFloatMagic1; + Reset(); + fRestricted = restricted; + fName = 0; + SetName( name); +} + +//begin ho +#ifndef NDEBUG +bool isQcFloatRep() const +{ return fMagic == qcFloatMagic1; } +#endif + +virtual ~QcFloatRep() +{ +#if qcReportAlloc + cout << "destroying " << this << endl; +#endif + qcAssertPre( isQcFloatRep()); + qcAssertPre ((fName == 0) + || memcmp (fName, qcFloatMagic2, + qcMagic2Len) == 0); + delete [] fName; + fMagic = 0; +} +//end ho + +//-----------------------------------------------------------------------// +// Set and Get member functions // +//-----------------------------------------------------------------------// +//begin o[d] +long Counter() const +{ + qcAssertPre( isQcFloatRep()); + return fCounter; +} + +numT EditWeight() const +{ + qcAssertPre( isQcFloatRep()); + return fEditWeight; +} + +long Magic() const +{ return fMagic; } + +numT StayWeight() const +{ + qcAssertPre( isQcFloatRep()); + return fStayWeight; +} + +numT Value() const +{ + qcAssertPre( isQcFloatRep()); + return fValue; +} + +numT Weight() const +{ + qcAssertPre( isQcFloatRep()); + return fWeight; +} + +numT DesireValue() const +{ + qcAssertPre( isQcFloatRep()); + return fDesireValue; +} + +bool IsRestricted() const +{ + qcAssertPre( isQcFloatRep()); + return fRestricted; +} + +TId Id() const +{ + qcAssertPre( isQcFloatRep()); + return fId; +} + +/** Called when number of references decreases. */ +void Decrease() +{ + qcAssertPre( isQcFloatRep()); + fCounter--; + qcAssertPre (fCounter >= 0); +} + +/** Call when number of references increases. */ +void Increase() +{ + qcAssertPre( isQcFloatRep()); + fCounter++; +} + +//end o[d] + +//hf +inline char const *Name() const +{ + qcAssertPre( isQcFloatRep()); + if (fName == 0) + return 0; + else + return (fName + qcMagic2Len); +} + +//cf +virtual void SetWeight (numT w) +{ + qcAssertPre( isQcFloatRep()); + fWeight = w; +} + +//cf +virtual void SetValue (numT v) +{ + qcAssertPre( isQcFloatRep()); +#ifdef qcSafetyChecks + if (fRestricted && QcUtility::IsNegative(v)) + throw QcWarning("Restricted float made negative"); +#endif + + fValue = v; +} + +/** Set the goal value of this variable to dv. + +

Note that many solvers ignore SuggestValue on variables that are not edit + variables. +**/ //cf +void +SuggestValue (numT dv) +{ + qcAssertPre( isQcFloatRep()); + fDesireValue = dv; +} + +/** Sets field fName to point to a heap-allocated string with a hidden + magic number field at the front. (The magic number is qcFloatMagic2 without + the '\0' terminator.) + +

(The Java version doesn't bother with a magic number, presumably because + of lack of pointers. The Java version consists of `fName = n'.) +**/ //cf +void SetName (char const *n) +{ + qcAssertPre( isQcFloatRep()); + /* Note: Although is pretty standard, for portability we try + to avoid using it here as we have no other need for it. */ + int len = 0; + char const *magic2 = qcFloatMagic2; + + // find length of source string + while (n[len] != '\0') + len++; + + qcAssertPost (n[len] == '\0'); +#ifdef qcSafetyChecks + if (len > 1000) + throw QcWarning("QcFloatRep::SetName name over 1000 chars long"); +#endif + + /* Deallocate existing name string. If FreeName fails, leave old string + and allocate a new one. */ + if (!FreeName()) + throw QcWarning("QcFloatRep::SetName: failed to free old name string"); + + fName = new char[len + qcMagic2Len + 1]; // allocate for magic+string + + for (int i = 0; i < qcMagic2Len; i++) + fName[i] = magic2[i]; + + for (int i=0; i <= len; i++) + fName[i + qcMagic2Len] = n[i]; + + qcAssertPost (fName[len + qcMagic2Len] == '\0'); +} + +//hf +inline void SetToGoal() +{ + qcAssertPre( isQcFloatRep()); + SetValue (fDesireValue); +} + +//begin o[d] +virtual void SetToEditWeight() = 0; + +virtual void SetToStayWeight() = 0; + + +/** Do RestDesVal, then return true iff the goal value changed. */ +virtual bool RestDesVal_changed() = 0; + +/** For nomadic variables, set the goal value to equal the actual + (solved) value; does nothing for "fixed" (non-nomadic) variables. +**/ +virtual void RestDesVal() = 0; +//end o[d] + + +/** Called just before delete, to detect pointer corruption. */ +//o[d] virtual void assertInvar() const; +//begin o[i] +#ifndef qcCheckInternalPre +inline void QcFloatRep::assertInvar() const +{ } +#endif +//end o[i] +//begin o[c] +#if qcCheckInternalPre +void QcFloatRep::assertInvar() const +{ + qcAssertInvar (fId > 0); + qcAssertInvar (Magic() == qcFloatMagic1); + qcAssertInvar (fCounter >= 0); + qcAssertInvar (fStayWeight >= 0); + qcAssertInvar (fEditWeight >= 0); + qcAssertInvar (fWeight >= 0); + qcAssertInvar ((fName == 0) + || (memcmp (fName, qcFloatMagic2, qcMagic2Len) + == 0)); +} +#endif +//end o[c] + + +/** Deallocates old name string checking magic2. + Returns success indicator. +**/ //cf +bool FreeName() +{ + qcAssertPre( isQcFloatRep()); + bool ok = true; + + if (fName != 0) + { // check for magic2 + char const *magic2 = qcFloatMagic2; + + for (int i = 0; i < qcMagic2Len; i++) + ok &= (fName[i] == magic2[i]); + + if (ok) + { + delete[] fName; + fName = 0; + } + } + + return ok; +} + +/** Set variables to defaults (including getting a new fId). */ +inline void Reset() +{ + fCounter = 1; + fId = fNextValidId++; + qcAssertPost (fNextValidId > 0); +} + +//begin o[d] +bool operator<(const QcFloatRep &other) const + // The comparisons are for when QcFloatRep is used + // as an identifier and compares instances not structure. + // General pointer inequality comparisons are not reliable + // (see the C++ ARM section 5.9), fId is provided for this. +{ + qcAssertPre( isQcFloatRep()); + qcAssertPre( other.isQcFloatRep()); + + return fId < other.fId; +} + +#if 0 +bool operator==(const QcFloatRep &other) const +{ return fId == other.fId; } + +bool operator!=(const QcFloatRep &other) const +{ return fId != other.fId; } +#endif +//end o[d] + + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// + +//cf +virtual void Print (ostream &os) const +{ + qcAssertPre( isQcFloatRep()); + + if (fName != 0) + os << Name(); + + os << "#" << fId + << "(" << fValue << ", " + << fDesireValue << ", " + << fWeight + << ")"; +} + +//begin ho +protected: + static TId fNextValidId; + static const TId fInvalidId = 0; + // fInvalidId is currently set to 0. All negative values are reserved + // for future use. + +private: + TId fId; // Used as index key and for operator<. + long fMagic; // To detect corruption. + long fCounter; // Reference count. + numT fStayWeight; + numT fEditWeight; +protected: + numT fValue; + numT fWeight; + numT fDesireValue; +private: + char *fName; // 0 or a heap allocated string with hidden prefix. + bool fRestricted; +//end ho +//ho }; + + +//begin ho +struct QcFloatRep_hash +{ + size_t operator()(QcFloatRep const *v) const + { + return (size_t) v->Id(); + } +}; + +struct QcFloatRep_equal +{ + size_t operator()(QcFloatRep const *v1, + QcFloatRep const *v2) const + { + return v1->Id() == v2->Id(); + } +}; +//end ho + +//o[c] QcFloatRep::TId QcFloatRep::fNextValidId = 1; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcFloatRep.hh b/src/kits/interface/qoca/QcFloatRep.hh new file mode 100644 index 0000000000..4fe9f5f6e1 --- /dev/null +++ b/src/kits/interface/qoca/QcFloatRep.hh @@ -0,0 +1,97 @@ +// Generated automatically from QcFloatRep.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcFloatRep.H" +#ifndef QcFloatRepIFN +#define QcFloatRepIFN +#line 1 "QcFloatRep.ch" +// $Id: QcFloatRep.ch,v 1.13 2001/01/10 05:01:51 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include "qoca/QcUtility.hh" + + +#line 48 "QcFloatRep.ch" + //-----------------------------------------------------------------------// + // Constructors // + //-----------------------------------------------------------------------// + +#line 93 "QcFloatRep.ch" +//-----------------------------------------------------------------------// +// Set and Get member functions // +//-----------------------------------------------------------------------// + +#line 166 "QcFloatRep.ch" +inline char const *QcFloatRep::Name() const +{ + qcAssertPre( isQcFloatRep()); + if (fName == 0) + return 0; + else + return (fName + qcMagic2Len); +} + + +#line 248 "QcFloatRep.ch" +inline void QcFloatRep::SetToGoal() +{ + qcAssertPre( isQcFloatRep()); + SetValue (fDesireValue); +} + + +#line 273 "QcFloatRep.ch" +#ifndef qcCheckInternalPre +inline void QcFloatRep::QcFloatRep::assertInvar() const +{ } +#endif + + +#line 322 "QcFloatRep.ch" +inline void QcFloatRep::Reset() +{ + fCounter = 1; + fId = fNextValidId++; + qcAssertPost (fNextValidId > 0); +} + + +#line 352 "QcFloatRep.ch" +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// + + +#line 416 "QcFloatRep.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcFloatRepIFN */ diff --git a/src/kits/interface/qoca/QcIneqSolverBase.H b/src/kits/interface/qoca/QcIneqSolverBase.H new file mode 100644 index 0000000000..08352d2988 --- /dev/null +++ b/src/kits/interface/qoca/QcIneqSolverBase.H @@ -0,0 +1,128 @@ +// Generated automatically from QcIneqSolverBase.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcIneqSolverBaseDCL +#define QcIneqSolverBaseDCL +#line 1 "QcIneqSolverBase.ch" +#include + +#include + +class QcIneqSolverBase + : public QcSolver +{ +public: + +inline +QcIneqSolverBase(); +#line 18 "QcIneqSolverBase.ch" +inline +QcIneqSolverBase(unsigned hintNumConstraints, unsigned hintNumVariables); +#line 26 "QcIneqSolverBase.ch" +virtual ~QcIneqSolverBase() +{ +} + +//-----------------------------------------------------------------------// +// Variable management methods // +//-----------------------------------------------------------------------// +virtual void +AddVar(QcFloat &v) +{ + fSystem.AddVar( v); +} + +virtual void +SuggestValue(QcFloat &v, numT desval) +{ + fSystem.SuggestValue( v, desval); +} + +virtual bool +RemoveVar(QcFloat &v) +{ + return fSystem.RemoveVar( v); +} + +virtual void +RestSolver() +{ + fSystem.RestSolver(); +} + +//-----------------------------------------------------------------------// +// Enquiry functions for variables // +//-----------------------------------------------------------------------// +virtual bool +IsRegistered(QcFloat const &v) const +{ + return fSystem.IsRegistered( v); +} + +virtual bool +IsFree(QcFloat const &v) const +{ + return fSystem.IsFree( v); +} + +virtual bool +IsBasic(QcFloat const &v) const +{ + return fSystem.IsBasic( v); +} + + + +//-----------------------------------------------------------------------// +// Constraint management methods // +//-----------------------------------------------------------------------// + + +virtual bool +AddConstraint(QcConstraint &c); +#line 101 "QcIneqSolverBase.ch" +virtual bool +AddConstraint(QcConstraint &c, QcFloat &hint); +#line 117 "QcIneqSolverBase.ch" +virtual void +BeginAddConstraint() +{ + fSystem.BeginAddConstraint(); +} + +virtual bool +EndAddConstraint() +{ + return fSystem.EndAddConstraint(); +} + + + +virtual bool +ChangeConstraint(QcConstraint &oldc, numT rhs); +#line 143 "QcIneqSolverBase.ch" +virtual bool +RemoveConstraint(QcConstraint &c); +#line 159 "QcIneqSolverBase.ch" +virtual bool +Reset() +{ + return fSystem.Reset(); +} + + + + +protected: + QcDelLinInEqSystem fSystem; + +}; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcIneqSolverBaseDCL */ diff --git a/src/kits/interface/qoca/QcIneqSolverBase.cc b/src/kits/interface/qoca/QcIneqSolverBase.cc new file mode 100644 index 0000000000..2fabb32c56 --- /dev/null +++ b/src/kits/interface/qoca/QcIneqSolverBase.cc @@ -0,0 +1,88 @@ +// Generated automatically from QcIneqSolverBase.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcIneqSolverBase.hh" +#line 1 "QcIneqSolverBase.ch" + +#include + + + + + + + +#line 80 "QcIneqSolverBase.ch" +//-----------------------------------------------------------------------// +// Constraint management methods // +//-----------------------------------------------------------------------// + + +bool +QcIneqSolverBase::AddConstraint(QcConstraint &c) +{ + bool success = fSystem.AddConstraint( c); + if (success) + { +#if qcCheckPost + addCheckedConstraint( c.pointer()); +#endif + if (fAutoSolve) + Solve(); + } + return success; +} + + +bool +QcIneqSolverBase::AddConstraint(QcConstraint &c, QcFloat &hint) +{ + bool success = fSystem.AddConstraint( c, hint); + if (success) + { +#if qcCheckPost + addCheckedConstraint( c.pointer()); +#endif + if (fAutoSolve) + Solve(); + } + return success; +} + + +#line 131 "QcIneqSolverBase.ch" +bool +QcIneqSolverBase::ChangeConstraint(QcConstraint &oldc, numT rhs) +{ + bool success = fSystem.ChangeConstraint( oldc, rhs); +#if qcCheckPost + if (success) + changeCheckedConstraint( oldc.pointer(), rhs); +#endif + return success; +} + + +bool +QcIneqSolverBase::RemoveConstraint(QcConstraint &c) +{ + bool success = fSystem.RemoveConstraint( c); + if (success) + { +#if qcCheckPost + removeCheckedConstraint( c.pointer()); +#endif + if (fAutoSolve) + Solve(); + } + return success; +} + + +#line 173 "QcIneqSolverBase.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcIneqSolverBase.ch b/src/kits/interface/qoca/QcIneqSolverBase.ch new file mode 100644 index 0000000000..5a2aa659c5 --- /dev/null +++ b/src/kits/interface/qoca/QcIneqSolverBase.ch @@ -0,0 +1,180 @@ +//o[d] #include +//o[ci] #include +//o[d] #include + +//ho class QcIneqSolverBase +//ho : public QcSolver +//ho { +//ho public: + +inline +QcIneqSolverBase() + : QcSolver(), + fSystem() +{ +} + + +inline +QcIneqSolverBase(unsigned hintNumConstraints, unsigned hintNumVariables) + : QcSolver(), + fSystem( hintNumConstraints, hintNumVariables) +{ +} + +//begin ho +virtual ~QcIneqSolverBase() +{ +} + +//-----------------------------------------------------------------------// +// Variable management methods // +//-----------------------------------------------------------------------// +virtual void +AddVar(QcFloat &v) +{ + fSystem.AddVar( v); +} + +virtual void +SuggestValue(QcFloat &v, numT desval) +{ + fSystem.SuggestValue( v, desval); +} + +virtual bool +RemoveVar(QcFloat &v) +{ + return fSystem.RemoveVar( v); +} + +virtual void +RestSolver() +{ + fSystem.RestSolver(); +} + +//-----------------------------------------------------------------------// +// Enquiry functions for variables // +//-----------------------------------------------------------------------// +virtual bool +IsRegistered(QcFloat const &v) const +{ + return fSystem.IsRegistered( v); +} + +virtual bool +IsFree(QcFloat const &v) const +{ + return fSystem.IsFree( v); +} + +virtual bool +IsBasic(QcFloat const &v) const +{ + return fSystem.IsBasic( v); +} +//end ho + + +//-----------------------------------------------------------------------// +// Constraint management methods // +//-----------------------------------------------------------------------// + +//cf +virtual bool +AddConstraint(QcConstraint &c) +{ + bool success = fSystem.AddConstraint( c); + if (success) + { +#if qcCheckPost + addCheckedConstraint( c.pointer()); +#endif + if (fAutoSolve) + Solve(); + } + return success; +} + +//cf +virtual bool +AddConstraint(QcConstraint &c, QcFloat &hint) +{ + bool success = fSystem.AddConstraint( c, hint); + if (success) + { +#if qcCheckPost + addCheckedConstraint( c.pointer()); +#endif + if (fAutoSolve) + Solve(); + } + return success; +} + +//begin ho +virtual void +BeginAddConstraint() +{ + fSystem.BeginAddConstraint(); +} + +virtual bool +EndAddConstraint() +{ + return fSystem.EndAddConstraint(); +} +//end ho + +//cf +virtual bool +ChangeConstraint(QcConstraint &oldc, numT rhs) +{ + bool success = fSystem.ChangeConstraint( oldc, rhs); +#if qcCheckPost + if (success) + changeCheckedConstraint( oldc.pointer(), rhs); +#endif + return success; +} + +//cf +virtual bool +RemoveConstraint(QcConstraint &c) +{ + bool success = fSystem.RemoveConstraint( c); + if (success) + { +#if qcCheckPost + removeCheckedConstraint( c.pointer()); +#endif + if (fAutoSolve) + Solve(); + } + return success; +} + +//begin ho +virtual bool +Reset() +{ + return fSystem.Reset(); +} +//end ho + + +//begin ho +protected: + QcDelLinInEqSystem fSystem; +//end ho +//ho }; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcIneqSolverBase.hh b/src/kits/interface/qoca/QcIneqSolverBase.hh new file mode 100644 index 0000000000..ec34d40cfb --- /dev/null +++ b/src/kits/interface/qoca/QcIneqSolverBase.hh @@ -0,0 +1,47 @@ +// Generated automatically from QcIneqSolverBase.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcIneqSolverBase.H" +#ifndef QcIneqSolverBaseIFN +#define QcIneqSolverBaseIFN +#line 1 "QcIneqSolverBase.ch" + +#include + + + + + + + +inline +QcIneqSolverBase::QcIneqSolverBase() + : QcSolver(), + fSystem() +{ +} + + +inline +QcIneqSolverBase::QcIneqSolverBase(unsigned hintNumConstraints, unsigned hintNumVariables) + : QcSolver(), + fSystem( hintNumConstraints, hintNumVariables) +{ +} + + +#line 80 "QcIneqSolverBase.ch" +//-----------------------------------------------------------------------// +// Constraint management methods // +//-----------------------------------------------------------------------// + + +#line 173 "QcIneqSolverBase.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcIneqSolverBaseIFN */ diff --git a/src/kits/interface/qoca/QcIterator.hh b/src/kits/interface/qoca/QcIterator.hh new file mode 100644 index 0000000000..b093028f44 --- /dev/null +++ b/src/kits/interface/qoca/QcIterator.hh @@ -0,0 +1,46 @@ +// $Id: QcIterator.hh,v 1.5 2000/12/06 05:32:56 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcIteratorH +#define __QcIteratorH + +class QcIterator +{ +public: + virtual ~QcIterator() { } + + //-----------------------------------------------------------------------// + // Iteration functions. // + //-----------------------------------------------------------------------// + //virtual void Advance() = 0; + virtual bool AtEnd() const = 0; + // Returns true iff the iterator is past the end of its row or column. + virtual void Increment() = 0; + virtual void Reset() = 0; + //virtual void SetToBeginOf(int i) = 0; +}; + +#endif /* !__QcIteratorH */ diff --git a/src/kits/interface/qoca/QcLinEqColState.hh b/src/kits/interface/qoca/QcLinEqColState.hh new file mode 100644 index 0000000000..7f63caab77 --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqColState.hh @@ -0,0 +1,132 @@ +// $Id: QcLinEqColState.hh,v 1.5 2000/12/06 05:32:56 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// The class QcBiMap provides a bi-directional mapping from // +// identifier class to index class. // +//============================================================================// + +#ifndef __QcLinEqColStateH +#define __QcLinEqColStateH + +#include +#include "qoca/QcQuasiColState.hh" + +class QcLinEqColState : public QcQuasiColState +{ + friend class QcLinEqColStateVector; + friend class QcLinEqRowColStateVector; + +public: + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcLinEqColState(int vi); + QcLinEqColState(bool isbasic); + + //-----------------------------------------------------------------------// + // Query functions + //-----------------------------------------------------------------------// + + QcLinEqColState const *getNextBasicnessCol() const + { + return fNextCol; + } + + /** Returns true iff the variable is a basic (i.e. dependent) + variable. */ + bool isBasic() const + { return fIsBasic; } + + /** The constraint that this variable is basic in, or InvalidCIndex if + none. */ + int getConstraintBasicIn() const + { return fIsBasicIn; } + + /** Returns cached value of variable's desired value, for during solve. */ + numT getGoalVal() const + { + return fDesValue; + } + + //----------------------------------------------------------------------- + // Setter functions + //----------------------------------------------------------------------- + /** The constraint that this variable is basic in, or InvalidCIndex if + none. */ + void setConstraintBasicIn(int c) + { fIsBasicIn = c; } + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os); + +private: + numT fDesValue; // cache desired value of variable during solve + bool fIsBasic; // means variable is basic, otherwise it is parametric. + int fIsBasicIn; + + /** fNextCol and fPrevCol are used by QcLinEqColStateVector for some + doubly-linked lists. See that class for details. */ + QcLinEqColState *fNextCol; + QcLinEqColState *fPrevCol; + +protected: + /** Arbitrary constant used as fIndex for the heads of linked lists. Used + only in assertion checking. */ + static unsigned const fHeadIndex = 0x4eadad4e; +}; + +inline QcLinEqColState::QcLinEqColState(int vi) + : QcQuasiColState(vi), + fDesValue( 0), + fIsBasic( false), + fIsBasicIn(QcTableau::fInvalidConstraintIndex), + fNextCol( 0), + fPrevCol( 0) +{ +} + +inline QcLinEqColState::QcLinEqColState(bool isbasic) + : QcQuasiColState( fHeadIndex), + fDesValue(), + fIsBasic( isbasic), + fNextCol( this), + fPrevCol( this) +{ +} + +inline void QcLinEqColState::Print(ostream &os) +{ + QcQuasiColState::Print(os); + os << ",DV(" << fDesValue << ")," + << "IsBasic(" << fIsBasic << ")," + << "BasicIn(" << fIsBasicIn << ")," + << "PrevCol(" << fPrevCol << ")," + << "NextCol(" << fNextCol << ")"; +} + +#endif diff --git a/src/kits/interface/qoca/QcLinEqColStateVector.H b/src/kits/interface/qoca/QcLinEqColStateVector.H new file mode 100644 index 0000000000..55fa2ebe41 --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqColStateVector.H @@ -0,0 +1,149 @@ +// Generated automatically from QcLinEqColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcLinEqColStateVectorDCL +#define QcLinEqColStateVectorDCL +#line 1 "QcLinEqColStateVector.ch" +// $Id: QcLinEqColStateVector.ch,v 1.2 2000/12/06 05:32:56 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcQuasiColStateVector.hh" +#include "qoca/QcLinEqColState.hh" + +class QcLinEqColStateVector + : public QcQuasiColStateVector +{ +public: + + + +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// + +QcLinEqColStateVector() + : QcQuasiColStateVector(), + fParamHead( false), + fBasicHead( true) +{ +} + + +#ifndef NDEBUG +private: + + +void +assertLinkageInvar() const; +#line 113 "QcLinEqColStateVector.ch" +protected: + + +virtual void +virtualAssertLinkageInvar() const; +#line 121 "QcLinEqColStateVector.ch" +#endif /* !NDEBUG */ + + +//-----------------------------------------------------------------------// +// Query functions. // +//-----------------------------------------------------------------------// +public: + +inline numT +GetDesireValue(unsigned i) const; +#line 136 "QcLinEqColStateVector.ch" +inline bool +IsBasic(unsigned i) const; +#line 143 "QcLinEqColStateVector.ch" +inline int +IsBasicIn(unsigned i) const; +#line 151 "QcLinEqColStateVector.ch" +//-----------------------------------------------------------------------// +// Set functions. // +//-----------------------------------------------------------------------// +inline void +SetDesireValue(unsigned i, numT dv) const; +#line 161 "QcLinEqColStateVector.ch" +inline QcLinEqColState * +head( bool isbasic); +#line 172 "QcLinEqColStateVector.ch" +void +SetBasic(unsigned i, bool b); +#line 187 "QcLinEqColStateVector.ch" +inline void +SetBasicIn(unsigned i, int bi) const; +#line 195 "QcLinEqColStateVector.ch" +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + +virtual void +FixLinkage(); +#line 223 "QcLinEqColStateVector.ch" +inline void +Link(QcLinEqColState *state, QcLinEqColState *head); +#line 238 "QcLinEqColStateVector.ch" +inline void +Unlink(QcLinEqColState *state); +#line 251 "QcLinEqColStateVector.ch" +protected: + + +virtual void +Alloc(QcState **start, QcState **finish); +#line 269 "QcLinEqColStateVector.ch" +virtual void +AddToList(QcState **start, QcState **finish); +#line 292 "QcLinEqColStateVector.ch" +virtual void +RemoveFromList(QcState **start, QcState **finish); +#line 310 "QcLinEqColStateVector.ch" +public: + + +virtual void +Print(ostream &os) const; +#line 339 "QcLinEqColStateVector.ch" +private: +inline QcLinEqColState * +getState(unsigned i) const; +#line 351 "QcLinEqColStateVector.ch" +public: + QcLinEqColState fParamHead; // head of linked list of non-basic variables. + QcLinEqColState fBasicHead; // head of linked list of basic variables. + +}; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcLinEqColStateVectorDCL */ diff --git a/src/kits/interface/qoca/QcLinEqColStateVector.cc b/src/kits/interface/qoca/QcLinEqColStateVector.cc new file mode 100644 index 0000000000..b265974b29 --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqColStateVector.cc @@ -0,0 +1,264 @@ +// Generated automatically from QcLinEqColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcLinEqColStateVector.hh" +#line 1 "QcLinEqColStateVector.ch" +// $Id: QcLinEqColStateVector.ch,v 1.2 2000/12/06 05:32:56 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcQuasiColStateVector.hh" +#include "qoca/QcLinEqColState.hh" + + + + + + + +#line 49 "QcLinEqColStateVector.ch" +#ifndef NDEBUG + + + +void +QcLinEqColStateVector::assertLinkageInvar() const +{ + unsigned nParams = 0, nBasic = 0; + + assert( fParamHead.getIndex() == QcLinEqColState::fHeadIndex); + assert( fBasicHead.getIndex() == QcLinEqColState::fHeadIndex); + + { + QcState const * const *i, * const *end = fStates + fSize; + + for (i = getAllocEnd(); + i-- != end;) + { + QcLinEqColState const *curr = CAST(QcLinEqColState const *, *i); + assert( curr->fNextCol == 0); + assert( curr->fPrevCol == 0); + } + assert( i + 1 == end); + + for (;i >= fStates; i--) + { + QcLinEqColState const *curr = CAST(QcLinEqColState const *, *i); + if (curr->isBasic()) + nBasic++; + else + nParams++; + assert( curr->fNextCol != 0); + assert( curr->fNextCol->fPrevCol == curr); + } + } + assert( nBasic + nParams == fSize); + + assert( fParamHead.fNextCol != 0); + assert( fParamHead.fNextCol->fPrevCol == &fParamHead); + for (QcLinEqColState *curr = fParamHead.fNextCol; + curr != &fParamHead; + curr = curr->fNextCol) + { + assert( !curr->isBasic()); + assert( curr->fIndex < (int) fSize); + assert( nParams != 0); + nParams--; + } + assert( nParams == 0); + + assert( fBasicHead.fNextCol != 0); + assert( fBasicHead.fNextCol->fPrevCol == &fBasicHead); + for (QcLinEqColState *curr = fBasicHead.fNextCol; + curr != &fBasicHead; + curr = curr->fNextCol) + { + assert( curr->isBasic()); + assert( curr->getIndex() < fSize); + assert( nBasic != 0); + nBasic--; + } + assert( nBasic == 0); +} + + + + +void +QcLinEqColStateVector::virtualAssertLinkageInvar() const +{ + assertLinkageInvar(); +} +#endif /* !NDEBUG */ + + +//-----------------------------------------------------------------------// +// Query functions. // +//-----------------------------------------------------------------------// + + +#line 151 "QcLinEqColStateVector.ch" +//-----------------------------------------------------------------------// +// Set functions. // +//-----------------------------------------------------------------------// +#line 172 "QcLinEqColStateVector.ch" +void +QcLinEqColStateVector::SetBasic(unsigned i, bool b) +{ + qcAssertPre( i < fSize); + qcAssertPre( (unsigned) b <= 1); + + QcLinEqColState *state = getState( i); + if (state->fIsBasic != b) + { + state->fIsBasic = b; + Unlink( state); + Link( state, head( b)); + } +} + +#line 195 "QcLinEqColStateVector.ch" +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + +void +QcLinEqColStateVector::FixLinkage() +{ + dbg(assertLinkageInvar()); + +#if 0 /* shouldn't be necessary any more. */ + fBasicHead->fPrevCol = fBasicHead->fNextCol = &fBasicHead; + fParamHead->fPrevCol = fParamHead->fNextCol = &fParamHead; + QcLinEqColState heads[] = {fParamHead, fBasicHead}; + + for (unsigned i = 0; i < fSize; i++) + { + QcLinEqColState *state = getState( i); + + unsigned ix = state->isBasic(); + assert (ix <= 1); + Link( state, heads[ix]); + } + + dbg(assertLinkageInvar()); +#endif +} + + +#line 254 "QcLinEqColStateVector.ch" +void +QcLinEqColStateVector::Alloc(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fCapacity); + + for (unsigned i = start - fStates; + start != finish; + start++, i++) + *start = new QcLinEqColState( (int) i); +} + + + +void +QcLinEqColStateVector::AddToList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start < finish); + qcAssertPre( finish <= getAllocEnd()); + + for(; start != finish; start++) + { + QcLinEqColState *state = CAST(QcLinEqColState *, *start); + + assert( (state->fNextCol == 0) + && (state->fPrevCol == 0) + && (state->fDesValue == 0.0) + && (state->fIsBasic == false) + && (state->fIsBasicIn == QcTableau::fInvalidConstraintIndex)); + + Link( state, &fParamHead); + } +} + + + +void +QcLinEqColStateVector::RemoveFromList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fSize); + + for(; start != finish; start++) + { + QcLinEqColState *state = CAST(QcLinEqColState *, *start); + + Unlink( state); + state->fDesValue = 0.0f; + state->fIsBasic = false; + state->fIsBasicIn = QcTableau::fInvalidConstraintIndex; + } +} + + + + +void +QcLinEqColStateVector::Print(ostream &os) const +{ + QcQuasiColStateVector::Print(os); + os << endl << "Basic variable list:" << endl; + QcLinEqColState *curr = fBasicHead.fNextCol; + + while (curr != &fBasicHead) + { + curr->Print(os); + os << endl; + curr = curr->fNextCol; + } + + os << endl << "Param variable list:" << endl; + curr = fParamHead.fNextCol; + + while (curr != &fBasicHead) + { + curr->Print(os); + os << endl; + curr = curr->fNextCol; + } +} + + + +#line 358 "QcLinEqColStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcLinEqColStateVector.ch b/src/kits/interface/qoca/QcLinEqColStateVector.ch new file mode 100644 index 0000000000..e36255beae --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqColStateVector.ch @@ -0,0 +1,365 @@ +// $Id: QcLinEqColStateVector.ch,v 1.2 2000/12/06 05:32:56 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcQuasiColStateVector.hh" +#include "qoca/QcLinEqColState.hh" + +//o[d] class QcLinEqColStateVector +//o[d] : public QcQuasiColStateVector +//o[d] { +//o[d] public: + +//begin o[d] + +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// + +QcLinEqColStateVector() + : QcQuasiColStateVector(), + fParamHead( false), + fBasicHead( true) +{ +} +//end o[d] + +#ifndef NDEBUG +//o[d] private: + +//cf +void +assertLinkageInvar() const +{ + unsigned nParams = 0, nBasic = 0; + + assert( fParamHead.getIndex() == QcLinEqColState::fHeadIndex); + assert( fBasicHead.getIndex() == QcLinEqColState::fHeadIndex); + + { + QcState const * const *i, * const *end = fStates + fSize; + + for (i = getAllocEnd(); + i-- != end;) + { + QcLinEqColState const *curr = CAST(QcLinEqColState const *, *i); + assert( curr->fNextCol == 0); + assert( curr->fPrevCol == 0); + } + assert( i + 1 == end); + + for (;i >= fStates; i--) + { + QcLinEqColState const *curr = CAST(QcLinEqColState const *, *i); + if (curr->isBasic()) + nBasic++; + else + nParams++; + assert( curr->fNextCol != 0); + assert( curr->fNextCol->fPrevCol == curr); + } + } + assert( nBasic + nParams == fSize); + + assert( fParamHead.fNextCol != 0); + assert( fParamHead.fNextCol->fPrevCol == &fParamHead); + for (QcLinEqColState *curr = fParamHead.fNextCol; + curr != &fParamHead; + curr = curr->fNextCol) + { + assert( !curr->isBasic()); + assert( curr->fIndex < (int) fSize); + assert( nParams != 0); + nParams--; + } + assert( nParams == 0); + + assert( fBasicHead.fNextCol != 0); + assert( fBasicHead.fNextCol->fPrevCol == &fBasicHead); + for (QcLinEqColState *curr = fBasicHead.fNextCol; + curr != &fBasicHead; + curr = curr->fNextCol) + { + assert( curr->isBasic()); + assert( curr->getIndex() < fSize); + assert( nBasic != 0); + nBasic--; + } + assert( nBasic == 0); +} + +//o[d] protected: + +//cf +virtual void +virtualAssertLinkageInvar() const +{ + assertLinkageInvar(); +} +#endif /* !NDEBUG */ + + +//-----------------------------------------------------------------------// +// Query functions. // +//-----------------------------------------------------------------------// +//o[d] public: + +inline numT +GetDesireValue(unsigned i) const +{ + qcAssertPre (i < fSize); + return ((QcLinEqColState *)fStates[i])->fDesValue; +} + +inline bool +IsBasic(unsigned i) const +{ + qcAssertPre (i < fSize); + return ((QcLinEqColState *)fStates[i])->fIsBasic; +} + +inline int +IsBasicIn(unsigned i) const +{ + qcAssertPre (i < fSize); + return ((QcLinEqColState *)fStates[i])->fIsBasicIn; +} + + +//-----------------------------------------------------------------------// +// Set functions. // +//-----------------------------------------------------------------------// +inline void +SetDesireValue(unsigned i, numT dv) const +{ + qcAssertPre (i < fSize); + ((QcLinEqColState *)fStates[i])->fDesValue = dv; +} + +inline QcLinEqColState * +head( bool isbasic) +{ + QcLinEqColState *heads = &fParamHead; + assert( &heads[1] == &fBasicHead); + unsigned ix = isbasic; + qcAssertPre( ix <= 1); + return &heads[ix]; +} + +//cf +void +SetBasic(unsigned i, bool b) +{ + qcAssertPre( i < fSize); + qcAssertPre( (unsigned) b <= 1); + + QcLinEqColState *state = getState( i); + if (state->fIsBasic != b) + { + state->fIsBasic = b; + Unlink( state); + Link( state, head( b)); + } +} + +inline void +SetBasicIn(unsigned i, int bi) const +{ + qcAssertPre (i < fSize); + ((QcLinEqColState *)fStates[i])->fIsBasicIn = bi; +} + + +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// +//cf +virtual void +FixLinkage() +{ + dbg(assertLinkageInvar()); + +#if 0 /* shouldn't be necessary any more. */ + fBasicHead->fPrevCol = fBasicHead->fNextCol = &fBasicHead; + fParamHead->fPrevCol = fParamHead->fNextCol = &fParamHead; + QcLinEqColState heads[] = {fParamHead, fBasicHead}; + + for (unsigned i = 0; i < fSize; i++) + { + QcLinEqColState *state = getState( i); + + unsigned ix = state->isBasic(); + assert (ix <= 1); + Link( state, heads[ix]); + } + + dbg(assertLinkageInvar()); +#endif +} + + +inline void +Link(QcLinEqColState *state, QcLinEqColState *head) +{ + qcAssertPre( (head == &fParamHead) + || (head == &fBasicHead)); + qcAssertPre( (state->fNextCol == 0) + && (state->fPrevCol == 0)); + + state->fPrevCol = head; + head->fNextCol->fPrevCol = state; + state->fNextCol = head->fNextCol; + head->fNextCol = state; +} + + +inline void +Unlink(QcLinEqColState *state) +{ + qcAssertPre( (state->fNextCol != 0) + && (state->fPrevCol != 0)); + + state->fNextCol->fPrevCol = state->fPrevCol; + state->fPrevCol->fNextCol = state->fNextCol; + + dbg(state->fPrevCol = state->fNextCol = 0); +} + + +//o[d] protected: + +//cf +virtual void +Alloc(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fCapacity); + + for (unsigned i = start - fStates; + start != finish; + start++, i++) + *start = new QcLinEqColState( (int) i); +} + + +//cf +virtual void +AddToList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start < finish); + qcAssertPre( finish <= getAllocEnd()); + + for(; start != finish; start++) + { + QcLinEqColState *state = CAST(QcLinEqColState *, *start); + + assert( (state->fNextCol == 0) + && (state->fPrevCol == 0) + && (state->fDesValue == 0.0) + && (state->fIsBasic == false) + && (state->fIsBasicIn == QcTableau::fInvalidConstraintIndex)); + + Link( state, &fParamHead); + } +} + + +//cf +virtual void +RemoveFromList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fSize); + + for(; start != finish; start++) + { + QcLinEqColState *state = CAST(QcLinEqColState *, *start); + + Unlink( state); + state->fDesValue = 0.0f; + state->fIsBasic = false; + state->fIsBasicIn = QcTableau::fInvalidConstraintIndex; + } +} + +//o[d] public: + +//cf +virtual void +Print(ostream &os) const +{ + QcQuasiColStateVector::Print(os); + os << endl << "Basic variable list:" << endl; + QcLinEqColState *curr = fBasicHead.fNextCol; + + while (curr != &fBasicHead) + { + curr->Print(os); + os << endl; + curr = curr->fNextCol; + } + + os << endl << "Param variable list:" << endl; + curr = fParamHead.fNextCol; + + while (curr != &fBasicHead) + { + curr->Print(os); + os << endl; + curr = curr->fNextCol; + } +} + + +private: +inline QcLinEqColState * +getState(unsigned i) const +{ + qcAssertPre( i < fSize); + QcLinEqColState *ret = CAST(QcLinEqColState *, fStates[i]); + qcAssertPost( ret != 0); + return ret; +} + + +//begin o[d] +public: + QcLinEqColState fParamHead; // head of linked list of non-basic variables. + QcLinEqColState fBasicHead; // head of linked list of basic variables. +//end o[d] +//o[d] }; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcLinEqColStateVector.hh b/src/kits/interface/qoca/QcLinEqColStateVector.hh new file mode 100644 index 0000000000..0a7b69f4e1 --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqColStateVector.hh @@ -0,0 +1,165 @@ +// Generated automatically from QcLinEqColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcLinEqColStateVector.H" +#ifndef QcLinEqColStateVectorIFN +#define QcLinEqColStateVectorIFN +#line 1 "QcLinEqColStateVector.ch" +// $Id: QcLinEqColStateVector.ch,v 1.2 2000/12/06 05:32:56 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcQuasiColStateVector.hh" +#include "qoca/QcLinEqColState.hh" + + + + + + + +#line 49 "QcLinEqColStateVector.ch" +#ifndef NDEBUG + + + +#line 121 "QcLinEqColStateVector.ch" +#endif /* !NDEBUG */ + + +//-----------------------------------------------------------------------// +// Query functions. // +//-----------------------------------------------------------------------// + + +inline numT +QcLinEqColStateVector::GetDesireValue(unsigned i) const +{ + qcAssertPre (i < fSize); + return ((QcLinEqColState *)fStates[i])->fDesValue; +} + +inline bool +QcLinEqColStateVector::IsBasic(unsigned i) const +{ + qcAssertPre (i < fSize); + return ((QcLinEqColState *)fStates[i])->fIsBasic; +} + +inline int +QcLinEqColStateVector::IsBasicIn(unsigned i) const +{ + qcAssertPre (i < fSize); + return ((QcLinEqColState *)fStates[i])->fIsBasicIn; +} + + +//-----------------------------------------------------------------------// +// Set functions. // +//-----------------------------------------------------------------------// +inline void +QcLinEqColStateVector::SetDesireValue(unsigned i, numT dv) const +{ + qcAssertPre (i < fSize); + ((QcLinEqColState *)fStates[i])->fDesValue = dv; +} + +inline QcLinEqColState * +QcLinEqColStateVector::head( bool isbasic) +{ + QcLinEqColState *heads = &fParamHead; + assert( &heads[1] == &fBasicHead); + unsigned ix = isbasic; + qcAssertPre( ix <= 1); + return &heads[ix]; +} + + +#line 187 "QcLinEqColStateVector.ch" +inline void +QcLinEqColStateVector::SetBasicIn(unsigned i, int bi) const +{ + qcAssertPre (i < fSize); + ((QcLinEqColState *)fStates[i])->fIsBasicIn = bi; +} + + +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + +#line 223 "QcLinEqColStateVector.ch" +inline void +QcLinEqColStateVector::Link(QcLinEqColState *state, QcLinEqColState *head) +{ + qcAssertPre( (head == &fParamHead) + || (head == &fBasicHead)); + qcAssertPre( (state->fNextCol == 0) + && (state->fPrevCol == 0)); + + state->fPrevCol = head; + head->fNextCol->fPrevCol = state; + state->fNextCol = head->fNextCol; + head->fNextCol = state; +} + + +inline void +QcLinEqColStateVector::Unlink(QcLinEqColState *state) +{ + qcAssertPre( (state->fNextCol != 0) + && (state->fPrevCol != 0)); + + state->fNextCol->fPrevCol = state->fPrevCol; + state->fPrevCol->fNextCol = state->fNextCol; + + dbg(state->fPrevCol = state->fNextCol = 0); +} + + + + + +#line 340 "QcLinEqColStateVector.ch" +inline QcLinEqColState * +QcLinEqColStateVector::getState(unsigned i) const +{ + qcAssertPre( i < fSize); + QcLinEqColState *ret = CAST(QcLinEqColState *, fStates[i]); + qcAssertPost( ret != 0); + return ret; +} + + + +#line 358 "QcLinEqColStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcLinEqColStateVectorIFN */ diff --git a/src/kits/interface/qoca/QcLinEqRowColStateVector.hh b/src/kits/interface/qoca/QcLinEqRowColStateVector.hh new file mode 100644 index 0000000000..a8c3e938b4 --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqRowColStateVector.hh @@ -0,0 +1,169 @@ +// $Id: QcLinEqRowColStateVector.hh,v 1.8 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcLinEqRowColStateVectorH +#define __QcLinEqRowColStateVectorH + +#include "qoca/QcQuasiRowColStateVector.hh" +#include "qoca/QcLinEqRowStateVector.hh" +#include "qoca/QcLinEqColStateVector.hh" + +class QcLinEqRowColStateVector : public QcQuasiRowColStateVector +{ +public: + QcLinEqRowStateVector *fRowState; + QcLinEqColStateVector *fColState; + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcLinEqRowColStateVector(); + QcLinEqRowColStateVector(QcLinEqColStateVector *csv); + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + QcLinEqRowStateVector &GetRowState() const + { return *fRowState; } + + QcLinEqColStateVector &GetColState() const + { return *fColState; } + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + virtual void SwapColumns(unsigned v1, unsigned v2); +#if 0 /* unused */ + virtual void SwapRows(unsigned c1, unsigned c2); +#endif +}; + +inline QcLinEqRowColStateVector::QcLinEqRowColStateVector() + : QcQuasiRowColStateVector(new QcLinEqRowStateVector(), + new QcLinEqColStateVector()) +{ + fRowState = (QcLinEqRowStateVector *)QcQuasiRowColStateVector::fRowState; + fColState = (QcLinEqColStateVector *)QcQuasiRowColStateVector::fColState; +} + +inline QcLinEqRowColStateVector::QcLinEqRowColStateVector( + QcLinEqColStateVector *csv) + : QcQuasiRowColStateVector(new QcLinEqRowStateVector(), csv) +{ + fRowState = (QcLinEqRowStateVector *)QcQuasiRowColStateVector::fRowState; + fColState = (QcLinEqColStateVector *)QcQuasiRowColStateVector::fColState; +} + +inline void QcLinEqRowColStateVector::SwapColumns(unsigned v1, unsigned v2) +{ + qcAssertPre( v1 < fColState->getNColumns()); + qcAssertPre( v2 < fColState->getNColumns()); + + if (v1 == v2) + return; + + QcLinEqColState *r1 = (QcLinEqColState *)fColState->GetState(v1); + QcLinEqColState *r2 = (QcLinEqColState *)fColState->GetState(v2); + + // Swap col references in fRowState + { + int c1 = r1->getConstraintBasicIn(); + int c2 = r2->getConstraintBasicIn(); + + if (c1 != QcTableau::fInvalidConstraintIndex) + fRowState->SetBasicVar( c1, v2); + + if (c2 != QcTableau::fInvalidConstraintIndex) + fRowState->SetBasicVar( c2, v1); + } + + // Exchange the data contents (excluding the Index field) + { + int isbin = r1->getConstraintBasicIn(); + r1->fIsBasicIn = r2->getConstraintBasicIn(); + r2->fIsBasicIn = isbin; + } + { + numT dv = r1->fDesValue; + r1->fDesValue = r2->fDesValue; + r2->fDesValue = dv; + } + + // Now fix up the linkage + if (r1->fIsBasic != r2->fIsBasic) + { // N.B. its an unordered list! + if (r2->fIsBasic) + { // Make r1-> original basic + QcLinEqColState *temp = r2; // and r2-> original parameter + r2 = r1; + r1 = temp; + } + assert( r1->fIsBasic && !r2->fIsBasic); + + // First, the Basic vars linked list + fColState->Unlink( r1); + fColState->Unlink( r2); + + // Finally, swap over the descriminator. + r1->fIsBasic = false; + r2->fIsBasic = true; + + fColState->Link( r1, &fColState->fParamHead); + fColState->Link( r2, &fColState->fBasicHead); + } +} + +#if 0 /* unused */ +inline void QcLinEqRowColStateVector::SwapRows(unsigned c1, unsigned c2) +{ + qcAssertPre( c1 < fRowState->getNRows()); + qcAssertPre( c2 < fRowState->getNRows()); + + if (c1 == c2) + return; + + QcLinEqRowState *r1 = (QcLinEqRowState *)fRowState->GetState(c1); + QcLinEqRowState *r2 = (QcLinEqRowState *)fRowState->GetState(c2); + + // Swap row references in ColState + int v1 = r1->fBasicVar; + int v2 = r2->fBasicVar; + + if (v1 != QcTableau::fInvalidVariableIndex) + fColState->SetBasicIn(v1, c2); + + if (v2 != QcTableau::fInvalidVariableIndex) + fColState->SetBasicIn(v2, c1); + + // Swap fCondition, fBasicVar + r1->swap( *r2); + + // Swap lower level properties + QcQuasiRowColStateVector::SwapRows(c1, c2); +} +#endif /* unused */ + +#endif /* !__QcLinEqRowColStateVectorH */ diff --git a/src/kits/interface/qoca/QcLinEqRowState.hh b/src/kits/interface/qoca/QcLinEqRowState.hh new file mode 100644 index 0000000000..a38d77f933 --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqRowState.hh @@ -0,0 +1,135 @@ +// $Id: QcLinEqRowState.hh,v 1.4 2000/12/13 01:44:58 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// The class QcBiMap provides a bi-directional mapping from // +// identifier class to index class. // +//============================================================================// + +#ifndef __QcLinEqRowStateH +#define __QcLinEqRowStateH + +#include "qoca/QcQuasiRowState.hh" +#include "qoca/QcTableau.hh" + +class QcLinEqRowState : public QcQuasiRowState +{ +public: + enum { + fInvalid = 0, + fNormalised = 1, + fRegular = 2, + fRedundant = 3 + }; + // If any row is normalised then the tableau is not in solved form + // (undetermined means invalid or normalised). + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcLinEqRowState(int ci); + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os); + + int getCondition() const + { + dbg(assertValidCondition( fCondition)); + return fCondition; + } + + void setCondition(int c) + { + dbg(assertValidCondition( c)); + fCondition = c; + } + + void swap(QcLinEqRowState &other) + { + // Swap fCondition + { + int tmp = fCondition; + + fCondition = other.fCondition; + other.fCondition = tmp; + } + + // Swap fBasicVar + { + int tmp = fBasicVar; + + fBasicVar = other.fBasicVar; + other.fBasicVar = tmp; + } + } + +private: +#ifndef NDEBUG + void assertValidCondition(int c) const + { + assert( (unsigned) c <= 3); + } +#endif + +private: + int fCondition; +public: + int fBasicVar; // The basic variable for a regular row else + // fInvalidVariableIndex. +}; + +inline QcLinEqRowState::QcLinEqRowState(int ci) + : QcQuasiRowState(ci) +{ + fCondition = fInvalid; + fBasicVar = QcTableau::fInvalidVariableIndex; +} + +inline void QcLinEqRowState::Print(ostream &os) +{ + QcQuasiRowState::Print(os); + + os << ",Cond("; + + switch (fCondition) { + case fInvalid: + os << "Invalid"; + break; + case fNormalised: + os << "Normalised"; + break; + case fRegular: + os << "Regular"; + break; + case fRedundant: + os << "Redundant"; + break; + } + + os << "), BasicVar(" << fBasicVar << ")"; +} + +#endif diff --git a/src/kits/interface/qoca/QcLinEqRowStateVector.H b/src/kits/interface/qoca/QcLinEqRowStateVector.H new file mode 100644 index 0000000000..d94d1fd6ad --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqRowStateVector.H @@ -0,0 +1,99 @@ +// Generated automatically from QcLinEqRowStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcLinEqRowStateVectorDCL +#define QcLinEqRowStateVectorDCL +#line 1 "QcLinEqRowStateVector.ch" +// $Id: QcLinEqRowStateVector.ch,v 1.3 2000/12/13 01:44:58 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include + +#include + +class QcLinEqRowStateVector + : public QcQuasiRowStateVector +{ +public: + + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcLinEqRowStateVector() + : QcQuasiRowStateVector() + { } + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + int GetBasicVar(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcLinEqRowState *)fStates[i])->fBasicVar; + } + + int GetCondition(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcLinEqRowState *)fStates[i])->getCondition(); + } + + //-----------------------------------------------------------------------// + // Set functions. // + //-----------------------------------------------------------------------// + void SetBasicVar(unsigned i, int vi) + { + qcAssertPre (i < fSize); + ((QcLinEqRowState *)fStates[i])->fBasicVar = vi; + } + + void SetCondition(unsigned i, int c) + { + qcAssertPre (i < fSize); + ((QcLinEqRowState *)fStates[i])->setCondition( c); + } + + + + +virtual void +Alloc(QcState **start, QcState **finish); +#line 91 "QcLinEqRowStateVector.ch" +virtual void +RemoveFromList(QcState **start, QcState **finish); +#line 108 "QcLinEqRowStateVector.ch" +}; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcLinEqRowStateVectorDCL */ diff --git a/src/kits/interface/qoca/QcLinEqRowStateVector.cc b/src/kits/interface/qoca/QcLinEqRowStateVector.cc new file mode 100644 index 0000000000..14c2434a8b --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqRowStateVector.cc @@ -0,0 +1,82 @@ +// Generated automatically from QcLinEqRowStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcLinEqRowStateVector.hh" +#line 1 "QcLinEqRowStateVector.ch" +// $Id: QcLinEqRowStateVector.ch,v 1.3 2000/12/13 01:44:58 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + + + +#include + + + + + + + +#line 77 "QcLinEqRowStateVector.ch" +void +QcLinEqRowStateVector::Alloc(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fCapacity); + + for (unsigned i = start - fStates; + start != finish; + start++, i++) + *start = new QcLinEqRowState( i); +} + + +void +QcLinEqRowStateVector::RemoveFromList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fSize); + + for(; start != finish; start++) + { + QcLinEqRowState *state = CAST(QcLinEqRowState *, *start); + + state->setCondition( QcLinEqRowState::fInvalid); + state->fBasicVar = QcTableau::fInvalidVariableIndex; + QcQuasiRowStateVector::Restart( start - fStates); + } +} + + + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcLinEqRowStateVector.ch b/src/kits/interface/qoca/QcLinEqRowStateVector.ch new file mode 100644 index 0000000000..36a3281487 --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqRowStateVector.ch @@ -0,0 +1,118 @@ +// $Id: QcLinEqRowStateVector.ch,v 1.3 2000/12/13 01:44:58 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +//o[d] #include +//o[i] #include +#include + +//o[d] class QcLinEqRowStateVector +//o[d] : public QcQuasiRowStateVector +//o[d] { +//o[d] public: + +//begin o[d] + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcLinEqRowStateVector() + : QcQuasiRowStateVector() + { } + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + int GetBasicVar(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcLinEqRowState *)fStates[i])->fBasicVar; + } + + int GetCondition(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcLinEqRowState *)fStates[i])->getCondition(); + } + + //-----------------------------------------------------------------------// + // Set functions. // + //-----------------------------------------------------------------------// + void SetBasicVar(unsigned i, int vi) + { + qcAssertPre (i < fSize); + ((QcLinEqRowState *)fStates[i])->fBasicVar = vi; + } + + void SetCondition(unsigned i, int c) + { + qcAssertPre (i < fSize); + ((QcLinEqRowState *)fStates[i])->setCondition( c); + } +//end o[d] + + +//cf +virtual void +Alloc(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fCapacity); + + for (unsigned i = start - fStates; + start != finish; + start++, i++) + *start = new QcLinEqRowState( i); +} + +//cf +virtual void +RemoveFromList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fSize); + + for(; start != finish; start++) + { + QcLinEqRowState *state = CAST(QcLinEqRowState *, *start); + + state->setCondition( QcLinEqRowState::fInvalid); + state->fBasicVar = QcTableau::fInvalidVariableIndex; + QcQuasiRowStateVector::Restart( start - fStates); + } +} + +//o[d] }; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcLinEqRowStateVector.hh b/src/kits/interface/qoca/QcLinEqRowStateVector.hh new file mode 100644 index 0000000000..2c229263a4 --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqRowStateVector.hh @@ -0,0 +1,52 @@ +// Generated automatically from QcLinEqRowStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcLinEqRowStateVector.H" +#ifndef QcLinEqRowStateVectorIFN +#define QcLinEqRowStateVectorIFN +#line 1 "QcLinEqRowStateVector.ch" +// $Id: QcLinEqRowStateVector.ch,v 1.3 2000/12/13 01:44:58 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + + +#include +#include + + + + + + + +#line 111 "QcLinEqRowStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcLinEqRowStateVectorIFN */ diff --git a/src/kits/interface/qoca/QcLinEqSolver.cc b/src/kits/interface/qoca/QcLinEqSolver.cc new file mode 100644 index 0000000000..45884d2c89 --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqSolver.cc @@ -0,0 +1,459 @@ +// $Id: QcLinEqSolver.cc,v 1.16 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcDesireValueStore.hh" +#include "qoca/QcLinEqSolver.hh" +#include "qoca/QcParamVarIndexIterator.hh" +#include "qoca/QcTableauColIterator.hh" +#include "qoca/QcBasicVarIndexIterator.hh" +#include "qoca/QcSparseMatrixRowIterator.hh" +#include "qoca/QcVariableIndexIterator.hh" + +#ifndef NDEBUG +void QcLinEqSolver::assertDeepInvar() const +{ + QcSolver::assertDeepInvar(); + fSystem.vAssertDeepInvar(); +} + +void QcLinEqSolver::vAssertDeepInvar() const +{ + assertDeepInvar(); +} +#endif + +void QcLinEqSolver::BeginEdit() +{ + vector::iterator voiIt; + vector::iterator viIt; + + // build a version of fEditVars by index. + fVarsByIndex.resize(0); + for (voiIt = fEditVars.begin(); voiIt != fEditVars.end(); ++voiIt) + fVarsByIndex.push_back(fVBiMap.Index(*voiIt)); + + fSubSystem.Restart(); + TransitiveClosure(); // Calculates fDepPars and fDepBasicVars + + // Create a variable for the desired value of each EditVars. + // Also set fSubSystem EditVars to this->EditVars. + fDesValVar.resize( fTableau.getNColumns()); + for (unsigned i = 0; i < fVarsByIndex.size(); i++) + { + unsigned vi = fVarsByIndex[i]; + assert( vi < fTableau.getNColumns()); + fSubSystem.RegisterEditVar( fDesValVar[vi] = QcFloat( "desired value")); + } + + // Make a copy of a matrix of coefficients to speed up GenerateKT1. + QcSparseMatrix ccache; + ccache.Resize(fTableau.GetRows(), fTableau.GetColumns()); + QcParamVarIndexIterator vIt(fTableau); + + while (!vIt.AtEnd()) { + QcTableauColIterator colCoeffs (fTableau, vIt.getIndex()); + while (!colCoeffs.AtEnd()) { + ccache.SetValue(colCoeffs.getIndex(), vIt.getIndex(), colCoeffs.getValue()); + colCoeffs.Increment(); + } + vIt.Increment(); + } + + #ifndef qcRealTableauRHS + vector crhs; + crhs.Resize(fTableau.GetRows()); + for (int r = 0; r < fTableau.GetRows(); r++) + crhs[r] = fTableau.GetRHS(r); + #endif + + // Generate subsystem KT constraint for each dependent parameter + // Also set fSystem EditVars to fDepPars. + fSystem.ClearEditVars(); + for (viIt = fDepPars.begin(); viIt != fDepPars.end(); ++viIt) { + QcFloat &v = fVBiMap.Identifier(*viIt); + // N.B. constraint may be needed even when v is free + GenerateKT2(v, ccache +#ifndef qcRealTableauRHS + , crhs +#endif + ); + fSystem.RegisterEditVar(v); + } + + fSubSystem.BeginEdit(); + fEditVarsSetup = true; + dbg(assertInvar()); +} + +void QcLinEqSolver::EndEdit() +{ + vector::const_iterator vIt; + + for (unsigned int vi = 0; vi < fDepBasicVars.size(); ++vi) + if (fDepBasicVars[vi]) + fVBiMap.Identifier(vi).RestVariable(); + + for (vIt = fDepPars.begin(); vIt != fDepPars.end(); ++vIt) + fVBiMap.Identifier(*vIt).RestVariable(); + + QcSolver::EndEdit(); + dbg(assertInvar()); +} + +void QcLinEqSolver::GenerateKT1(QcFloat &p, QcSparseMatrix &ccache +#ifndef qcRealTableauRHS + , vector &crhs +#endif +) + // Generate the constraint df'/dp == 0 + // where f' = least squares objective function with basic variables + // eliminated. Add the constraint to the subsystem fSubSystem. + // It is important that this routine does not rely on + // the values of any of the variables being a solution of LinEq. + // See note in QcLinEqSolver::Solve. +{ +#ifndef qcRealTableauRHS + qcAssertPre (crhs.size() == ccache.getNRows()); +#endif + + QcLinPoly lpoly; // N.B. lpoly is destroyed when this routine returns + numT rhs = 0.0; + int pIndex = fVBiMap.Index(p); + numT pWeight2 = p.Weight() * 2; + numT pAccumulator = pWeight2; + + QcBasicVarIndexIterator bvIt(fTableau); + + while (!bvIt.AtEnd()) { + QcFloat &bv = fVBiMap.Identifier(bvIt.getIndex()); + unsigned c = bvIt.getConstraintBasicIn(); // use constraint c to eliminate bv + assert (c < ccache.getNRows()); + numT pCoeff = ccache.GetValue(c, pIndex); + numT factor = bv.Weight() * pCoeff * 2; + pAccumulator += factor * pCoeff; + + QcSparseMatrixRowIterator varCoeffs(ccache, c); + while (!varCoeffs.AtEnd()) { + QcFloat &pv = fVBiMap.Identifier(varCoeffs.GetIndex()); + int pvIndex = varCoeffs.GetIndex(); + + if (pvIndex!=pIndex) + lpoly += QcLinPolyTerm(factor * varCoeffs.GetValue(), pv); + + varCoeffs.Increment(); + } + #ifdef qcRealTableauRHS + rhs += factor * (fTableau.GetRHS(c) - bv.DesireValue()); + #else + rhs += factor * (crhs[c] - bv.GetDesValue()); + #endif + bvIt.Increment(); + } + + lpoly.Push(pAccumulator, p); + rhs += pWeight2 * p.DesireValue(); + + QcConstraint kt("", lpoly, QcConstraintRep::coEQ, rhs); + + #ifdef qcSafetyChecks + if (!fSubSystem.AddConstraint(kt)) + throw QcWarning("QcLinEqSolver::GenerateKT1: subsystem inconsistant"); + #else + fSubSystem.AddConstraint(kt); + #endif +} + +void QcLinEqSolver::GenerateKT2(QcFloat &p, QcSparseMatrix &ccache +#ifndef qcRealTableauRHS + , vector &crhs +#endif + ) + // Generate the constraint df'/dp == 0 where parameters of interest + // have variable desired values and where f' = least squares + // objective function with basic variables eliminated. + // Add the constraint to the subsystem fSubSystem. +{ +#ifndef qcRealTableauRHS + qcAssertPre (crhs.size() == ccache.getNRows()); +#endif + + QcLinPoly lpoly; // N.B. lpoly is destroyed when this routine returns + numT rhs = 0.0; + int pIndex = fVBiMap.Index(p); + numT pWeight2 = p.Weight() * 2; + numT pAccumulator = pWeight2; + QcFloat &pDV = fDesValVar[pIndex]; + + QcBasicVarIndexIterator bvIt(fTableau); + + while (!bvIt.AtEnd()) { + unsigned bvi = bvIt.getIndex(); + QcFloat &bv = fVBiMap.Identifier(bvi); + unsigned c = bvIt.getConstraintBasicIn(); // use constraint c to eliminate bv + assert (c < ccache.getNRows()); + numT pCoeff = ccache.GetValue(c, pIndex); + numT factor = bv.Weight() * pCoeff * 2; + pAccumulator += factor * pCoeff; + + QcSparseMatrixRowIterator varCoeffs(ccache, c); + while (!varCoeffs.AtEnd()) { + QcFloat &pv = fVBiMap.Identifier(varCoeffs.GetIndex()); + int pvIndex = varCoeffs.GetIndex(); + + if (pvIndex!=pIndex) + lpoly += QcLinPolyTerm(factor * varCoeffs.GetValue(), pv); + + varCoeffs.Increment(); + } + if (IsDepBasicVar(bvi) && IsEditVar(bv)) { + #ifdef qcRealTableauRHS + rhs += factor * fTableau.GetRHS(c); + #else + rhs += factor * crhs[c]; + #endif + lpoly += QcLinPolyTerm(factor, fDesValVar[bvi]); + } else { + #ifdef qcRealTableauRHS + rhs += factor * (fTableau.GetRHS(c) - bv.DesireValue()); + #else + rhs += factor * (crhs[c] - bv.GetDesValue()); + #endif + } + bvIt.Increment(); + } + + lpoly.Push(pAccumulator, p); + + if (IsEditVar(p)) + lpoly.Push(-pWeight2, pDV); + else + rhs += pWeight2 * p.DesireValue(); + + QcConstraint kt("", lpoly, QcConstraintRep::coEQ, rhs); + + #ifdef qcSafetyChecks + if (!fSubSystem.AddConstraint(kt)) + throw QcWarning("QcLinEqSolver::GenerateKT2: subsystem inconsistant"); + #else + fSubSystem.AddConstraint(kt); + #endif +} + +bool QcLinEqSolver::IsDepPar(int vi) const +{ + if (vi < 0) /* TODO: We can probably assertPre (vi > 0). Similarly for other IsDepPar implementations. */ + return false; + + vector::const_iterator it; + for (it = fDepPars.begin(); it != fDepPars.end(); ++it) + if ((*it) == (unsigned) vi) + return true; + return false; +} + +numT QcLinEqSolver::Objective() +{ + numT opt = 0.0; + QcVariableIndexIterator vIt(fTableau); + + while (!vIt.AtEnd()) { + QcFloat &v = fVBiMap.Identifier(vIt.getIndex()); + numT delta = v.Value() - v.DesireValue(); + opt += v.Weight() * delta * delta; + vIt.Increment(); + } + + return opt; +} + +void QcLinEqSolver::Resolve() +{ + if (!fEditVarsSetup) + BeginEdit(); + + // Setup the desired value variables. + assert( fVarsByIndex.size() == fEditVars.size()); + for (unsigned i = 0; i < fVarsByIndex.size(); i++) + { + unsigned vi = fVarsByIndex[i]; + assert( vi < fDesValVar.size()); + fDesValVar[vi].SuggestValue( fEditVars[i].DesireValue()); + } + + fSubSystem.Resolve(); + + /* effic: The handling of saveDesireValue (both here and in Solve) could + be improved: we do a lot of unnecessary construction and + deconstruction. */ + vector saveDesireValue; + + // The dependent variables have their desired values altered + // according to the value found by the subsystem solve. + for (vector::const_iterator vIt = fDepPars.begin(); + vIt != fDepPars.end(); + ++vIt) + { + QcFloatRep *vr = fVBiMap.getIdentifierPtr( *vIt); + saveDesireValue.push_back( QcDesireValueStore( vr)); + if (!vr->RestDesVal_changed()) + saveDesireValue.pop_back(); + } + + fSystem.Resolve(); + + // Restore the altered desired values. + for (vector::iterator irdv = saveDesireValue.begin(), irdvEnd = saveDesireValue.end(); + irdv != irdvEnd; + irdv++) + irdv->Restore(); + +#if qcCheckPost + checkSatisfied(); + dbg(assertInvar()); +#endif +} + +void QcLinEqSolver::Solve() +{ + // Make a copy of a matrix of coefficients to speed up GenerateKT1. + QcSparseMatrix ccache; + ccache.Resize(fTableau.GetRows(), fTableau.GetColumns()); + QcParamVarIndexIterator vIt(fTableau); + + while (!vIt.AtEnd()) { + QcTableauColIterator colCoeffs (fTableau, vIt.getIndex()); + while (!colCoeffs.AtEnd()) { + ccache.SetValue (colCoeffs.getIndex(), vIt.getIndex(), colCoeffs.getValue()); + colCoeffs.Increment(); + } + vIt.Increment(); + } + + #ifndef qcRealTableauRHS + vector crhs; + crhs.Resize(tableau.GetRows()); + for (int r = 0; r < fTableau.GetRows(); r++) + crhs[r] = fTableau.GetRHS(r); + #endif + + // Generate a subsystem constraint for each parametric variable. + fSubSystem.Restart(); + vIt.Reset(); + + while (!vIt.AtEnd()) { + unsigned vi = vIt.getIndex(); + // The test avoids entering a redundant constraint in + // the subsystem to save time. Also, there is no need to + // call v.Set when the variable is free since this will be + // done when LinEq::Solve() is called later. + if (!fTableau.IsFree(vi)) + GenerateKT1(fVBiMap.Identifier(vi), ccache +#ifndef qcRealTableauRHS + , crhs +#endif + ); + vIt.Increment(); + } + + fSubSystem.Solve(); + + vector saveDesireValue; + + // At this point we have final values for the non-free parametric + // variables. Set the desired values and solve the original system + // again to get the values for the basic variables. + // Make a record of the altered desired values. + for (QcBasicVarIndexIterator bvIt( fSubSystem.GetTableau()); + !bvIt.AtEnd(); + bvIt.Increment()) + { + unsigned ix = bvIt.getIndex(); + assert( fSubSystem.GetTableau().IsBasic( ix)); + QcFloatRep *vr = fSubSystem.GetVBiMap().getIdentifierPtr( ix); + saveDesireValue.push_back( QcDesireValueStore( vr)); + if (!vr->RestDesVal_changed()) + saveDesireValue.pop_back(); + } + + fSystem.Solve(); + + // Restore the altered desired values + for (vector::iterator irdv = saveDesireValue.begin(), irdvEnd = saveDesireValue.end(); + irdv != irdvEnd; + irdv++) + irdv->Restore(); + + // And now the variable values provide the solution. + +#if qcCheckPost + checkSatisfied(); +#endif +} + +void QcLinEqSolver::TransitiveClosure() +{ + vector depVars(fVarsByIndex); + fSystem.TransitiveClosure(depVars); + + // Sift depVars into fDepPars and fDepBasicVars. + fDepBasicVars.resize( fTableau.getNColumns()); + + for (unsigned int i = 0; i < fDepBasicVars.size(); i++) + fDepBasicVars[i] = false; + + fDepPars.resize(0); + + for (unsigned i = 0; i < depVars.size(); i++) + { + unsigned vi = depVars[i]; + + if (fTableau.IsBasic( vi)) + fDepBasicVars[vi] = true; + else + fDepPars.push_back( vi); + } +} + +void QcLinEqSolver::Print(ostream &os) const +{ + fSystem.Print(os); + + if (fEditVarsSetup) { + os << "Subsystem:" << endl; + fSubSystem.Print(os); + os << endl << "fDepBasicVars is:"; + + for (unsigned int i = 0; i < fDepBasicVars.size(); i++) + if (fDepBasicVars[i]) + os << i << ", "; + + os << endl << "fDepPars is:"; + + for (unsigned int i = 0; i < fDepPars.size(); i++) + os << fDepPars[i] << ", "; + } +} diff --git a/src/kits/interface/qoca/QcLinEqSolver.hh b/src/kits/interface/qoca/QcLinEqSolver.hh new file mode 100644 index 0000000000..af3d3f21e3 --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqSolver.hh @@ -0,0 +1,247 @@ +// $Id: QcLinEqSolver.hh,v 1.12 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// This interface needs to be read in conjuction with that of Solver. // +//============================================================================// + +#ifndef __QcEqSolverH +#define __QcEqSolverH + +#include "qoca/QcDelLinEqSystem.hh" + +class QcLinEqSolver : public QcSolver +{ +protected: + QcDelLinEqSystem fSystem; + #if defined(qcRealTableauCoeff) || defined(qcRealTableauRHS) + QcLinEqSystem fSubSystem; + #else + QcDelLinEqSystem fSubSystem; + #endif + vector fDesValVar; + vector fDepPars; + vector fVarsByIndex; + vector fDepBasicVars; + + QcVariableBiMap &fVBiMap; + const QcBiMapNotifier &fNotifier; + QcConstraintBiMap &fOCBiMap; + QcDelLinEqTableau &fTableau; + +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcLinEqSolver(); + QcLinEqSolver(unsigned hintNumConstraints, unsigned hintNumVariables); + +#ifndef NDEBUG + void assertInvar() const { } + void assertDeepInvar() const; + virtual void vAssertDeepInvar() const; +#endif + + //-----------------------------------------------------------------------// + // Variable management methods // + //-----------------------------------------------------------------------// + virtual void AddVar(QcFloat &v) + { fSystem.AddVar(v); } + + virtual void SuggestValue(QcFloat &v, numT desval) + { fSystem.SuggestValue(v, desval); } + + virtual bool RemoveVar(QcFloat &v) + { return fSystem.RemoveVar(v); } + + virtual void RestSolver() + { fSystem.RestSolver(); } + + //-----------------------------------------------------------------------// + // Enquiry functions for variables // + //-----------------------------------------------------------------------// + virtual bool IsRegistered(QcFloat const &v) const + { return fSystem.IsRegistered(v); } + + virtual bool IsFree(QcFloat const &v) const + { return fSystem.IsFree(v); } + + virtual bool IsBasic(QcFloat const &v) const + { return fSystem.IsBasic(v); } + + bool IsDepBasicVar(unsigned vi) const + { + qcAssertPre( vi < fDepBasicVars.size()); + return fDepBasicVars[vi]; + } + + bool IsDepPar(int vi) const; + + //-----------------------------------------------------------------------// + // High Level Edit Variable Interface for use by solver clients. // + //-----------------------------------------------------------------------// + virtual void BeginEdit(); + virtual void EndEdit(); + + //-----------------------------------------------------------------------// + // Constraint management methods // + //-----------------------------------------------------------------------// + virtual bool AddConstraint(QcConstraint &c); + virtual bool AddConstraint(QcConstraint &c, QcFloat &hint); + + virtual bool ChangeConstraint(QcConstraint &oldc, numT rhs); + + virtual bool RemoveConstraint(QcConstraint &c); + + virtual bool Reset() + { return fSystem.Reset(); } + + //-----------------------------------------------------------------------// + // Constraint Solving methods // + //-----------------------------------------------------------------------// + virtual void Solve(); + // IMPORTANT NOTE. + // It is is not necessary to call QcLinEqSystem::solve() before + // creating and solving the subsystem since the subsystem + // is created without using the values of any variables - just + // desired values and weights. + virtual void Resolve(); + +protected: + numT Objective(); + + //-----------------------------------------------------------------------// + // Sub-system specific functions. // + //-----------------------------------------------------------------------// + void GenerateKT1(QcFloat &p, QcSparseMatrix &ccache +#ifndef qcRealTableauRHS + , vector &crhs +#endif + ); + // Generate the constraint df'/dp == 0 + // where f' = least squares objective function with basic variables + // eliminated. Add the constraint to the subsystem fSubSystem. + // It is important that this routine does not rely on + // the values of any of the variables being a solution of LinEq. + // See note in QcLinEqSolver::Solve. + + void GenerateKT2(QcFloat &p, QcSparseMatrix &ccache +#ifndef qcRealTableauRHS + , vector &crhs +#endif + ); + // Generate the constraint df'/dp == 0 where parameters of interest + // have variable desired values and where f' = least squares + // objective function with basic variables eliminated. + // Add the constraint to the subsystem fSubSystem. + + void TransitiveClosure(); + // Calculates dependent basic variables and parameters as transitive + // closure of VOI using the relation "belongs to same constraint". + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + QcConstraint GetConstraint(const char *n) + { return fSystem.GetConstraint(n); } + + QcFloat GetVariable(const char *n) + { return fSystem.GetVariable(n); } + + void GetVariableSet(vector &vars) + { fSystem.GetVariableSet(vars); } + + virtual void QcLinEqSolver::Print(ostream &os) const; +}; + +inline QcLinEqSolver::QcLinEqSolver() + : QcSolver(), + fVBiMap(fSystem.GetVBiMap()), + fNotifier(fSystem.GetNotifier()), + fOCBiMap(fSystem.GetOCBiMap()), + fTableau((QcDelLinEqTableau &)fSystem.GetTableau()) +{ +} + +inline QcLinEqSolver::QcLinEqSolver(unsigned hintNumConstraints, unsigned hintNumVariables) + : QcSolver(), + fSystem(hintNumConstraints, hintNumVariables), + fSubSystem(hintNumConstraints, hintNumVariables), + fVBiMap(fSystem.GetVBiMap()), + fNotifier(fSystem.GetNotifier()), + fOCBiMap(fSystem.GetOCBiMap()), + fTableau((QcDelLinEqTableau &)fSystem.GetTableau()) +{ +} + +inline bool QcLinEqSolver::AddConstraint(QcConstraint &c) +{ + bool success = fSystem.AddConstraint(c); + if (success) { +#if qcCheckPost + addCheckedConstraint( c.pointer()); +#endif + if (fAutoSolve) + Solve(); + } + return success; +} + +inline bool QcLinEqSolver::AddConstraint(QcConstraint &c, QcFloat &hint) +{ + bool success = fSystem.AddConstraint(c, hint); + if (success) { +#if qcCheckPost + addCheckedConstraint( c.pointer()); +#endif + if (fAutoSolve) + Solve(); + } + return success; +} + +inline bool QcLinEqSolver::ChangeConstraint(QcConstraint &oldc, numT rhs) +{ + bool success = fSystem.ChangeConstraint(oldc, rhs); +#if qcCheckPost + if (success) + changeCheckedConstraint( oldc.pointer(), rhs); +#endif + return success; +} + +inline bool QcLinEqSolver::RemoveConstraint(QcConstraint &c) +{ + bool success = fSystem.RemoveConstraint(c); + if (success) { +#if qcCheckPost + removeCheckedConstraint( c.pointer()); +#endif + if (fAutoSolve) + Solve(); + } + return success; +} + +#endif diff --git a/src/kits/interface/qoca/QcLinEqSystem.cc b/src/kits/interface/qoca/QcLinEqSystem.cc new file mode 100644 index 0000000000..bad21381cf --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqSystem.cc @@ -0,0 +1,539 @@ +// $Id: QcLinEqSystem.cc,v 1.14 2001/01/31 07:37:13 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// Unlike identifiers, indexes start from 0 since they are used as array and // +// matrix subscripts in the tableau. // +//============================================================================// + +#include +#include "qoca/QcDefines.hh" +#include "qoca/QcLinEqSystem.hh" +#include "qoca/QcRowAdaptor.hh" +#include "qoca/QcTableauRowIterator.hh" +#include "qoca/QcTableauColIterator.hh" +#include "qoca/QcBasicVarIndexIterator.hh" +#include "qoca/QcVariableIndexIterator.hh" +#include "qoca/QcConstraintIndexIterator.hh" +#include "qoca/QcDenseTableauRowIterator.hh" + +#if qcCheckInternalInvar +void QcLinEqSystem::assertDeepInvar() const +{ + QcSolver::assertDeepInvar(); + fVBiMap.vAssertDeepInvar(); + fNotifier.vAssertDeepInvar(); + fOCBiMap.vAssertDeepInvar(); + fTableau.vAssertDeepInvar(); +} + +void QcLinEqSystem::vAssertDeepInvar() const +{ + assertDeepInvar(); +} +#endif + + +bool QcLinEqSystem::AddConstraint(QcConstraint &c) +{ + return doAddConstraint(c, -1); +} + +bool QcLinEqSystem::AddConstraint(QcConstraint &c, QcFloat &hint) +{ +#if qcCheckPre + int hintIx = fVBiMap.safeIndex(hint); + qcAssertExternalPre(hintIx >= 0); +#else + int hintIx = fVBiMap.Index(hint); +#endif + + return doAddConstraint(c, hintIx); +} + + +bool QcLinEqSystem::doAddConstraint(QcConstraint &c, int hintIx) +{ + qcAssertExternalPre(c.getRelation() == QcConstraintRep::coEQ); + + if (fBatchAddConst && fBatchAddConstFail) + return false; + + QcRowAdaptor ra(c.LinPoly(), fVBiMap, fTableau); + bool success = true; + + int co = fTableau.AddEq(ra, c.RHS()); // co is original constraint index + int cs = fTableau.Eliminate(co); // cs is solved form constraint index + + if (hintIx >= 0) { + fTableau.fPivotHints.clear(); + fTableau.fPivotHints.push_back(hintIx); + } + + if (cs == QcTableau::fInvalidConstraintIndex) { + fInconsistant.push_back(c); + success = false; + } else if (!fTableau.IsRedundant(cs)) + ApplyHints(cs); + + if (success) { + fOCBiMap.Update(c, co); + fBatchConstraints.push_back(c); + } else if (fBatchAddConst) + fBatchAddConstFail = true; + + fEditVarsSetup = false; + + dbg(assertInvar()); + return success; +} + +bool QcLinEqSystem::ApplyHints(int cs) +{ + bool pivoted = false; + + if (cs < 0 || cs >= fTableau.GetRows() || fTableau.IsRedundant(cs)) + throw QcWarning("ApplyHints called for invalid constraint", + cs, fTableau.GetRows() - 1); + else { + for (unsigned int i = 0; i < fTableau.fPivotHints.size() && !pivoted; i++) + pivoted = fTableau.Pivot(cs,fTableau.fPivotHints[i]); + + // If PivotHints failed, this means all the pivot hints variables + // have zero coeffs. Now try all the rest of the parametric + // variables with non-zero coeffs in the solved form constraint. + if (!pivoted) + { +#ifdef qcUseSafeIterator + { + QcDenseTableauRowIterator varCoeffs(fTableau, cs); + + // Note this iterator will not return zero coeffs, so + // there is no need to exclude the hints. + while (!varCoeffs.AtEnd()) { + if (!fTableau.IsBasic(varCoeffs.getIndex())) + pivoted = fTableau.Pivot(cs, varCoeffs.getIndex()); + varCoeffs.Increment(); + } + } +#else + // Cache tableau column coefficients since it is possible that + // the iterator may be invalidated (by Pivot) during iteration. + { + vector coeffCache; + + for(QcTableauRowIterator rowIt( fTableau, cs); + !rowIt.AtEnd(); + rowIt.Increment()) + coeffCache.push_back( QcSparseCoeff( rowIt.getValue(), + rowIt.getIndex())); + + /* Note that the iterator above will not return zero + coeffs, so there is no need to exclude the hints. */ + for (vector::iterator cIt = coeffCache.begin(); + (cIt != coeffCache.end()) && !pivoted; + cIt++) + { + unsigned cix = cIt->getIndex(); + + if (!fTableau.IsBasic( cix)) + pivoted = fTableau.Pivot( cs, cix); + } + } +#endif + } + qcAssert(pivoted); + } + + return true; +} + +void QcLinEqSystem::BeginEdit() +{ + qcAssert(fTableau.IsSolved()); + + // build a version of fEditVars by index. + vector::iterator voiIt; + vector::iterator viIt; + fVarsByIndex.resize(0); + + for (voiIt = fEditVars.begin(); voiIt != fEditVars.end(); ++voiIt) + if (IsRegistered( *voiIt)) + fVarsByIndex.push_back( fVBiMap.Index( *voiIt)); + + // try to make all variables of interest into parameters. + for (viIt = fVarsByIndex.begin(); + viIt != fVarsByIndex.end(); + ++viIt) + { + int const vi = *viIt; + if (fTableau.IsBasic( vi)) { + int const ci = fTableau.IsBasicIn(vi); + +#ifdef qcUseSafeIterator + + for (QcDenseTableauRowIterator varCoeffs( fTableau, ci); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + unsigned const coeff_ix = varCoeffs.getIndex(); + + bool reject = false; + for (vector::const_iterator viIt2 = fVarsByIndex.begin(); + !reject && (viIt2 != fVarsByIndex.end()); + viIt2++) + if (coeff_ix == *viIt2) + reject = true; + + if (!reject) + { + qcAssert( fTableau.IsBasic( vi)); + qcAssert( fTableau.GetBasicVar( ci) == vi); + qcAssert( !fTableau.IsBasic( coeff_ix)); + qcAssert( fVBiMap.Identifier( coeff_ix) + != *voiIt); // TODO: looks wrong; perhaps meant `coeff_ix != *viIt'? + dbg(bool pivoted =) + fTableau.Pivot( ci, coeff_ix); + assert( pivoted); + break; + } + } +#else + // Cache tableau column coefficients since it is possible that + // the iterator may be invalidated during iteration. + { + vector coeffCache; + + for (QcTableauRowIterator varCoeffs( fTableau, ci); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + coeffCache.push_back( QcSparseCoeff( varCoeffs.getValue(), + varCoeffs.getIndex())); + + for (vector::iterator cIt = coeffCache.begin(); + cIt != coeffCache.end(); + cIt++) + { + QcSparseCoeff &coeff = (*cIt); + unsigned const coeff_ix = coeff.getIndex(); + + bool reject = false; + for (vector::const_iterator viIt2 = fVarsByIndex.begin(); + !reject && (viIt2 != fVarsByIndex.end()); + viIt2++) + if (coeff_ix == *viIt2) + reject = true; + + if (!reject) + { + qcAssert( fTableau.IsBasic( vi)); + qcAssert( fTableau.GetBasicVar( ci) == vi); + qcAssert( !fTableau.IsBasic( coeff_ix)); + qcAssert( fVBiMap.Identifier( coeff_ix) != *voiIt); // TODO: looks wrong; perhaps meant `coeff_ix != *viIt'? + + dbg(bool pivoted =) + fTableau.Pivot(ci, coeff_ix); + assert( pivoted); + break; + } + } + } +#endif + qcAssert( !fTableau.IsBasic( vi)); + } + } + + Solve(); // Compute new solution here. + fParsOfInterest.resize(0); // setup fParsOfInterest + + for (viIt = fVarsByIndex.begin(); viIt != fVarsByIndex.end(); ++viIt) + if (!fTableau.IsBasic(*viIt) && !IsParOfInterest(*viIt)) + fParsOfInterest.push_back(*viIt); + + fDepVars.resize(0); // setup fDepVars + + // setup fDepVarCoeffs + // extend fDepVarCoeffs so 0..fTableau.GetColumns()-1 are legal indices. + fDepVarCoeffs.resize(fTableau.GetColumns()); + fDepVarBaseVals.resize(fTableau.GetColumns()); + + for (unsigned int i = 0; i < fDepVarCoeffs.size(); i++) + fDepVarCoeffs[i].resize(0); + + QcBasicVarIndexIterator bvIt(fTableau); + while (!bvIt.AtEnd()) + { + unsigned bvi = bvIt.getIndex(); + assert (fTableau.IsBasic (bvi)); + unsigned ci = bvIt.getConstraintBasicIn(); + fDepVarBaseVals[bvi] = fTableau.GetRHS (ci);; + QcTableauRowIterator varCoeffs (fTableau, ci); + while (!varCoeffs.AtEnd()) + { + if (IsParOfInterest (varCoeffs.getIndex())) + { + /* TODO: Check this logic here. The previous formatting + gave the impression that the author intended something + else. */ + if (!IsDepVar (bvi)) + fDepVars.push_back (bvi); + fDepVarCoeffs[bvi].push_back (QcSparseCoeff (varCoeffs.getValue(), + varCoeffs.getIndex())); + } + else if (bvi != varCoeffs.getIndex()) + { + numT val = fVBiMap.getIdentifierPtr( varCoeffs.getIndex())->Value(); + fDepVarBaseVals[bvi] -= val * varCoeffs.getValue(); + } + varCoeffs.Increment(); + } + + bvIt.Increment(); + } + + fEditVarsSetup = true; +} + + +void QcLinEqSystem::EndEdit() +{ + for (vector::const_iterator vIt = fDepVars.begin(); vIt != fDepVars.end(); ++vIt) + fVBiMap.getIdentifierPtr( *vIt)->RestDesVal(); + + for (vector::const_iterator vIt = fParsOfInterest.begin(); vIt != fParsOfInterest.end(); ++vIt) + fVBiMap.getIdentifierPtr( *vIt)->RestDesVal(); + + QcSolver::EndEdit(); +} + +bool QcLinEqSystem::IsDepVar(int vi) const +{ + if (vi < 0) /* TODO: We can probably assertPre (vi > 0). Similarly for other IsDepPar implementations. */ + return false; + + vector::const_iterator loc = fDepVars.begin(); + while (loc != fDepVars.end()) { + if (*loc == (unsigned) vi) + return true; + ++loc; + } + + return false; +} + +bool QcLinEqSystem::IsParOfInterest(int vi) const +{ + if (vi < 0) /* TODO: We can probably assertPre (vi > 0). Similarly for other IsParOfInterest implementations. */ + return false; + + vector::const_iterator loc = fParsOfInterest.begin(); + while (loc != fParsOfInterest.end()) { + if (*loc == (unsigned) vi) + return true; + ++loc; + } + + return false; +} + + +void QcLinEqSystem::LoadDesValCache() +{ + for (QcVariableIndexIterator vIt( fTableau); + !vIt.AtEnd(); + vIt.Increment()) + { + unsigned const vi = vIt.getIndex(); + fTableau.SetDesireValue( vi, fVBiMap.getIdentifierPtr( vi)->DesireValue()); + } +} + + +bool QcLinEqSystem::Reset() +{ + bool result = true; + + /* Record the columns of the previous basic variables so to make them + basic after this Reset() method. */ + bool *basic = new bool[fTableau.getNColumns()]; + + for (unsigned c = 0; c < fTableau.getNColumns(); c++) + basic[c] = fTableau.IsBasic(c); + + fEditVarsSetup = false; + fTableau.Restore(); // Reset variable state information + + // Establish solved form and quasi-inverse from original constraints. + for (unsigned c = 0; c < fTableau.getNColumns(); c++) + { + if (!basic[c]) + continue; + + int maxrow = -1; + { + numT max = QcUtility::qcMaxZeroVal; + QcTableauColIterator iC (fTableau, c); + + while (!iC.AtEnd()) + { + numT absVal = fabs (iC.getValue()); + if (max < absVal) + { + max = absVal; + maxrow = iC.getIndex(); + } + + iC.Increment(); + } + assert( (maxrow < 0) == (QcUtility::IsZero( max))); + } + + // If there is at least one non-zero coefficient in the current + // column. + if (maxrow != -1) + fTableau.Pivot (maxrow, c); + + } + + delete [] basic; // no longer need. + + // Make sure that all solved form constraints are assigned a basic variable. + for (unsigned r = 0; r < fTableau.getNRows(); r++) + { + if (fTableau.GetRowCondition (r) != QcLinEqRowState::fNormalised) + continue; + + int maxcol = -1; + { + numT max = QcUtility::qcMaxZeroVal; + QcTableauRowIterator iR (fTableau, r); + + while (!iR.AtEnd()) + { + numT absVal = fabs (iR.getValue()); + if (max < absVal) + { + max = absVal; + maxcol = iR.getIndex(); + assert (maxcol >= 0); + } + + iR.Increment(); + } + } + + // If there is at least one non-zero coefficient in the current + // column. + if (maxcol != -1) + fTableau.Pivot (r, maxcol); + else + { + // Verify that the Reset operation is successful. It fails + // if one of more of the solved form row is marked as + // "invalid". + if (QcUtility::IsZero (fTableau.GetRHS (r))) + fTableau.SetRowCondition (r, QcLinEqRowState::fRedundant); + else + { + fTableau.SetRowCondition (r, QcLinEqRowState::fInvalid); + result = false; + } + } + } + + dbg(assertInvar()); + return result; +} + +void QcLinEqSystem::Resolve() +{ + if (!fEditVarsSetup) + BeginEdit(); + + // adjust the dependent basic variables + vector::const_iterator vIt; + vector::iterator pIt; + + for (vIt = fDepVars.begin(); vIt != fDepVars.end(); ++vIt) + { + QcFloatRep *dvr = fVBiMap.getIdentifierPtr( *vIt); + qcAssert(fTableau.IsBasic(*vIt)); + vector &Coeffs = fDepVarCoeffs[*vIt]; + numT dvValue = fDepVarBaseVals[*vIt]; + + for (pIt = Coeffs.begin(); pIt != Coeffs.end(); ++pIt) + { + QcFloatRep const *pr = fVBiMap.getIdentifierPtr( (*pIt).getIndex()); + dvValue -= (*pIt).getValue() * pr->DesireValue(); + } + + dvr->SetValue( QcUtility::Zeroise( dvValue)); + } + + // Adjust the parameters of interest + for (vIt = fParsOfInterest.begin(); vIt != fParsOfInterest.end(); ++vIt) + fVBiMap.getIdentifierPtr( *vIt)->SetToGoal(); +} + + +void QcLinEqSystem::Restart() +{ + QcSolver::Restart(); + fTableau.Restart(); + fNotifier.Restart(); + fDepVars.resize(0); + fParsOfInterest.resize(0); + fDepVarCoeffs.resize(0); +} + + +void QcLinEqSystem::RestSolver() +{ + for (QcVariableIndexIterator vIt( fTableau); + !vIt.AtEnd(); + vIt.Increment()) + fVBiMap.getIdentifierPtr( vIt.getIndex())->RestDesVal(); +} + + +void QcLinEqSystem::Solve() +{ + LoadDesValCache(); + + for (QcVariableIndexIterator vIt( fTableau); + !vIt.AtEnd(); + vIt.Increment()) + { + unsigned const vi = vIt.getIndex(); + QcFloatRep *vr = fVBiMap.getIdentifierPtr( vi); + + if (fTableau.IsBasic( vi)) + { + numT value = fTableau.EvalBasicVar( vi); + vr->SetValue( QcUtility::Zeroise( value)); + } + else + vr->SetToGoal(); + } +} diff --git a/src/kits/interface/qoca/QcLinEqSystem.hh b/src/kits/interface/qoca/QcLinEqSystem.hh new file mode 100644 index 0000000000..383acf97ed --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqSystem.hh @@ -0,0 +1,254 @@ +// $Id: QcLinEqSystem.hh,v 1.10 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcLinEqSystemH +#define __QcLinEqSystemH + +#include +#include "qoca/QcSolver.hh" +#include "qoca/QcLinEqTableau.hh" +#include "qoca/QcConstraint.hh" +#include "qoca/QcBiMapNotifier.hh" +#include "qoca/QcSparseCoeff.hh" +#include + +class QcLinEqSystem : public QcSolver +{ +public: + typedef QcVariableBiMap::const_identifier_iterator const_var_iterator; + +protected: + vector fDepVars; + vector fParsOfInterest; + vector fVarsByIndex; // Indices of variables of interest. + vector fDepVarBaseVals; // Used for Resolve + vector > fDepVarCoeffs; + // fDepVarCoeffs is a partial map from dependant variable index + // to a vector (used as a list) of sparse coefficients. + + QcVariableBiMap &fVBiMap; + QcBiMapNotifier fNotifier; + QcConstraintBiMap &fOCBiMap; + QcLinEqTableau &fTableau; + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// +public: + QcLinEqSystem(); + QcLinEqSystem(unsigned hintRows, unsigned hintCols); + QcLinEqSystem(QcLinEqTableau &tab); + virtual ~QcLinEqSystem(); + +#if qcCheckInternalInvar + void assertInvar() const { } + void assertDeepInvar() const; + virtual void vAssertDeepInvar() const; +#endif + + //-----------------------------------------------------------------------// + // Data Structure query functions // + //-----------------------------------------------------------------------// + QcBiMapNotifier GetNotifier() + { return fNotifier; } + + QcConstraintBiMap &GetOCBiMap() + { return fOCBiMap; } + + QcVariableBiMap &GetVBiMap() + { return fVBiMap; } + + QcLinEqTableau &GetTableau() + { return fTableau; } + + //-----------------------------------------------------------------------// + // Variable management methods (see QcSolver.java for descriptions) // + //-----------------------------------------------------------------------// + virtual void AddVar(QcFloat &v); + // N.B. AddVar does nothing if the variable is already registered. + virtual void SuggestValue(QcFloat &v, numT desval); + // Sets the desired value of v to desval. + virtual void RestSolver(); + + //-----------------------------------------------------------------------// + // Enquiry functions for variables // + //-----------------------------------------------------------------------// + virtual bool IsRegistered(QcFloat const &v) const + { return (fVBiMap.IdentifierPresent(v)); } + + virtual bool IsBasic(QcFloat const &v) const + { return fTableau.IsBasic(fVBiMap.Index(v)); } + + //-----------------------------------------------------------------------// + // High Level Edit Variable Interface for use by solver clients. // + // The methods addEditVar and endEdit are more efficient than the ones // + // inherited from Solver since variable weights have no effect on // + // QcLinEqSystem::Resolve. // + //-----------------------------------------------------------------------// + virtual void BeginEdit(); + // Implementation note. + // It does not appear to be necessary to call solve before + // BeginEdit, so don't depend on this in the first loop. + virtual void EndEdit(); + // Specialised version of EndEdit since LinEqSystem does not adjust + // weights. + + //-----------------------------------------------------------------------// + // Constraint management methods // + //-----------------------------------------------------------------------// + virtual bool AddConstraint(QcConstraint &c); + // Extracts the various components and calls Insert, as well as + // updating the bimapnotifier for the tableau if successful. The + // return value indicates success or failure. If AddConstraint fails + // the state of the tableau is unchanged. + virtual bool AddConstraint(QcConstraint &c, QcFloat &hint); + virtual bool ChangeConstraint(QcConstraint &c, numT rhs); + virtual bool Reset(); + // While this routine is in progress the tableau is slowly rebuilt + // from row 0 forwards retaining the original constraint matrix fA. + // The implementation used here only relies on the rest of the tableau + // methods being able to cope with multiple undetermined constraints. + // Reset starts by calling Restore to establish a state equivalent + // to the original constraints having been all entered using AddEq + // and nothing else apart from the deleted entries being left alone. + + //-----------------------------------------------------------------------// + // Constraint Solving methods // + //-----------------------------------------------------------------------// + virtual void Solve(); + // Using the tableau's desired values cache, calculate the value + // for each variable depending upon whether it is basic or parametric. + virtual void Resolve(); + +protected: + //-----------------------------------------------------------------------// + // Read access to the Tableau and BimapNotifier are a low level aspect of// + // the public interface. // + //-----------------------------------------------------------------------// + virtual bool ApplyHints(int cs); + // ApplyHints calls Pivot according to the PivotHints and should + // only be called after a successful Eliminate call (i.e. the + // new constraint is consistent and independent). If all the + // PivotHints fail then ApplyHints trys pivoting at all the + // parametric variables with non-zero coeffs for cs. + virtual void LoadDesValCache(); // Used for Solve + + virtual void NewVariable(QcFloat &v) + { fVBiMap.Update(v, fTableau.NewVariable()); } + + bool IsDepVar(int vi) const; + // Used by EditVars and Resolve optimised linkage. + bool IsParOfInterest(int vi) const; + +public: + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; + virtual void Restart(); + // Erase everything ready to start afresh. + + QcFloat &GetVariable(const char *n) const + { return fVBiMap.Identifier(n); } + + void GetVariableSet(vector &vars) const + { fVBiMap.GetVariableSet(vars); } + + const_var_iterator getVariables_begin() const + { return fVBiMap.getIdentifiers_begin(); } + + const_var_iterator getVariables_end() const + { return fVBiMap.getIdentifiers_end(); } + + QcConstraint &GetConstraint(const char *n) const + { return fOCBiMap.Identifier(n); } + +private: + bool doAddConstraint(QcConstraint &c, int hintIx); +}; + +inline QcLinEqSystem::QcLinEqSystem() + : QcSolver(), + fVBiMap( fNotifier.GetVMap()), + fOCBiMap( fNotifier.GetOCMap()), + fTableau( *new QcLinEqTableau( 0, 0, fNotifier)) +{ +} + +inline QcLinEqSystem::QcLinEqSystem(unsigned hintRows, unsigned hintCols) + : QcSolver(), fVBiMap(fNotifier.GetVMap()), + fOCBiMap(fNotifier.GetOCMap()), + fTableau(*new QcLinEqTableau(hintRows, hintCols, fNotifier)) +{ +} + +inline QcLinEqSystem::QcLinEqSystem(QcLinEqTableau &tab) + : QcSolver(), fVBiMap(fNotifier.GetVMap()), + fOCBiMap(fNotifier.GetOCMap()), + fTableau(tab) +{ +} + +inline QcLinEqSystem::~QcLinEqSystem() +{ + delete &fTableau; +} + +inline void QcLinEqSystem::AddVar(QcFloat &v) +{ + if (!fVBiMap.IdentifierPresent(v)) { + NewVariable(v); + dbg(assertInvar()); + } +} + +inline bool QcLinEqSystem::ChangeConstraint(QcConstraint &c, numT rhs) +{ + int ix = fOCBiMap.safeIndex(c); + if (ix < 0) + return false; // TODO: perhaps use qcAssertExternalPre. + fTableau.ChangeRHS(ix, rhs); + // TODO: if (!fBatchAddConst) { maybe return false; } + return true; +} + +inline void QcLinEqSystem::Print(ostream &os) const +{ + QcSolver::Print(os); + fNotifier.Print(os); + os << endl; + fTableau.Print(os); +} + +inline void QcLinEqSystem::SuggestValue(QcFloat &v, numT desval) +{ + if (!fVBiMap.IdentifierPresent(v)) + throw QcWarning("SuggestValue: variable must be registered"); + else + v.SuggestValue(desval); +} + +#endif diff --git a/src/kits/interface/qoca/QcLinEqTableau.cc b/src/kits/interface/qoca/QcLinEqTableau.cc new file mode 100644 index 0000000000..c9c96e7ecb --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqTableau.cc @@ -0,0 +1,489 @@ +// $Id: QcLinEqTableau.cc,v 1.12 2001/01/31 07:37:13 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include "qoca/QcDefines.hh" +#include "qoca/QcLinEqTableau.hh" +#include "qoca/QcTableauRowIterator.hh" +#include "qoca/QcTableauColIterator.hh" +#include "qoca/QcConstraintIndexIterator.hh" +#include "qoca/QcBasicVarIndexIterator.hh" +#include "qoca/QcDenseTableauRowIterator.hh" +#include "qoca/QcDenseTableauColIterator.hh" + +#ifndef NDEBUG +void +QcLinEqTableau::assertDeepInvar() const +{ + assertInvar(); + QcTableau::assertDeepInvar(); + fCoreTableau->vAssertDeepInvar(); +} + +void +QcLinEqTableau::vAssertDeepInvar() const +{ + assertDeepInvar(); +} +#endif + + +int +QcLinEqTableau::Eliminate(unsigned ci) +{ + qcAssertPre( ci < getNRows()); + qcAssertPre( !fCoreTableau->GetARowDeleted( ci)); + + int quasiRow = fCoreTableau->GetMRowIndex(ci); + // The corresponding row of fM + + qcAssert(quasiRow >= 0 && quasiRow < GetRows() && + !fCoreTableau->GetMRowDeleted(quasiRow)); + + #ifdef qcSafetyChecks + if (GetRowCondition(quasiRow) != QcLinEqRowState::fInvalid) + throw QcWarning(qcPlace, "Eliminate called for a valid constraint"); + qcAssert(GetBasicVar(quasiRow) == QcTableau::fInvalidVariableIndex); + #endif + + // Erase the list of pivot variable index hints. + fPivotHints.resize(0); + + // Eliminate the basic variables from quasiRow. +#ifdef qcUseSafeIterator + QcDenseTableauRowIterator rowIt( *this, quasiRow); + + numT maxCoeff( 0); + for(; !rowIt.AtEnd(); rowIt.Increment()) + { + unsigned col = rowIt.getIndex(); + + if(IsBasic( col)) + fCoreTableau->AddScaledRow( quasiRow, IsBasicIn( col), + -rowIt.getValue()); + else + { + // Arrange to put the biggest hint coeff first. + numT absVal = fabs( rowIt.getValue()); + if(absVal > maxCoeff) + { + maxCoeff = absVal; + fPivotHints.push_front( col); + } + else + fPivotHints.push_back( col); + } + } +#else + // N.B. Eliminate cannot use QcLeqTabRowIterator as the tableau + // quasi matrix fM is altered (and this is essential to Eliminate). + QcTableauRowIterator rowIt(*this, quasiRow); + { + vector coeffCache; + + while (!rowIt.AtEnd()) + { + coeffCache.push_back( QcSparseCoeff( rowIt.getValue(), + rowIt.getIndex())); + rowIt.Increment(); + } + + numT maxCoeff( 0); + for(vector::iterator cIt = coeffCache.begin(); + cIt != coeffCache.end(); + cIt++) + { + QcSparseCoeff &coeff = (*cIt); + unsigned col = coeff.getIndex(); + + if(IsBasic( col)) + { + fCoreTableau->AddScaledRow( quasiRow, IsBasicIn( col), + -coeff.getValue()); + } + else + { + /* Arrange to put the biggest (in magnitude) hint coeff first. + A full sort shouldn't be necessary, as usually only the + first element is consulted. */ + numT absVal = fabs( coeff.getValue()); + if(absVal > maxCoeff) + { + maxCoeff = absVal; + fPivotHints.push_front( col); + } + else + fPivotHints.push_back( col); + } + } + } +#endif + + // Check for linear independance + rowIt.SetToBeginOf(quasiRow); + + if (rowIt.AtEnd()) { // all coeffs are zero + if (QcUtility::IsZero(fCoreTableau->GetRHS(quasiRow))) { + SetRowCondition(quasiRow, QcLinEqRowState::fRedundant); + SetMRowIndex(ci, QcTableau::fInvalidConstraintIndex); + SetARowIndex(quasiRow, QcTableau::fInvalidConstraintIndex); + } else { + #ifdef qcSafetyChecks + throw QcWarning(qcPlace, "Inconsistant Constraint"); + #endif + qcAssert(GetRowCondition(quasiRow) == QcLinEqRowState::fInvalid); + DeleteRow(ci); + return QcTableau::fInvalidConstraintIndex; + } + } else + SetRowCondition(quasiRow, QcLinEqRowState::fNormalised); + + return quasiRow; // Note alternative return qcInvalidCIndex above. +} + +numT QcLinEqTableau::EvalBasicVar(unsigned vi) const +{ + qcAssertPre( IsBasic( vi)); + int ci = IsBasicIn( vi); + assert( ci != QcTableau::fInvalidConstraintIndex); + + numT value = GetRHS( ci); + + for (QcTableauRowIterator varCoeffs( *this, ci); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + unsigned coeff_vi = varCoeffs.getIndex(); + if (coeff_vi != vi) + value -= varCoeffs.getValue() * GetDesireValue( coeff_vi); + } + + return value; +} + +#if 0 /* unused */ +//numT QcLinEqTableau::GetSparsenessExBasic() const +//{ +// unsigned nZeros = 0; +// unsigned total = 0; +// +// for (unsigned i = 0; i < getNRows(); i++) +// if (GetRowCondition( i) == QcLinEqRowState::fRegular) +// for (unsigned j = 0; j < getNColumns(); j++) +// if (!IsBasic( j)) +// { +// total++; +// if (QcUtility::IsZero(GetValue( i, j))) +// nZeros++; +// } +// +// if (total == 0) +// return 0; +//#if NUMT_IS_DOUBLE +// return (total - nZeros) / (numT) total; +//#else +// return numT( total - nZeros, total); +//#endif +//} +// +//numT QcLinEqTableau::GetSparsenessInBasic() const +//{ +// unsigned nZeros = 0; +// unsigned total = 0; +// +// for (unsigned i = 0; i < getNRows(); i++) +// if (GetRowCondition( i) == QcLinEqRowState::fRegular) +// for (unsigned j = 0; j < getNColumns(); j++) +// { +// total++; +// if (QcUtility::IsZero( GetValue( i, j))) +// nZeros++; +// } +// +// if (total == 0) +// return 0; +//#if NUMT_IS_DOUBLE +// return (total - nZeros) / (numT) total; +//#else +// return numT( total - nZeros, total); +//#endif +//} +#endif /* unused */ + +numT QcLinEqTableau::GetValue(unsigned ci, unsigned vi) const +{ + qcAssertPre (ci < getNRows()); + qcAssertPre (vi < getNColumns()); + + // Short cut evaluations + switch (GetRowCondition(ci)) { + case QcLinEqRowState::fRedundant: + return 0.0; + case QcLinEqRowState::fNormalised: + if (IsBasic(vi)) + return 0.0; + break; + case QcLinEqRowState::fRegular: + if (IsBasic(vi)) { + if ((int) vi == GetBasicVar(ci)) + return numT( 1); + else + return numT( 0); + } + break; + case QcLinEqRowState::fInvalid: break; + default: + throw QcWarning(qcPlace, "Invalid LinEqRowCondition"); + } + + return fCoreTableau->GetValue(ci, vi); +} + +bool QcLinEqTableau::IsSolved() const +{ + for (QcConstraintIndexIterator cIt( *this); + !cIt.AtEnd(); + cIt.Increment()) + if (IsUndetermined( cIt.getIndex())) + return false; + + return true; +} + +bool QcLinEqTableau::Pivot(unsigned ci, unsigned vi) +{ + qcAssertPre( ci < getNRows()); + qcAssertPre( !IsRedundant( ci)); + qcAssertPre( GetRowCondition(ci) != QcLinEqRowState::fInvalid); + + numT p = GetValue(ci, vi); // GetValue returns the raw coefficient + + if (QcUtility::IsZero(p)) // so this test is required. + return false; + + #ifdef qcSafetyChecks + if (IsBasic( vi) + && !((GetRowCondition( ci) == QcLinEqRowState::fRegular) + && (GetBasicVar( ci) == (int) vi))) + { + throw QcWarning(qcPlace, + "Pivot attempted for variable already basic in another constraint"); + return false; + } + #endif + + // If ci is regular then remove it from the basis. + if (GetRowCondition(ci) == QcLinEqRowState::fRegular) + Unsolve(ci); + // Note that fARowIndex[ci] can be left as qcInvalidCIndex, + // hence check below. + + // From this point, until the pivot is completed, + // the conditions MRowIndex(fARowIndex(ci))==ci and + // ARowIndex(MRowIndex(ci2))==ci2 may not hold. Since it is + // Pivot that causes a row to become regular, and these conditions + // do not hold for regular rows, this is a consequence of the + // change of state. We could introduce another row state for this + // phase, but that seems a bit over the top. Just check that all + // tableau methods that Pivot calls from here on do not assume the + // conditions. I.E. don't call: DecreaseRows, Eliminate, RemoveEq, + // Restore, or AddRow. And of course if IsSolved is + // called with checks enabled it may report an assert violation. + + // From this point the pivot must succeed. + // So can now wipe fARowIndex and fMRowIndex + if (GetARowIndex(ci) != QcTableau::fInvalidConstraintIndex) { + SetMRowIndex(GetARowIndex(ci), QcTableau::fInvalidConstraintIndex); + SetARowIndex(ci, QcTableau::fInvalidConstraintIndex); + } + + #ifdef qcSafetyChecks + qcAssert(GetARowIndex(ci) == QcTableau::fInvalidConstraintIndex); + qcAssert(GetRowCondition(ci) == QcLinEqRowState::fNormalised); + qcAssert(GetBasicVar(ci) == QcTableau::fInvalidVariableIndex); + qcAssert(IsBasicIn(vi) == QcTableau::fInvalidConstraintIndex); + #endif + + // Scale the pivot row so pivot coeff is 1.0 + fCoreTableau->ScaleRow(ci, recip( p)); + // FractionRow may be used here rather than ScaleRow(ci,recip(p)) + // so that we don't introduce rounding errors at the cost of + // efficiency (FractionRow uses division so is less efficient). + +#ifdef qcUseSafeIterator + // Eliminate the new basic variable from all the other rows. + QcDenseTableauColIterator varCoeffs(*this, vi); + + while (!varCoeffs.AtEnd()) + { + // Only process regular rows. Redundant and deleted rows would + // not be affected in any case. Undetermined rows are not + // in solved form so should not be included. By checking here + // we can allow rows to be added without requiring an + // immediate pivot and also enable a full resolve by + // setting all the rows to normalised and fM to identity. + if ((GetRowCondition( varCoeffs.getIndex()) == QcLinEqRowState::fRegular) + || ((GetRowCondition( varCoeffs.getIndex()) == QcLinEqRowState::fNormalised) + && (varCoeffs.getIndex() != ci))) + { + // Excludes (varCoeffs.Index() == ci) + // since (GetRowCondition(ci) != regular). + fCoreTableau->AddScaledRow( varCoeffs.getIndex(), ci, -varCoeffs.getValue()); + } + varCoeffs.Increment(); + } +#else + // Eliminate the new basic variable from all the other rows. + { + vector coeffCache; + + for(QcTableauColIterator varCoeffs( *this, vi); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + unsigned row = varCoeffs.getIndex(); + + /* Process only regular rows. Redundant and deleted rows would + not be affected in any case. Undetermined rows are not in + solved form so should not be included. By checking here we can + allow rows to be added without requiring an immediate pivot and + also enable a full resolve by setting all the rows to + normalised and fM to identity. */ + // Excludes (varCoeffs.Index() == ci) + // since (GetRowCondition(ci) != regular). + if ((GetRowCondition( row) == QcLinEqRowState::fRegular) + || ((GetRowCondition( row) == QcLinEqRowState::fNormalised) + && (row != ci))) + coeffCache.push_back( QcSparseCoeff( varCoeffs.getValue(), row)); + } + + for(vector::iterator cIt = coeffCache.begin(); + cIt != coeffCache.end(); + cIt++) + fCoreTableau->AddScaledRow( cIt->getIndex(), ci, -cIt->getValue()); + } +#endif + + SetBasic(vi, true); + SetBasicIn(vi, ci); + SetBasicVar(ci, vi); + SetRowCondition(ci, QcLinEqRowState::fRegular); + + return true; +} + +void QcLinEqTableau::Print(ostream &os) const +{ + unsigned rows = getNRows(); + unsigned cols = getNColumns(); + + fCoreTableau->Print(os); + os << endl; + os << (IsSolved() ? "Solved " : "Unsolved ") << endl; + + os << "Tableau with " << rows << " rows and " << cols << " columns." << endl; + os << "==================================================" << endl; + os << "Basic vars are: " << endl; + + QcBasicVarIndexIterator it(*this); + while (!it.AtEnd()) { + os << it.getIndex() << ", "; + it.Increment(); + } + + os << endl << "Solved Form:" << endl; + + for (unsigned i = 0; i < rows; i++) { + os << i << ":"; + + switch (GetRowCondition(i)) { + case QcLinEqRowState::fInvalid: + if (fCoreTableau->GetMRowDeleted(i)) + os << "deleted\t"; + else + os << "invalid\t"; + break; + case QcLinEqRowState::fNormalised: + os << "normalised\t"; + break; + case QcLinEqRowState::fRegular: + os << "regular\t"; + break; + case QcLinEqRowState::fRedundant: + os << "redundant\t"; + break; + default: + throw QcWarning("RowCondition is invalid"); + } + + os << "Basic(" << GetBasicVar(i) << ")\t"; + + for (unsigned j = 0; j < cols; j++) + os << GetValue(i, j) << "\t"; + + os << endl; + } + + os << endl; + + for (unsigned i = 0; i < rows; i++) + os << "[" << i << "] " << GetRHS(i) << endl; +} + +void QcLinEqTableau::Restore() +{ + // Reset state information. + for (int c = 0; c < GetColumns(); c++) { + SetBasic(c, false); + SetBasicIn(c, QcTableau::fInvalidConstraintIndex); + } + + for (int r = 0; r < GetRows(); r++) { + // Row condition is set to normalised so that a full pivot can be + // performed on Reset(). + SetBasicVar(r, QcTableau::fInvalidVariableIndex); + SetRowCondition(r, GetMRowDeleted(r) ? + QcLinEqRowState::fInvalid : QcLinEqRowState::fNormalised); + } + + fCoreTableau->Restore(); // Do this last as it calls Row/Col FixLinkage + + dbg(assertInvar()); +} + +void QcLinEqTableau::Unsolve(unsigned ci) + // Remove constraint from the basis given solved form constraint index +{ + qcAssertPre( ci < getNRows()); + + qcAssert(GetRowCondition(ci) == QcLinEqRowState::fRegular); + int b = GetBasicVar(ci); + qcAssert(b != QcTableau::fInvalidVariableIndex); + SetBasic(b, false); + SetBasicIn(b, QcTableau::fInvalidConstraintIndex); + SetBasicVar(ci, QcTableau::fInvalidVariableIndex); + SetRowCondition(ci, QcLinEqRowState::fNormalised); +} diff --git a/src/kits/interface/qoca/QcLinEqTableau.hh b/src/kits/interface/qoca/QcLinEqTableau.hh new file mode 100644 index 0000000000..bfc3e42680 --- /dev/null +++ b/src/kits/interface/qoca/QcLinEqTableau.hh @@ -0,0 +1,356 @@ +// $Id: QcLinEqTableau.hh,v 1.18 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcLinEqTableauH +#define __QcLinEqTableauH + +#include +#include +#include "qoca/QcTableau.hh" +#include "qoca/QcSparseCoeff.hh" +#include "qoca/QcDelCoreTableau.hh" +#include "qoca/QcLinEqRowColStateVector.hh" + +class QcLinEqTableau : public QcTableau +{ +protected: + QcLinEqRowColStateVector *fRowColState; + QcLinEqRowStateVector *fRowState; + QcLinEqColStateVector *fColState; + QcCoreTableau *fCoreTableau; + +public: + deque fPivotHints; + // During an eliminate operation, fPivotHints is erased and then + // the indices of parametric variables that do not have zero + // solved form coeffs are recorded. These are likely to be good + // candidates for the pivot operation. Note that it is still + // necessary to check that the coeff is non-zero, since + // parametric coeffs may be modified by eliminate after the coeff + // is recorded, this check is intended to be done using pivot. + + //-----------------------------------------------------------------------// + // Constructors. // + //-----------------------------------------------------------------------// + QcLinEqTableau(unsigned hintRows, unsigned hintCols, QcBiMapNotifier &n); + QcLinEqTableau(QcCoreTableau &tab, QcBiMapNotifier &n); + virtual ~QcLinEqTableau(); + +#ifndef NDEBUG + void assertInvar() const { } + void assertDeepInvar() const; + virtual void vAssertDeepInvar() const; +#endif + + //-----------------------------------------------------------------------// + // Data Structure access functions. // + //-----------------------------------------------------------------------// + QcCoreTableau &GetCoreTableau() const + { return *fCoreTableau; } + + QcLinEqRowColStateVector &GetRowColState() const + { return *fRowColState; } + + QcLinEqRowStateVector &GetRowState() const + { return *fRowState; } + + QcLinEqColStateVector &GetColState() const + { return *fColState; } + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + + /** Get RHS for solved-form constraint ci. + +

ci is allowed to be a deleted constraint, in which case zero + is returned. + **/ + virtual numT GetRHS(unsigned ci) const + { return fCoreTableau->GetRHS(ci); } + + + /** Get coefficient for variable vi in solved-form constraint ci. + +

ci is allowed to be a deleted constraint, in which case zero + is returned. + + @precondition ci < getNRows() + @precondition vi < getNColumns() + **/ + virtual numT GetValue(unsigned ci, unsigned vi) const; + + + /** Find the value of the basic variable with index vi, using + the desired value cache and tableau coeffs. + + @precondition IsBasic(vi) + **/ + virtual numT EvalBasicVar(unsigned vi) const; + + int GetColumns() const + { return fCoreTableau->GetColumns(); } + + unsigned getNColumns() const + { return fCoreTableau->GetColumns(); } + + bool GetARowDeleted(unsigned ci) const + { return fCoreTableau->GetARowDeleted(ci); } + + int GetARowIndex(unsigned ci) const + { return fCoreTableau->GetARowIndex(ci); } + + bool GetMRowDeleted(unsigned ci) const + { return fCoreTableau->GetMRowDeleted(ci); } + + int GetMRowIndex(unsigned ci) const + { return fCoreTableau->GetMRowIndex(ci); } + + int GetBasicVar(unsigned ci) const + { return fRowState->GetBasicVar(ci); } + + numT GetDesireValue(unsigned vi) const + { return fColState->GetDesireValue(vi); } + + int GetRowCondition(unsigned ci) const + { return fRowState->GetCondition(ci); } + + int GetRows() const + { return fCoreTableau->GetRows(); } + + unsigned getNRows() const + { return fCoreTableau->GetRows(); } + +#if 0 /* unused */ + numT GetSparsenessInBasic() const; + numT GetSparsenessExBasic() const; +#endif + + int IsBasicIn(unsigned vi) const + { return fColState->IsBasicIn(vi); } + + bool IsBasic(unsigned vi) const + { return fColState->IsBasic(vi); } + + bool IsRedundant(unsigned ci) const + { return (GetRowCondition(ci) == QcLinEqRowState::fRedundant); } + + /** Indicates whether the tableau is in solved form. + Returns true iff every constraint is determined (i.e. !IsUndetermined). + **/ + bool IsSolved() const; + + bool IsUndetermined(unsigned ci) const; + + bool IsValidCIndex(int ci) const + { return fCoreTableau->IsValidCIndex(ci); } + + bool IsValidOCIndex(int ci) const + { return fCoreTableau->IsValidOCIndex(ci); } + + bool IsValidVIndex(int vi) + { return fCoreTableau->IsValidVIndex(vi); } + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + + /** Create a new invalid constraint, and add any new variables + indicated. + + @return The new original constraint index. + + @postcondition ret ≥ 0 + @postcondition ret < getNRows() + **/ + virtual int AddEq(QcRowAdaptor &varCoeffs, numT rhs) + { + int ret = fCoreTableau->AddRow( varCoeffs, rhs); + qcAssertPost( (unsigned) ret < getNRows()); + return ret; + } + + virtual void ChangeRHS(unsigned ci, numT rhs) + // Change the RHS of the constraint ci. + { fCoreTableau->ChangeRHS(ci, rhs); } + + virtual void DeleteRow(int co); + // Delete an undetermined constraint given its original row index + + virtual int Eliminate(unsigned ci); // Call after addEq + // see QcTableau.hh for doc. + + /** Create a new non-basic variable. */ + virtual unsigned IncreaseColumns(); + + /** Create a new constraint. */ + virtual unsigned IncreaseRows() + { return fCoreTableau->IncreaseRows(); } + + virtual unsigned NewVariable() + // Create a new non basic variable and return its index. This + // new variable will have zero coefficient in all existing constraints. + // There is no necessity to explicitely call this function. It just + // may is convenient to determine in advance the variable index for + // a new variable rather than let AddEq to assign one. + { return IncreaseColumns(); } + + virtual bool Pivot(unsigned ci, unsigned vi); + // The parameters indicate a solved form coeff. Pivot can only be + // applied to a normalised or regular constraint. Get the pivot + // element and check it is non-zero, this catches redundant and + // deleted constaints as well (Pivot should not be called for these). + // To save checking that the pivot element is non-zero before calling + // Pivot, and Pivot has to look at this in any case, it is expected + // that Pivot be used to do this check. + + virtual void Restart() + // Erase everything ready to start afresh. This also restarts + // fRowColState. + { fCoreTableau->Restart(); } + + virtual void Restore(); + // By setting all the undeleted constraints to normalised, the tableau + // data structures can remain in a consistent state through this Reset. + // It is tempting to set fRows to -1 and bring it back up to its + // original value while solving each constraint in turn. But this is + // an invitation to disaster since other routines are entitled to + // assume fRows is an upper bound for constraint indices and the + // deleted rows information in fMRowIndex and fIsDeleted would need to + // violate this. Hence the safe implementation used here only relies + // on the rest of the tableau methods being able to cope with multiple + // normalised constraints. Restore establishes a state equivalent to + // the original constraints having been all entered using AddRow and + // nothing else apart from the deleted entries being left alone. + + + /** Normalize the corresponding row in fM if the rhs is negative. This + makes rhs positive. + + @precondition ci < getNRows() + **/ + void Normalize (unsigned ci) + { + qcAssertPre (ci < getNRows()); + fCoreTableau->Normalize (ci); + } + + void SetARowDeleted(int ci, bool d) + { fCoreTableau->SetARowDeleted(ci, d); } + + void SetARowIndex(int ci, int i) + { fCoreTableau->SetARowIndex(ci, i); } + + void SetDesireValue(int vi, numT dv) // must be setup by client + { fColState->SetDesireValue(vi, dv); } + + void SetMRowDeleted(int ci, bool d) + { fCoreTableau->SetMRowDeleted(ci, d); } + + void SetMRowIndex(int ci, int i) + { fCoreTableau->SetMRowIndex(ci, i); } + + void SetBasicVar(int ci, int i) + { fRowState->SetBasicVar(ci, i); } + + void SetRowCondition(int ci, int s) + { fRowState->SetCondition(ci, s); } + + void SetBasicIn(int vi, int i) + { fColState->SetBasicIn(vi, i); } + + void SetBasic(int vi, bool b) + { fColState->SetBasic(vi, b); } + + void Unsolve(unsigned ci); + // Given a solved form constraint index, for a regular constraint, + // Unsolve removes it from the basis so that it looks like a newly + // entered row after Eliminate but before a Pivot. However the + // bookeeping information associating this solved form constraint with + // an original constraint is not done by Unsolve. + + //-----------------------------------------------------------------------// + // Utility function. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; + +protected: + //-----------------------------------------------------------------------// + // Constructors. // + //-----------------------------------------------------------------------// + QcLinEqTableau(QcBiMapNotifier &n); +}; + +inline QcLinEqTableau::QcLinEqTableau(unsigned hintRows, unsigned hintCols, + QcBiMapNotifier &n) + : QcTableau(n), + fRowColState(new QcLinEqRowColStateVector()), + fRowState(&fRowColState->GetRowState()), + fColState(&fRowColState->GetColState()), + fCoreTableau(new QcCoreTableau(hintRows, hintCols, *fRowColState)) +{ +} + +inline QcLinEqTableau::QcLinEqTableau(QcCoreTableau &tab, QcBiMapNotifier &n) + : QcTableau(n), + fRowColState((QcLinEqRowColStateVector *)&tab.GetRowColState()), + fRowState(&fRowColState->GetRowState()), + fColState(&fRowColState->GetColState()), + fCoreTableau(&tab) +{ +} + +inline QcLinEqTableau::QcLinEqTableau(QcBiMapNotifier &n) + : QcTableau(n) +{ +} + +inline QcLinEqTableau::~QcLinEqTableau() +{ + delete fRowColState; + delete fCoreTableau; +} + +inline void QcLinEqTableau::DeleteRow(int co) +{ + SetRowCondition(fCoreTableau->GetMRowIndex(co), QcLinEqRowState::fInvalid); + fCoreTableau->DeleteRow(co); +} + +inline unsigned QcLinEqTableau::IncreaseColumns() +{ + unsigned i = fCoreTableau->IncreaseColumns(); + return i; +} + +inline bool QcLinEqTableau::IsUndetermined(unsigned ci) const +{ + int status = GetRowCondition( ci); + return ((status == QcLinEqRowState::fInvalid) + || (status == QcLinEqRowState::fNormalised)); +} + +#endif /* !__QcLinEqTableauH */ diff --git a/src/kits/interface/qoca/QcLinInEqColState.hh b/src/kits/interface/qoca/QcLinInEqColState.hh new file mode 100644 index 0000000000..69bb7651ec --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqColState.hh @@ -0,0 +1,153 @@ +// $Id: QcLinInEqColState.hh,v 1.8 2000/12/13 05:59:49 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// The class QcBiMap provides a bi-directional mapping from // +// identifier class to index class. // +//============================================================================// + +#ifndef __QcLinInEqColStateH +#define __QcLinInEqColStateH + +#include "qoca/QcQuasiColState.hh" + +class QcLinInEqColState : public QcLinEqColState +{ + friend class QcLinInEqColStateVector; + friend class QcLinInEqRowColStateVector; + +public: + enum { + fStructural = 0x01, + fSlack = 0x02, + fDual = 0x04, + fArtificial = 0x08, + fDesire = 0x10, + fError = 0x20 + }; + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcLinInEqColState(int vi); + +private: +#ifndef NDEBUG + bool isValidColCondition(int c) const + { + switch( c) + { + case fDual: + case fArtificial: + case fDesire: + case fStructural: + case (fStructural | fSlack): + case (fStructural | fSlack | fError): + return true; + } + return false; + } +#endif + + //----------------------------------------------------------------------- + // Query functions + //----------------------------------------------------------------------- +public: + int getCondition() const + { + qcAssertPost( isValidColCondition( fCondition)); + return fCondition; + } + + void setCondition(int c) + { + qcAssertPre( isValidColCondition( c)); + fCondition = c; + } + + QcLinInEqColState const *getNextStructuralCol() const + { + return fNextStruct; + } + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os); + +public: + /** A constrained variable may only take non-negative values and hence if it + is basic, its coefficient cannot be allowed to have a different sign from + the rhs value if the tableau is in solved form. A solved form tableau row + with a constrained basic variable is called restricted. + **/ + bool fIsConstrained; + +private: + int fCondition; + // Currently only slack and dual variables are constrained. +public: + numT fObj; // Objective function coeff (for Solver's use) +private: + QcLinInEqColState *fNextStruct; // Circular doubly linked list of + QcLinInEqColState *fPrevStruct; // slack variables. +}; + +inline QcLinInEqColState::QcLinInEqColState(int vi) + : QcLinEqColState(vi) +{ + fIsConstrained = false; + fCondition = fStructural; + fObj = 0.0; + fNextStruct = 0; + fPrevStruct = 0; +} + +inline void QcLinInEqColState::Print(ostream &os) +{ + QcLinEqColState::Print(os); + os << ",IsConst(" << fIsConstrained << ")," + << "Cond(" << fCondition << "),"; + + if (fCondition & fStructural) + os << "[structural]"; + + if (fCondition & fSlack) + os << "[slack]"; + + if (fCondition & fDual) + os << "[dual]"; + + if (fCondition & fArtificial) + os << "[artificial]"; + + if (fCondition & fDesire) + os << "[desire]"; + + os << "),Obj(" << fObj << ")," + << "PrevStruct(" << fPrevStruct << ")," + << "NextStruct(" << fNextStruct << ")"; +} + +#endif diff --git a/src/kits/interface/qoca/QcLinInEqColStateVector.H b/src/kits/interface/qoca/QcLinInEqColStateVector.H new file mode 100644 index 0000000000..a15d81c822 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqColStateVector.H @@ -0,0 +1,165 @@ +// Generated automatically from QcLinInEqColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcLinInEqColStateVectorDCL +#define QcLinInEqColStateVectorDCL +#line 1 "QcLinInEqColStateVector.ch" +// $Id: QcLinInEqColStateVector.ch,v 1.5 2000/12/13 01:44:58 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include + +#include + +class QcLinInEqColStateVector + : public QcLinEqColStateVector +{ +public: + + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcLinInEqColStateVector() + : QcLinEqColStateVector(), fStructVarList(0) + { + } + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + int GetCondition(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcLinInEqColState *)fStates[i])->getCondition(); + } + + numT GetObjValue(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcLinInEqColState *)fStates[i])->fObj; + } + + bool IsArtificial(unsigned vi) const + { + qcAssertPre (vi < fSize); + return GetCondition(vi) & QcLinInEqColState::fArtificial; + } + + bool IsConstrained(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcLinInEqColState *)fStates[i])->fIsConstrained; + } + + bool IsDual(unsigned vi) const + { return GetCondition(vi) & QcLinInEqColState::fDual; } + + bool IsDesire(unsigned vi) const + { return GetCondition(vi) & QcLinInEqColState::fDesire; } + + bool IsError(unsigned vi) const + { return GetCondition(vi) & QcLinInEqColState::fError; } + + bool IsSlack(unsigned vi) const + { return GetCondition(vi) & QcLinInEqColState::fSlack; } + + bool IsStructural(unsigned vi) const + { return GetCondition(vi) & QcLinInEqColState::fStructural; } + + + +//-----------------------------------------------------------------------// +// Setter functions +//-----------------------------------------------------------------------// + + +void +SetCondition(unsigned i, int c); +#line 110 "QcLinInEqColStateVector.ch" +inline void +SetObjValue(unsigned i, numT v); +#line 117 "QcLinInEqColStateVector.ch" +inline void +SetConstrained(unsigned i, bool c); +#line 125 "QcLinInEqColStateVector.ch" +#ifndef NDEBUG + +void +assertLinkageInvar() const; +#line 159 "QcLinInEqColStateVector.ch" +virtual void +virtualAssertLinkageInvar() const; +#line 165 "QcLinInEqColStateVector.ch" +#endif + + + +virtual void +FixLinkage(); +#line 191 "QcLinInEqColStateVector.ch" +private: + +inline void +LinkStruct(QcLinInEqColState *state); +#line 211 "QcLinInEqColStateVector.ch" +inline void +UnlinkStruct(QcLinInEqColState *me); +#line 229 "QcLinInEqColStateVector.ch" +inline void +UnlinkStruct(unsigned i); +#line 239 "QcLinInEqColStateVector.ch" +protected: + + +virtual void +Alloc(QcState **start, QcState **finish); +#line 257 "QcLinInEqColStateVector.ch" +virtual void +AddToList(QcState **start, QcState **finish); +#line 282 "QcLinInEqColStateVector.ch" +virtual void +RemoveFromList(QcState **start, QcState **finish); +#line 304 "QcLinInEqColStateVector.ch" +private: +inline QcLinInEqColState * +getState(unsigned i) const; +#line 316 "QcLinInEqColStateVector.ch" +public: + /** head of linked list of structural variables. */ + QcLinInEqColState *fStructVarList; + +}; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcLinInEqColStateVectorDCL */ diff --git a/src/kits/interface/qoca/QcLinInEqColStateVector.cc b/src/kits/interface/qoca/QcLinInEqColStateVector.cc new file mode 100644 index 0000000000..582f7a3a14 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqColStateVector.cc @@ -0,0 +1,203 @@ +// Generated automatically from QcLinInEqColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcLinInEqColStateVector.hh" +#line 1 "QcLinInEqColStateVector.ch" +// $Id: QcLinInEqColStateVector.ch,v 1.5 2000/12/13 01:44:58 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + + + +#include + + + + + + + +#line 89 "QcLinInEqColStateVector.ch" +//-----------------------------------------------------------------------// +// Setter functions +//-----------------------------------------------------------------------// + + +void +QcLinInEqColStateVector::SetCondition(unsigned i, int c) +{ + qcAssertPre( i < fSize); + QcLinInEqColState *state = getState( i); + if ((c ^ state->getCondition()) + & QcLinInEqColState::fStructural) + { + if (c & QcLinInEqColState::fStructural) + LinkStruct( state); + else + UnlinkStruct( state); + } + state->setCondition( c); +} + +#line 125 "QcLinInEqColStateVector.ch" +#ifndef NDEBUG + +void +QcLinInEqColStateVector::assertLinkageInvar() const +{ + unsigned nStructural = 0; + for (QcState **i = fStates + fSize; i-- != fStates;) + { + QcLinInEqColState const *state = CAST(QcLinInEqColState const *, *i); + if (state->getCondition() & QcLinInEqColState::fStructural) + nStructural++; + else + { + assert( state->fPrevStruct == 0); + assert( state->fNextStruct == 0); + } + } + + assert( (fStructVarList == 0) + || (fStructVarList->fPrevStruct == 0)); + for (QcLinInEqColState *curr = fStructVarList; + curr != 0; + curr = curr->fNextStruct) + { + assert( curr->getCondition() & QcLinInEqColState::fStructural); + assert( (curr->fNextStruct == 0) + || (curr->fNextStruct->fPrevStruct == curr)); + assert( nStructural != 0); + nStructural--; + } + assert( nStructural == 0); +} + + +void +QcLinInEqColStateVector::virtualAssertLinkageInvar() const +{ + assertLinkageInvar(); + QcLinEqColStateVector::virtualAssertLinkageInvar(); +} +#endif + + + +void +QcLinInEqColStateVector::FixLinkage() +{ + dbg(assertLinkageInvar()); + +#if 0 /* shouldn't be necessary any more. */ + fStructVarList = 0; + + for (unsigned i = 0; i < fSize; i++) + { + QcLinInEqColState *state = (QcLinInEqColState *)fStates[i]; + state->fNextStruct = 0; + state->fPrevStruct = 0; + + if (state->getCondition() & QcLinInEqColState::fStructural) + LinkStruct( state); + } +#endif + + QcLinEqColStateVector::FixLinkage(); +} + + + +#line 242 "QcLinInEqColStateVector.ch" +void +QcLinInEqColStateVector::Alloc(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fCapacity); + + for (unsigned i = start - fStates; + start != finish; + start++, i++) + *start = new QcLinInEqColState( i); +} + + + +void +QcLinInEqColStateVector::AddToList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start < finish); + qcAssertPre( finish <= getAllocEnd()); + + QcLinEqColStateVector::AddToList( start, finish); + + for(; start != finish; start++) + { + QcLinInEqColState *state = CAST(QcLinInEqColState *, *start); + + assert( (state->fNextStruct == 0) + && (state->fPrevStruct == 0) + && (state->getCondition() == QcLinInEqColState::fStructural) + && (!state->fIsConstrained) + && (state->fObj == 0.0)); + + LinkStruct( state); + } +} + + + +void +QcLinInEqColStateVector::RemoveFromList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fSize); + + for (QcState **i = start; i != finish; i++) + { + QcLinInEqColState *state = CAST(QcLinInEqColState *, *i); + + if (state->getCondition() & QcLinInEqColState::fStructural) + UnlinkStruct( i - fStates); + state->setCondition( QcLinInEqColState::fStructural); + state->fIsConstrained = false; + state->fObj = 0.0; + } + + QcLinEqColStateVector::RemoveFromList( start, finish); +} + + + +#line 323 "QcLinInEqColStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcLinInEqColStateVector.ch b/src/kits/interface/qoca/QcLinInEqColStateVector.ch new file mode 100644 index 0000000000..6594d4d625 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqColStateVector.ch @@ -0,0 +1,330 @@ +// $Id: QcLinInEqColStateVector.ch,v 1.5 2000/12/13 01:44:58 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +//o[d] #include +//o[i] #include +#include + +//o[d] class QcLinInEqColStateVector +//o[d] : public QcLinEqColStateVector +//o[d] { +//o[d] public: + +//begin o[d] + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcLinInEqColStateVector() + : QcLinEqColStateVector(), fStructVarList(0) + { + } + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + int GetCondition(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcLinInEqColState *)fStates[i])->getCondition(); + } + + numT GetObjValue(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcLinInEqColState *)fStates[i])->fObj; + } + + bool IsArtificial(unsigned vi) const + { + qcAssertPre (vi < fSize); + return GetCondition(vi) & QcLinInEqColState::fArtificial; + } + + bool IsConstrained(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcLinInEqColState *)fStates[i])->fIsConstrained; + } + + bool IsDual(unsigned vi) const + { return GetCondition(vi) & QcLinInEqColState::fDual; } + + bool IsDesire(unsigned vi) const + { return GetCondition(vi) & QcLinInEqColState::fDesire; } + + bool IsError(unsigned vi) const + { return GetCondition(vi) & QcLinInEqColState::fError; } + + bool IsSlack(unsigned vi) const + { return GetCondition(vi) & QcLinInEqColState::fSlack; } + + bool IsStructural(unsigned vi) const + { return GetCondition(vi) & QcLinInEqColState::fStructural; } + +//end o[d] + +//-----------------------------------------------------------------------// +// Setter functions +//-----------------------------------------------------------------------// + +//cf +void +SetCondition(unsigned i, int c) +{ + qcAssertPre( i < fSize); + QcLinInEqColState *state = getState( i); + if ((c ^ state->getCondition()) + & QcLinInEqColState::fStructural) + { + if (c & QcLinInEqColState::fStructural) + LinkStruct( state); + else + UnlinkStruct( state); + } + state->setCondition( c); +} + +inline void +SetObjValue(unsigned i, numT v) +{ + qcAssertPre (i < fSize); + ((QcLinInEqColState *)fStates[i])->fObj = v; +} + +inline void +SetConstrained(unsigned i, bool c) +{ + qcAssertPre (i < fSize); + ((QcLinInEqColState *)fStates[i])->fIsConstrained = c; +} + + +#ifndef NDEBUG +//cf +void +assertLinkageInvar() const +{ + unsigned nStructural = 0; + for (QcState **i = fStates + fSize; i-- != fStates;) + { + QcLinInEqColState const *state = CAST(QcLinInEqColState const *, *i); + if (state->getCondition() & QcLinInEqColState::fStructural) + nStructural++; + else + { + assert( state->fPrevStruct == 0); + assert( state->fNextStruct == 0); + } + } + + assert( (fStructVarList == 0) + || (fStructVarList->fPrevStruct == 0)); + for (QcLinInEqColState *curr = fStructVarList; + curr != 0; + curr = curr->fNextStruct) + { + assert( curr->getCondition() & QcLinInEqColState::fStructural); + assert( (curr->fNextStruct == 0) + || (curr->fNextStruct->fPrevStruct == curr)); + assert( nStructural != 0); + nStructural--; + } + assert( nStructural == 0); +} + +//cf +virtual void +virtualAssertLinkageInvar() const +{ + assertLinkageInvar(); + QcLinEqColStateVector::virtualAssertLinkageInvar(); +} +#endif + + +//cf +virtual void +FixLinkage() +{ + dbg(assertLinkageInvar()); + +#if 0 /* shouldn't be necessary any more. */ + fStructVarList = 0; + + for (unsigned i = 0; i < fSize; i++) + { + QcLinInEqColState *state = (QcLinInEqColState *)fStates[i]; + state->fNextStruct = 0; + state->fPrevStruct = 0; + + if (state->getCondition() & QcLinInEqColState::fStructural) + LinkStruct( state); + } +#endif + + QcLinEqColStateVector::FixLinkage(); +} + +//o[d] private: + +inline void +LinkStruct(QcLinInEqColState *state) + // Only accesses the current item and those linked to StructVarList. + // Other items may have invalid NextStruct and PrevStruct pointers. +{ + qcAssertPre( state->fPrevStruct == 0); + qcAssertPre( state->fNextStruct == 0); + qcAssertPre( state != fStructVarList); + + if (fStructVarList != 0) + { + state->fNextStruct = fStructVarList; + fStructVarList->fPrevStruct = state; + } + + fStructVarList = state; +} + +inline void +UnlinkStruct(QcLinInEqColState *me) +{ + qcAssertPre( (me->fPrevStruct == 0) + == (fStructVarList == me)); + + if (me->fPrevStruct == 0) + fStructVarList = me->fNextStruct; + else + me->fPrevStruct->fNextStruct = me->fNextStruct; + + if (me->fNextStruct != 0) + me->fNextStruct->fPrevStruct = me->fPrevStruct; + + me->fPrevStruct = 0; + me->fNextStruct = 0; +} + +inline void +UnlinkStruct(unsigned i) +{ + qcAssertPre (i < fSize); + + QcLinInEqColState *me = (QcLinInEqColState *)fStates[i]; + UnlinkStruct( me); +} + + +//o[d] protected: + +//cf +virtual void +Alloc(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fCapacity); + + for (unsigned i = start - fStates; + start != finish; + start++, i++) + *start = new QcLinInEqColState( i); +} + + +//cf +virtual void +AddToList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start < finish); + qcAssertPre( finish <= getAllocEnd()); + + QcLinEqColStateVector::AddToList( start, finish); + + for(; start != finish; start++) + { + QcLinInEqColState *state = CAST(QcLinInEqColState *, *start); + + assert( (state->fNextStruct == 0) + && (state->fPrevStruct == 0) + && (state->getCondition() == QcLinInEqColState::fStructural) + && (!state->fIsConstrained) + && (state->fObj == 0.0)); + + LinkStruct( state); + } +} + + +//cf +virtual void +RemoveFromList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fSize); + + for (QcState **i = start; i != finish; i++) + { + QcLinInEqColState *state = CAST(QcLinInEqColState *, *i); + + if (state->getCondition() & QcLinInEqColState::fStructural) + UnlinkStruct( i - fStates); + state->setCondition( QcLinInEqColState::fStructural); + state->fIsConstrained = false; + state->fObj = 0.0; + } + + QcLinEqColStateVector::RemoveFromList( start, finish); +} + + +private: +inline QcLinInEqColState * +getState(unsigned i) const +{ + qcAssertPre( i < fSize); + QcLinInEqColState *ret = CAST(QcLinInEqColState *, fStates[i]); + qcAssertPost( ret != 0); + return ret; +} + + +//begin o[d] +public: + /** head of linked list of structural variables. */ + QcLinInEqColState *fStructVarList; +//end o[d] +//o[d] }; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcLinInEqColStateVector.hh b/src/kits/interface/qoca/QcLinInEqColStateVector.hh new file mode 100644 index 0000000000..377a0c1724 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqColStateVector.hh @@ -0,0 +1,143 @@ +// Generated automatically from QcLinInEqColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcLinInEqColStateVector.H" +#ifndef QcLinInEqColStateVectorIFN +#define QcLinInEqColStateVectorIFN +#line 1 "QcLinInEqColStateVector.ch" +// $Id: QcLinInEqColStateVector.ch,v 1.5 2000/12/13 01:44:58 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + + +#include +#include + + + + + + + +#line 89 "QcLinInEqColStateVector.ch" +//-----------------------------------------------------------------------// +// Setter functions +//-----------------------------------------------------------------------// + + +#line 110 "QcLinInEqColStateVector.ch" +inline void +QcLinInEqColStateVector::SetObjValue(unsigned i, numT v) +{ + qcAssertPre (i < fSize); + ((QcLinInEqColState *)fStates[i])->fObj = v; +} + +inline void +QcLinInEqColStateVector::SetConstrained(unsigned i, bool c) +{ + qcAssertPre (i < fSize); + ((QcLinInEqColState *)fStates[i])->fIsConstrained = c; +} + + +#ifndef NDEBUG + +#line 165 "QcLinInEqColStateVector.ch" +#endif + + + +#line 193 "QcLinInEqColStateVector.ch" +inline void +QcLinInEqColStateVector::LinkStruct(QcLinInEqColState *state) + // Only accesses the current item and those linked to StructVarList. + // Other items may have invalid NextStruct and PrevStruct pointers. +{ + qcAssertPre( state->fPrevStruct == 0); + qcAssertPre( state->fNextStruct == 0); + qcAssertPre( state != fStructVarList); + + if (fStructVarList != 0) + { + state->fNextStruct = fStructVarList; + fStructVarList->fPrevStruct = state; + } + + fStructVarList = state; +} + +inline void +QcLinInEqColStateVector::UnlinkStruct(QcLinInEqColState *me) +{ + qcAssertPre( (me->fPrevStruct == 0) + == (fStructVarList == me)); + + if (me->fPrevStruct == 0) + fStructVarList = me->fNextStruct; + else + me->fPrevStruct->fNextStruct = me->fNextStruct; + + if (me->fNextStruct != 0) + me->fNextStruct->fPrevStruct = me->fPrevStruct; + + me->fPrevStruct = 0; + me->fNextStruct = 0; +} + +inline void +QcLinInEqColStateVector::UnlinkStruct(unsigned i) +{ + qcAssertPre (i < fSize); + + QcLinInEqColState *me = (QcLinInEqColState *)fStates[i]; + UnlinkStruct( me); +} + + + + + +#line 305 "QcLinInEqColStateVector.ch" +inline QcLinInEqColState * +QcLinInEqColStateVector::getState(unsigned i) const +{ + qcAssertPre( i < fSize); + QcLinInEqColState *ret = CAST(QcLinInEqColState *, fStates[i]); + qcAssertPost( ret != 0); + return ret; +} + + + +#line 323 "QcLinInEqColStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcLinInEqColStateVectorIFN */ diff --git a/src/kits/interface/qoca/QcLinInEqRowColStateVector.H b/src/kits/interface/qoca/QcLinInEqRowColStateVector.H new file mode 100644 index 0000000000..81e121db9f --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqRowColStateVector.H @@ -0,0 +1,71 @@ +// Generated automatically from QcLinInEqRowColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcLinInEqRowColStateVectorDCL +#define QcLinInEqRowColStateVectorDCL +#line 1 "QcLinInEqRowColStateVector.ch" +// $Id: QcLinInEqRowColStateVector.ch,v 1.1 2000/11/29 04:31:16 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcLinEqRowColStateVector.hh" +#include "qoca/QcLinInEqColStateVector.H" + + +class QcLinInEqRowColStateVector + : public QcLinEqRowColStateVector +{ +public: + +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// +QcLinInEqRowColStateVector() + : QcLinEqRowColStateVector(new QcLinInEqColStateVector()), + fColState((QcLinInEqColStateVector *)QcLinEqRowColStateVector::fColState) +{ +} + + +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + +virtual void +SwapColumns(unsigned v1, unsigned v2); +#line 142 "QcLinInEqRowColStateVector.ch" +public: + QcLinInEqColStateVector *fColState; + +}; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcLinInEqRowColStateVectorDCL */ diff --git a/src/kits/interface/qoca/QcLinInEqRowColStateVector.cc b/src/kits/interface/qoca/QcLinInEqRowColStateVector.cc new file mode 100644 index 0000000000..83babddc02 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqRowColStateVector.cc @@ -0,0 +1,144 @@ +// Generated automatically from QcLinInEqRowColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcLinInEqRowColStateVector.hh" +#line 1 "QcLinInEqRowColStateVector.ch" +// $Id: QcLinInEqRowColStateVector.ch,v 1.1 2000/11/29 04:31:16 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcLinEqRowColStateVector.hh" + + + + + + + + +#line 46 "QcLinInEqRowColStateVector.ch" +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + +void +QcLinInEqRowColStateVector::SwapColumns(unsigned v1, unsigned v2) +{ + qcAssertPre( v1 < fColState->getNColumns()); + qcAssertPre( v2 < fColState->getNColumns()); + + if (v1 == v2) + return; + + QcLinInEqColState *r1 = (QcLinInEqColState *)fColState->GetState(v1); + QcLinInEqColState *r2 = (QcLinInEqColState *)fColState->GetState(v2); + + /* TODO: find out why we swap fIsConstrained and fCondition only if + at least one of v1,v2 is structural. */ + + // Exchange the data contents. First fix up the linkage + if ((r1->getCondition() ^ r2->getCondition()) + & QcLinInEqColState::fStructural) + { + if (r2->getCondition() & QcLinInEqColState::fStructural) { + // Make r1 original structural + QcLinInEqColState *temp = r2; + r2 = r1; + r1 = temp; + } + + if (r1->fPrevStruct == 0) + { + assert( fColState->fStructVarList == r1); + fColState->fStructVarList = r2; + } + else + r1->fPrevStruct->fNextStruct = r2; + + r2->fNextStruct = r1->fNextStruct; + r2->fPrevStruct = r1->fPrevStruct; + + if (r1->fNextStruct != 0) + r1->fNextStruct->fPrevStruct = r2; + + r1->fNextStruct = 0; + r1->fPrevStruct = 0; + + { + int r1Cond = r1->fCondition; + r1->fCondition = r2->fCondition; + r2->fCondition = r1Cond; + } + + { + bool r1IsConst = r1->fIsConstrained; + r1->fIsConstrained = r2->fIsConstrained; + r2->fIsConstrained = r1IsConst; + } + } + else if ((r1->fCondition & r2->fCondition) + & QcLinInEqColState::fStructural) + { + { + int r1Cond = r1->fCondition; + r1->fCondition = r2->fCondition; + r2->fCondition = r1Cond; + } + { + bool r1IsConst = r1->fIsConstrained; + r1->fIsConstrained = r2->fIsConstrained; + r2->fIsConstrained = r1IsConst; + } + } + else + { + static bool foundSame = false; + if (!foundSame + && (r1->fCondition == r2->fCondition) + && (r1->fIsConstrained == r2->fIsConstrained)) + { + cerr << __FILE__ ":" << __LINE__ << ": found same.\n"; + foundSame = true; + } + else + { + cerr << __FILE__ ":" << __LINE__ << ": Note: Found difference.\n"; + } + } + + //effic: Don't do this each time. + dbg(fColState->assertLinkageInvar()); + + QcLinEqRowColStateVector::SwapColumns(v1, v2); +} + + +#line 147 "QcLinInEqRowColStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcLinInEqRowColStateVector.ch b/src/kits/interface/qoca/QcLinInEqRowColStateVector.ch new file mode 100644 index 0000000000..27a9231b23 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqRowColStateVector.ch @@ -0,0 +1,154 @@ +// $Id: QcLinInEqRowColStateVector.ch,v 1.1 2000/11/29 04:31:16 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcLinEqRowColStateVector.hh" +//o[d] #include "qoca/QcLinInEqColStateVector.H" +//o[i] #include "qoca/QcLinInEqColStateVector.hh" + +//o[d] class QcLinInEqRowColStateVector +//o[d] : public QcLinEqRowColStateVector +//o[d] { +//o[d] public: +//begin o[d] +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// +QcLinInEqRowColStateVector() + : QcLinEqRowColStateVector(new QcLinInEqColStateVector()), + fColState((QcLinInEqColStateVector *)QcLinEqRowColStateVector::fColState) +{ +} +//end o[d] + +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// +//cf +virtual void +SwapColumns(unsigned v1, unsigned v2) +{ + qcAssertPre( v1 < fColState->getNColumns()); + qcAssertPre( v2 < fColState->getNColumns()); + + if (v1 == v2) + return; + + QcLinInEqColState *r1 = (QcLinInEqColState *)fColState->GetState(v1); + QcLinInEqColState *r2 = (QcLinInEqColState *)fColState->GetState(v2); + + /* TODO: find out why we swap fIsConstrained and fCondition only if + at least one of v1,v2 is structural. */ + + // Exchange the data contents. First fix up the linkage + if ((r1->getCondition() ^ r2->getCondition()) + & QcLinInEqColState::fStructural) + { + if (r2->getCondition() & QcLinInEqColState::fStructural) { + // Make r1 original structural + QcLinInEqColState *temp = r2; + r2 = r1; + r1 = temp; + } + + if (r1->fPrevStruct == 0) + { + assert( fColState->fStructVarList == r1); + fColState->fStructVarList = r2; + } + else + r1->fPrevStruct->fNextStruct = r2; + + r2->fNextStruct = r1->fNextStruct; + r2->fPrevStruct = r1->fPrevStruct; + + if (r1->fNextStruct != 0) + r1->fNextStruct->fPrevStruct = r2; + + r1->fNextStruct = 0; + r1->fPrevStruct = 0; + + { + int r1Cond = r1->fCondition; + r1->fCondition = r2->fCondition; + r2->fCondition = r1Cond; + } + + { + bool r1IsConst = r1->fIsConstrained; + r1->fIsConstrained = r2->fIsConstrained; + r2->fIsConstrained = r1IsConst; + } + } + else if ((r1->fCondition & r2->fCondition) + & QcLinInEqColState::fStructural) + { + { + int r1Cond = r1->fCondition; + r1->fCondition = r2->fCondition; + r2->fCondition = r1Cond; + } + { + bool r1IsConst = r1->fIsConstrained; + r1->fIsConstrained = r2->fIsConstrained; + r2->fIsConstrained = r1IsConst; + } + } + else + { + static bool foundSame = false; + if (!foundSame + && (r1->fCondition == r2->fCondition) + && (r1->fIsConstrained == r2->fIsConstrained)) + { + cerr << __FILE__ ":" << __LINE__ << ": found same.\n"; + foundSame = true; + } + else + { + cerr << __FILE__ ":" << __LINE__ << ": Note: Found difference.\n"; + } + } + + //effic: Don't do this each time. + dbg(fColState->assertLinkageInvar()); + + QcLinEqRowColStateVector::SwapColumns(v1, v2); +} + +//begin o[d] +public: + QcLinInEqColStateVector *fColState; +//end o[d] +//o[d] }; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcLinInEqRowColStateVector.hh b/src/kits/interface/qoca/QcLinInEqRowColStateVector.hh new file mode 100644 index 0000000000..482cf23a66 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqRowColStateVector.hh @@ -0,0 +1,56 @@ +// Generated automatically from QcLinInEqRowColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcLinInEqRowColStateVector.H" +#ifndef QcLinInEqRowColStateVectorIFN +#define QcLinInEqRowColStateVectorIFN +#line 1 "QcLinInEqRowColStateVector.ch" +// $Id: QcLinInEqRowColStateVector.ch,v 1.1 2000/11/29 04:31:16 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcLinEqRowColStateVector.hh" + +#include "qoca/QcLinInEqColStateVector.hh" + + + + + + +#line 46 "QcLinInEqRowColStateVector.ch" +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + +#line 147 "QcLinInEqRowColStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcLinInEqRowColStateVectorIFN */ diff --git a/src/kits/interface/qoca/QcLinInEqSolver.cc b/src/kits/interface/qoca/QcLinInEqSolver.cc new file mode 100644 index 0000000000..615d2d81c9 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqSolver.cc @@ -0,0 +1,871 @@ +// $Id: QcLinInEqSolver.cc,v 1.24 2000/12/15 01:20:05 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcLinInEqSolver.hh" +#include "qoca/QcTableauRowIterator.hh" +#include "qoca/QcTableauColIterator.hh" +#include "qoca/QcBasicVarIndexIterator.hh" +#include "qoca/QcParamVarIndexIterator.hh" +#include "qoca/QcVariableIndexIterator.hh" +#include "qoca/QcStructVarIndexIterator.hh" +#include "qoca/QcSparseMatrixRowIterator.hh" + +void QcLinInEqSolver::AddDualCoeffs(QcLinPoly &lpoly, int p) + // Used by Generate constraints to add the dual variable + // coefficients to a linpoly corresponding to parameter p. + // Assumes the dual variables have already been allocated. +{ + for (QcTableauColIterator varCoeffs( fTableau, p); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + if (!fTableau.IsRestricted( varCoeffs.getIndex())) + continue; + + int cvi = fTableau.GetBasicVar (varCoeffs.getIndex()); + assert ((unsigned) cvi < fDuals.size()); + QcFloatRep *dualVar = fDuals.varPtr( cvi); + + // Register the new dual index + if (!fSubVBiMap.IdentifierPtrPresent( dualVar)) + { + unsigned dualIndex = fSubTableau.AddDual(); + fSubVBiMap.Update( dualVar, dualIndex); + QcFloatRep *primeVar = fSubVBiMap.getIdentifierPtr( cvi); + fDuals.push_back( primeVar, cvi); + // This code is far from ideal for a number of reasons: + // 1) It uses knowledge about how LinSimp is implemented - + // specifically how the index for the new dual is allocated + // on the fly. + // 2) Looking up the handle for the corresponding variable + // via the variable bimap seems a bit heavy handed. + // + // This will be rethought when the interfaces are revamped. + } + lpoly.add( varCoeffs.getValue(), dualVar); + } + + dbg(assertInvar()); +} + + +void QcLinInEqSolver::BeginEdit() +{ + fAI = QcTableau::fInvalidVariableIndex; + fSubSystem.Restart(); + + // Let fVarsByIndex be a version of fEditVars by index. + { + fVarsByIndex.resize(0); + for (vector::iterator evi = fEditVars.begin(), eviEnd = fEditVars.end(); + evi != eviEnd; + ++evi) + fVarsByIndex.push_back( fVBiMap.Index( *evi)); + } + + /* Make a copy of the main tableau coefficients in fCacheCoeffs to speed up + GenerateKT. This is performed only if the virtual tableau or rhs is + used. */ + CacheTableau(); + + // Ensure variable indices are the same by adding variables into the + // sub-tableau. This may be improved later by just copying the bimaps. + PrepareVariables(); + + // Calculates fDepPars, fDepBasicVars and fDepParVars. + TransitiveClosure(); + + // Place constraints with slack basic variables with dependant variable in + // fDepParVars into fSubLS tableau. + for (QcBasicVarIndexIterator bvIt( fTableau); + !bvIt.AtEnd(); + bvIt.Increment()) + { + if (!fTableau.IsSlack( bvIt.getIndex())) + continue; + + /* Check if the current constraint has a dependant parameter variable. */ + unsigned c = bvIt.getConstraintBasicIn(); + assert (c < fTableau.getNRows()); + QcSparseMatrixRowIterator varCoeffs (fCacheCoeff, c); + bool hasDepPar = false; + while (!varCoeffs.AtEnd()) + { + if (IsDepVar( varCoeffs.getIndex())) + { + hasDepPar = true; + break; + } + varCoeffs.Increment(); + } + + /* If so, then add the solved form constraint into fSubLS tableau. */ + if (hasDepPar) + { + QcLinPoly lpoly; + lpoly.add( fTableau.GetValue( c, bvIt.getIndex()), + fVBiMap.getIdentifierPtr( bvIt.getIndex())); + varCoeffs.SetToBeginOf( c); + while (!varCoeffs.AtEnd()) + { + QcFloatRep *v = fVBiMap.getIdentifierPtr( varCoeffs.getIndex()); + lpoly.add( varCoeffs.getValue(), v); + varCoeffs.Increment(); + } + +#ifdef qcRealTableauRHS + QcConstraint lc ("", lpoly, QcConstraintRep::coEQ, + fTableau.GetRHS(c)); +#else + QcConstraint lc ("", lpoly, QcConstraintRep::coEQ, + fCacheRHS[c]); +#endif + dbg(bool added =) + fSubSystem.CopyConstraint( lc, bvIt.getIndex()); + assert( added); + } + } + + // This needs the original constraints copied into + // subsystem. The dual variables are preallocated. + // The indices are assigned below. + CreateDualVars(); + + // Create a variable for the desired value of each EditVars. + CreateDesValVars(); + + fAI = fSubTableau.AddArtificial (-1.0); + fAV.SetWeight (0.0); // Just in case it somehow get taken notice of. + fDuals.push_back( fAV.pointer(), fAI); // This shouldn't need to be accessed. + fSubVBiMap.Update (fAV, fAI); + + // Add Edit Variables. + fSystem.ClearEditVars(); + + for (vector::iterator viIt = fDepPars.begin(); + viIt != fDepPars.end(); ++viIt) + { + QcFloat &v = fSubVBiMap.Identifier (*viIt); + fSystem.RegisterEditVar (v); + } + + GenerateKT2(); + + // Enter fDualIndex values for non slack variables + { + unsigned ssCols = fSubTableau.getNColumns(); + assert( ssCols <= fDuals.size()); // todo: this could probably be tightened. + for (unsigned vi = 0; vi < ssCols; vi++) + { + QcFloatRep *dualVar = fDuals.varPtr( vi); + int dualVarIx = fSubVBiMap.safeIndex( dualVar); + if (dualVarIx >= 0) + fDuals.setIndex( vi, dualVarIx); + // TODO: Consider making the above non-conditional. + } + } + + // The subsystem has both the dual and restricted primal constraints. + LoadDesVarCache(); + MakeFeasibleComplex(); + qcAssert(fSubTableau.IsBasicFeasibleSolved()); + fSubSystem.InEqRawSolveComplex(); + fSubSystem.EqRawSolveComplex(); + // And now the variable values provide the solution. + fSystem.EqSolve(); // Solve using slack values as well + fEditVarsSetup = true; + + dbg(assertInvar()); +} + + +void +QcLinInEqSolver::CacheTableau() +{ + fCacheCoeff.clear(); + fCacheCoeff.Resize( fTableau.getNRows(), + fTableau.getNColumns()); + + for (QcParamVarIndexIterator vIt( fTableau); + !vIt.AtEnd(); + vIt.Increment()) + { + for (QcTableauColIterator colCoeffs( fTableau, vIt.getIndex()); + !colCoeffs.AtEnd(); + colCoeffs.Increment()) + { + fCacheCoeff.SetValue( colCoeffs.getIndex(), vIt.getIndex(), + colCoeffs.getValue()); + } + } + + // Make a copy of rhs to speed up GenerateKT. +#ifndef qcRealTableauRHS + fCacheRHS.Resize( 0); + fCacheRHS.Resize( tableau.getNRows()); + for (unsigned r = 0; r < tableau.getNRows(); r++) + fCacheRHS[r] = tableau.GetRHS(r); +#endif +} + +void QcLinInEqSolver::CreateDesValVars() +{ + fDesValVar.resize( fTableau.getNColumns()); + fDesValIndex.resize( fTableau.getNColumns()); + + for (unsigned i = 0; i < fTableau.getNColumns(); i++) + fDesValIndex[i] = QcTableau::fInvalidVariableIndex; + + for (vector::const_iterator i = fVarsByIndex.begin(), iEnd = fVarsByIndex.end(); + i != iEnd; i++) + { + unsigned const vi = *i; + QcFloat v("desval var", fSubVBiMap.getIdentifierPtr( vi)->DesireValue()); + v.SetWeight(0.0); + v.SuggestValue(v.Value()); + fDesValIndex[vi] = fSubTableau.AddDesValVar(); + fDesValVar[vi] = v; + fSubVBiMap.Update(v, fDesValIndex[vi]); + fDuals.push_back( v.pointer(), fDesValIndex[vi]); + assert( v.Counter() > 1); + } + + dbg(assertInvar()); +} + +void QcLinInEqSolver::CreateDualVars() + // Create complementary variables for each variable in + // the primal tableau. The fDual array is used to locate these + // variables. N.B. Not all these variables need be used. + // The rest of fDual is initialised in AddDualCoeffs. +{ + for (unsigned i = 0; i < fSubTableau.getNColumns(); i++) + { + QcFloat v( "Dual Var"); + fDuals.push_back( v.pointer(), QcTableau::fInvalidVariableIndex); + assert( v.Counter() > 1); + } +} + +numT QcLinInEqSolver::Derivative1(QcFloat &p, int pIndex, QcLinPoly &lpoly) + { return Derivative( p, pIndex, lpoly, false); } + +numT QcLinInEqSolver::Derivative2(QcFloat &p, int pIndex, QcLinPoly &lpoly) + { return Derivative( p, pIndex, lpoly, true); } + +numT QcLinInEqSolver::Derivative(QcFloat &p, int pIndex, QcLinPoly &lpoly, bool phaseII) + // Generate the expression (lpoly,rhs): df'/dp + dual(p). + // where f' = least squares objective function with basic variables + // eliminated and dual(p) is the column coeffs of the original + // tableau for p applied to new dual variables. + // The variable coefficients are accumulated in lpoly, the rhs value + // is returned. +{ + qcAssertPre(p == fSubVBiMap.Identifier(pIndex)); + numT rhs = 0.0; + numT pWeight2 = p.Weight() * 2; + numT pAccumulator = pWeight2; + + for (QcBasicVarIndexIterator bvIt( fTableau); + !bvIt.AtEnd(); + bvIt.Increment()) + { + QcFloat &bv = fSubVBiMap.Identifier (bvIt.getIndex()); + numT bvWeight = bv.Weight(); + + if (QcUtility::IsZero( bvWeight)) + continue; + + unsigned c = bvIt.getConstraintBasicIn(); + assert( c < fTableau.getNRows()); + numT pCoeff = fCacheCoeff.GetValue(c, pIndex); + + if (!QcUtility::IsZero( pCoeff)) + { + // bv is basic in the solved form constraint with index c. + numT factor = bv.Weight() * pCoeff * 2; + pAccumulator += factor * pCoeff; + + // constraint c will be used to eliminate bv, + // and pCoeff is the coefficient of p in the elimination. + for (QcSparseMatrixRowIterator varCoeffs( fCacheCoeff, c); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + if (varCoeffs.GetIndex() != pIndex) + { + QcFloatRep *pv = fSubVBiMap.getIdentifierPtr( varCoeffs.GetIndex()); + lpoly.add( factor * varCoeffs.GetValue(), pv); + } + } + + if (phaseII + && IsDepBasicVar( bvIt.getIndex()) + && IsEditVar( bv)) + { +#ifdef qcRealTableauRHS + rhs += factor * fTableau.GetRHS(c); +#else + rhs += factor * fCacheRHS[c]; +#endif + lpoly.add( factor, fDesValVar[bvIt.getIndex()].pointer()); + } + else + { +#ifdef qcRealTableauRHS + rhs += factor * (fTableau.GetRHS(c) - bv.DesireValue()); +#else + rhs += factor * (fCacheRHS[c] - bv.GetDesValue()); +#endif + } + } + } + + lpoly.Push(pAccumulator, p); + AddDualCoeffs(lpoly, pIndex); + + if (phaseII + && IsEditVar( p)) + { + QcFloat &pDV = fDesValVar[pIndex]; + lpoly.Push(-pWeight2, pDV); + } + else + rhs += pWeight2 * p.DesireValue(); + + return rhs; +} + +void QcLinInEqSolver::EndEdit() +{ + // The EndEdit in the QcSolver class is called so that the weight of all + // the edit variable are set back to stay weight, and for ClearEditVars. + QcSolver::EndEdit(); + + vector::iterator vIt; + + for (unsigned int vi = 0; vi < fDepBasicVars.size(); ++vi) + if (fDepBasicVars[vi]) + fVBiMap.getIdentifierPtr( vi)->RestDesVal(); + + for (vIt = fDepPars.begin(); vIt != fDepPars.end(); ++vIt) + fVBiMap.getIdentifierPtr( *vIt)->RestDesVal(); + + fDuals.clear(); +} + +void QcLinInEqSolver::GenerateKT1() + // Generate the constraint df'/dp + dual(p) == 0 for each unconstrained + // primal parameter p. Then generate the constraint + // df'/dp + dual(p) >= 0 for each constrained (i.e. slack) primal + // parameter. Add the new constraint directly to the subsystem. + // Where f' = least squares objective function with basic variables + // eliminated, and dual(p) is the column coeffs of the original + // tableau for p applied to new dual variables. +{ + QcParamVarIndexIterator vIt( fTableau); + + while (!vIt.AtEnd()) + { + unsigned const vi = vIt.getIndex(); + // The !IsFree test avoids entering a redundant constraint in + // the subsystem (to save time). There is no need to call + // v.Set when the variable is free since this will be + // done when fSystem.Solve() is called later. + if (!fTableau.IsFree( vi) + && fTableau.IsConstrained( vi)) + { + // Primal slack parameters were given a weight of 0 in Solve. + QcLinPoly lpoly; + /* [pjm:] It makes a difference that this is `QcFloat p' rather than + `QcFloat &p', because p becomes unused during fSubSystem.CopyInEq + below. Haven't checked whether this is OK. */ + QcFloat p = fSubVBiMap.Identifier( vi); + numT rhs = Derivative1(p, vi, lpoly); + lpoly.add( 1.0, fAV); // artificial variable coeff + QcConstraint lc("", lpoly, QcConstraintRep::coGE, rhs); + dbg(bool added =) + fSubSystem.CopyInEq( lc); // new slack is made basic + assert( added); + fDuals.push_back( p.pointer(), vi); // p corresponds to new slack + fDuals.setIndex( vi, fSubTableau.GetColumns() - 1); + // fDual[vi].SetName("Dual Slack Var"); + } + vIt.Increment(); + } + + fSubTableau.SetBeginEq(); + vIt.Reset(); + + while (!vIt.AtEnd()) + { + unsigned const vi = vIt.getIndex(); + // The !IsFree test avoids entering a redundant constraint in + // the subsystem (to save time). There is no need to call + // v.Set when the variable is free since this will be + // done when fSystem.Solve() is called later. + if (!fTableau.IsFree( vi) + && !fTableau.IsConstrained( vi)) + { + // Do the unrestricted primal parameters. + QcLinPoly lpoly; + QcFloat &viVar = fSubVBiMap.Identifier(vi); + numT rhs = Derivative1(viVar, vi, lpoly); + // No need to add the (-1) artificial variable coeff + // here since the primal parameter is unrestricted. + QcConstraint lc("", lpoly, QcConstraintRep::coEQ, rhs); + dbgPost(bool added =) + fSubSystem.AddConstraint(lc, viVar); + qcAssertPost( added); + } + vIt.Increment(); + } + + dbg(assertInvar()); +} + +void QcLinInEqSolver::GenerateKT2() + // Generate the constraint df'/dp + dual(p) == 0 for each unconstrained + // primal parameter p. Then generate the constraint + // df'/dp + dual(p) >= 0 for each constrained (i.e. slack) primal + // parameter. Add the new constraint directly to the subsystem. + // Where f' = least squares objective function with basic variables + // eliminated, and dual(p) is the column coeffs of the original + // tableau for p applied to new dual variables. +{ + vector::const_iterator viIt; + + for (viIt = fDepPars.begin(); viIt != fDepPars.end(); ++viIt) + { + unsigned const vi = *viIt; + + if (!fTableau.IsFree( vi) + && fTableau.IsConstrained( vi)) + { + // Primal slack parameters were given a weight of 0 in Solve. + QcLinPoly lpoly; + QcFloat &p = fSubVBiMap.Identifier( vi); + numT rhs = Derivative2(p, vi, lpoly); + lpoly.add( 1.0, fAV); // artificial variable coeff + QcConstraint lc("", lpoly, QcConstraintRep::coGE, rhs); + dbg(bool added =) + fSubSystem.CopyInEq( lc); // new slack is made basic + assert( added); + fDuals.push_back( p.pointer(), vi); // p corresponds to new slack + fDuals.setIndex( vi, fSubTableau.GetColumns() - 1); + // fDual[vi].SetName("Dual Slack Var"); + } + } + + fSubTableau.SetBeginEq(); + + for (viIt = fDepPars.begin(); viIt != fDepPars.end(); ++viIt) + { + unsigned const vi = *viIt; + + if (!fTableau.IsFree( vi) + && !fTableau.IsConstrained( vi)) + { + // First do the unrestricted primal parameters. + QcLinPoly lpoly; + QcFloat &viItVar = fSubVBiMap.Identifier( vi); + numT rhs = Derivative2( viItVar, vi, lpoly); + // No need to add the (-1) artificial variable coeff + // here since the primal parameter is unrestricted. + QcConstraint lc("", lpoly, QcConstraintRep::coEQ, rhs); + dbgPost(bool consistent =) + fSubSystem.AddConstraint(lc, viItVar); + qcAssertPost(consistent); + } + } + + dbg(assertInvar()); +} + +void QcLinInEqSolver::LoadDesVarCache() + // Required for desval variables. +{ + for (unsigned int i = 0; i < fDesValVar.size(); i++) { + if (fDesValIndex[i] != QcTableau::fInvalidVariableIndex) { + int vi = fDesValIndex[i]; + fSubTableau.SetDesireValue(vi, + fSubVBiMap.Identifier(i).DesireValue()); + } + } +} + +void QcLinInEqSolver::MakeFeasible() +{ + // Find the restricted row with most negative RHS + numT mostNeg = 0.0; + int mostNegIndex = QcTableau::fInvalidConstraintIndex; + int rows = fSubTableau.GetRows(); + + for (int ci = 0; ci < rows; ci++) { + if (ci >= fSubTableau.GetBeginEq()) + break; + + if (fSubTableau.IsRestricted(ci)) { + numT coeff = fSubTableau.GetRHS(ci); + + if (coeff < mostNeg) { + mostNeg = coeff; + mostNegIndex = ci; + } + } + } + + if (!QcUtility::IsNegative(mostNeg)) + return; // tableau is already feasible + + // Initialize the coefficients of fAV in all the constraints with 1.0. + fSubTableau.SetArtificial(-1.0); + + int justLeft = fSubTableau.GetBasicVar(mostNegIndex); + fSubTableau.RestrictedPivot(mostNegIndex, fAI); + qcAssert(fSubTableau.IsBasicFeasibleSolved()); + + // We now have a subsystem tableau which is basic feasible. + // But we wish to eliminate the artificial variable from it. + // To do so we keep pivoting on the variable complementary to the + // variable which just left the basis. + int ci; + + while (fSubTableau.IsBasic(fAI)) { // artificial variable is still basic + unsigned vi = fDuals.varIx( justLeft); // complementary variable + // Select Pivot row + qcAssert(fSubTableau.getNRestrictedRows() != 0); + ci = fSubSystem.SelectExitVar(vi); + qcAssert(ci >= 0); + + if (ci < 0) break; // Better to give up than continue now. + + justLeft = fSubTableau.GetBasicVar(ci); + #ifdef qcSafetyChecks + bool pivoted = fSubTableau.RestrictedPivot(ci, vi); + qcAssert(pivoted); + #else + fSubTableau.RestrictedPivot(ci, vi); + #endif + } +} + +void QcLinInEqSolver::MakeFeasibleComplex() +{ + // Find the restricted row with most negative RHS + numT mostNeg = 0.0; + int mostNegIndex = QcTableau::fInvalidConstraintIndex; + int rows = fSubTableau.GetRows(); + + for (int ci = 0; ci < rows; ci++) { + if (ci >= fSubTableau.GetBeginEq()) + break; + + if (fSubTableau.IsRestricted(ci)) { + numT coeff = fSubTableau.GetComplexRHS(ci); + if (coeff < mostNeg) { + mostNeg = coeff; + mostNegIndex = ci; + } + } + } + + if (!QcUtility::IsNegative(mostNeg)) + return; // tableau is already feasible + assert( mostNegIndex >= 0); + + // Initialize the coefficients of fAV in all the constraints with 1.0. + fSubTableau.SetArtificial(-1.0); + + int justLeft = fSubTableau.GetBasicVar(mostNegIndex); + fSubTableau.RestrictedPivot(mostNegIndex, fAI); + /* FIXME: The assertion on the following line can fail (e.g. in test suite). */ + qcAssert(fSubTableau.IsBasicFeasibleSolved()); + + // We now have a subsystem tableau which is basic feasible. + // But we wish to eliminate the artificial variable from it. + // To do so we keep pivoting on the variable complementary to the + // variable which just left the basis. + int ci; + + while (fSubTableau.IsBasic(fAI)) { // artificial variable is still basic + int vi = fDuals.varIx( justLeft); // complementary variable + // Select Pivot row + qcAssert(fSubTableau.getNRestrictedRows() != 0); + ci = fSubSystem.SelectExitVarComplex(vi); + qcAssert(ci >= 0); + + if (ci < 0) break; // Better to give up than continue now. + + justLeft = fSubTableau.GetBasicVar(ci); + #ifdef qcSafetyChecks + bool pivoted = fSubTableau.RestrictedPivot(ci, vi); + qcAssert(pivoted); + #else + fSubTableau.RestrictedPivot(ci, vi); + #endif + } +} + +numT QcLinInEqSolver::Objective() +{ + numT opt( 0); + + for (QcVariableIndexIterator vIt( fTableau); + !vIt.AtEnd(); + vIt.Increment()) + { + QcFloatRep *v = fVBiMap.getIdentifierPtr( vIt.getIndex()); + numT delta = v->Value() - v->DesireValue(); + opt += v->Weight() * delta * delta; + } + + return opt; +} + +void QcLinInEqSolver::PrepareVariables() +{ + qcAssertPre( fSubSystem.getVariables_begin() == fSubSystem.getVariables_end()); + + for (unsigned vi = 0; vi < fTableau.getNColumns(); vi++) + { + QcFloat &v = fVBiMap.Identifier( vi); + if (fTableau.IsSlack( vi)) + { + // TODO: Consider making slack vars QcFixedFloat's. + v.SuggestValue( 0); + fSubSystem.AddSlack( v); + } + else + fSubSystem.AddVar( v); + } +} + +void QcLinInEqSolver::Print(ostream &os) const +{ + fSystem.Print(os); + + if (fEditVarsSetup) { + os << "Complementary pivot tableau: " << endl; + fSubTableau.Print(os); + os << endl; + os << "Sub-system notifier: " << endl; + fSubNotifier.Print(os); + os << endl; + } +} + +void QcLinInEqSolver::Resolve() +{ + if (!fEditVarsSetup) + BeginEdit(); + + // The subsystem has both the dual and restricted primal constraints. + LoadDesVarCache(); + MakeFeasibleComplex(); + + qcAssert(fSubTableau.IsBasicFeasibleSolved()); + fSubSystem.InEqRawSolveComplex(); + fSubSystem.EqRawSolveComplex(); + SubSysEqSolve(); // Solve using slack values as well + +#if qcCheckPost + checkSatisfied(); +#endif +} + +void QcLinInEqSolver::Solve() + // IMPORTANT NOTE. + // It is not necessary to call fSystem.Solve() before creating and solving + // the subsystem since the subsystem is created without using the values + // of any variables - just desired values and weights. +{ + fAI = QcTableau::fInvalidVariableIndex; + fSubSystem.Restart(); + + // Make a copy of the main tableua coefficients to speed up GenerateKT. + // This is only performed if the virtual tableau or virtual rhs is used. + CacheTableau(); + + // Ensure variable indices are the same by adding variables into the + // sub-tableau. This may be improved later by just copying the bimaps. + PrepareVariables(); + + // Place constraints with slack basic variables into fSubTableau. + for (QcBasicVarIndexIterator bvIt( fTableau); + !bvIt.AtEnd(); + bvIt.Increment()) + { + if (!fTableau.IsSlack( bvIt.getIndex())) + continue; + + unsigned c = bvIt.getConstraintBasicIn(); + QcLinPoly lpoly; + lpoly.add( fTableau.GetValue( c, bvIt.getIndex()), + fVBiMap.getIdentifierPtr( bvIt.getIndex())); + for (QcSparseMatrixRowIterator varCoeffs( fCacheCoeff, c); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + lpoly.add( varCoeffs.getValue(), + fVBiMap.getIdentifierPtr( varCoeffs.getIndex())); + } +#ifdef qcRealTableauRHS + QcConstraint lc ("", lpoly, QcConstraintRep::coEQ, + fTableau.GetRHS(c)); +#else + QcConstraint lc ("", lpoly, QcConstraintRep::coEQ, + fCacheRHS[c]); +#endif +#ifdef QcAssertions + bool success = +#endif + fSubSystem.CopyConstraint (lc, bvIt.getIndex()); + qcAssert (success); + } + + // This needs the original constraints copied into + // subsystem. The dual variables are preallocated. + // The indices are assigned below. + CreateDualVars(); + + fAI = fSubTableau.AddArtificial(-1.0); + fAV.SetWeight(0.0); // Just in case it somehow get taken notice of + fDuals.push_back( fAV.pointer(), fAI); // This shouldn't need to be accessed. + fSubVBiMap.Update(fAV, fAI); + + // Add Kuhn-Tucker constraints to the SubSystem + GenerateKT1(); + + // Enter fDualIndex values for non slack variables + { + unsigned ssCols = fSubTableau.GetColumns(); + assert( fDuals.size() >= ssCols); // todo: could probably be tightened + for (unsigned vi = 0; vi < ssCols; vi++) + { + QcFloatRep *dualVar = fDuals.varPtr( vi); + int dualVarIx = fSubVBiMap.safeIndex(dualVar); + if (dualVarIx >= 0) + fDuals.setIndex( vi, dualVarIx); + // TODO: Consider making the above unconditional. + } + } + + // The subsystem has both the dual and restricted primal constraints. + MakeFeasible(); + qcAssert(fSubTableau.IsBasicFeasibleSolved()); + fSubSystem.InEqRawSolve(); + fSubSystem.EqRawSolve(); + SubSysEqSolve(); // Solve using slack values as well + + // Rest variables by setting their desire value to the actual value + // computed above. + for (QcVariableIndexIterator vIt( fTableau); + !vIt.AtEnd(); + vIt.Increment()) + { + QcFloatRep *v = fVBiMap.getIdentifierPtr( vIt.getIndex()); + v->RestDesVal(); + } + + // And now the variable values provide the solution. + fDuals.clear(); + +#if qcCheckPost + checkSatisfied(); + dbg(assertInvar()); +#endif +} + +void QcLinInEqSolver::SubSysEqSolve() + // Equivalent to LinEqSystem::Solve +{ + #ifdef qcSafetyChecks + if (!fSubTableau.IsBasicFeasibleSolved()) + throw QcWarning(qcPlace, + "tableau is not in basic feasible solved form"); + #endif + + QcVariableIndexIterator vIt(fTableau); + + while (!vIt.AtEnd()) { + if (fTableau.IsBasic(vIt.getIndex())) { + QcFloat &v = fVBiMap.Identifier(vIt.getIndex()); + int ci = fTableau.IsBasicIn(vIt.getIndex()); + QcTableauRowIterator varCoeffs(fTableau, ci); + numT value = fTableau.GetRHS(ci); + + while (!varCoeffs.AtEnd()) { + if (varCoeffs.getIndex() != vIt.getIndex()) { + QcFloat &bv = fVBiMap.Identifier (varCoeffs.getIndex()); + value -= varCoeffs.getValue() * bv.Value(); + } + varCoeffs.Increment(); + } + + v.SetValue(QcUtility::Zeroise(value)); + } + vIt.Increment(); + } +} + +void QcLinInEqSolver::TransitiveClosure() + // Calculate fDepBasicVars and fDepPars as transitive closure of + // variables in constraints which mention EditVars. +{ + vector depVars( fVarsByIndex); + fTableau.TransitiveClosure( depVars); + + // Sift depVars into fDepPars, fDepBasicVars and fDepParVars. + fDepBasicVars.resize( fTableau.getNColumns()); + fDepParVars.resize( fTableau.getNColumns()); + + for (unsigned i = 0; i < fTableau.getNColumns(); i++) + { + /* effic: Check if this could be achieved with clear() before the above + resize. In particular, is `bool()' guaranteed to be zero, or is it a + garbage value? clear()/resize() is especially better if vector + is implemented as a bit vector. */ + fDepBasicVars[i] = false; + fDepParVars[i] = false; + } + + fDepPars.resize(0); + for (vector::const_iterator i = depVars.begin(), iEnd = depVars.end(); + i != iEnd; i++) + { + unsigned const vi = *i; + assert( vi < fDepBasicVars.size()); + if (fTableau.IsBasic( vi)) + fDepBasicVars[vi] = true; + else + { + fDepPars.push_back( vi); + fDepParVars[vi] = true; + } + } +} diff --git a/src/kits/interface/qoca/QcLinInEqSolver.hh b/src/kits/interface/qoca/QcLinInEqSolver.hh new file mode 100644 index 0000000000..f61a809ae9 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqSolver.hh @@ -0,0 +1,339 @@ +// $Id: QcLinInEqSolver.hh,v 1.17 2001/01/04 05:20:11 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// This interface needs to be read in conjuction with that of Solver. // +//============================================================================// + +#ifndef __QcInEqSolverH +#define __QcInEqSolverH + +#include "qoca/QcDelLinInEqSystem.hh" +#include "qoca/QcCompPivotSystem.hh" +#include "qoca/QcIneqSolverBase.H" + +class QcLinInEqSolver + : public QcIneqSolverBase +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcLinInEqSolver(); + QcLinInEqSolver(unsigned hintNumConstraints, unsigned hintNumVariables); + +#ifndef NDEBUG + void assertInvar() const + { + assert( (fCacheCoeff.getNRows() == 0) + || (fCacheCoeff.getNRows() == fTableau.getNRows())); + assert( (fCacheCoeff.getNColumns() == 0) + || (fCacheCoeff.getNColumns() == fTableau.getNColumns())); + + unsigned pvs = fDepParVars.size(); + assert( pvs == fDepBasicVars.size()); + /* The following may be wrong: I haven't checked that fDep*Vars get + cleared after use. Note that they are set up in BeginEdit, and + still used by EndEdit. I think this will break if someone calls + AddVar between BeginEdit and EndEdit. fixme: Look at the AddVar + case. Also consider having all users of fDep*Vars assert( + fEditVarsSetup). [Can't do this yet: fEditVarsSetup is set to true + only at end of BeginEdit.] And see what happens with + AddConstraint: it looks as if it can go badly: e.g. it doesn't seem + to clear fEditVarsSetup. */ + assert( pvs == 0 || pvs == fTableau.getNColumns()); + } +#endif + + bool IsDepBasicVar(unsigned vi) const + { + qcAssertPre( vi < fDepBasicVars.size()); + return fDepBasicVars[vi]; + } + + bool IsDepVar(unsigned vi) const + { + qcAssertPre( (vi < fDepParVars.size()) + && (vi < fDepBasicVars.size())); + return fDepParVars[vi] || fDepBasicVars[vi]; + } + + //-----------------------------------------------------------------------// + // High Level Edit Variable Interface for use by solver clients. // + //-----------------------------------------------------------------------// + virtual void BeginEdit(); + virtual void EndEdit(); + + //-----------------------------------------------------------------------// + // Constraint Solving methods // + //-----------------------------------------------------------------------// + virtual void Solve(); + // IMPORTANT NOTE. + // It is not necessary to call fSystem.solve() before creating and + // solving the subsystem since the subsystem is created without using + // the values of any variables - just desired values and weights. + virtual void Resolve(); + +protected: + /** Current value of objective function. */ + numT Objective(); + + //-----------------------------------------------------------------------// + // Sub-system specific functions. // + //-----------------------------------------------------------------------// + void AddDualCoeffs(QcLinPoly &lpoly, int p); + // Used by Generate constraints to add the dual variable + // coefficients to a linpoly corresponding to parameter p. + // Assumes the dual variables have already been allocated. + void CacheTableau(); + void CreateDesValVars(); + void CreateDualVars(); + // Create complementary variables for each variable in + // the primal tableau. The fDual array is used to locate these + // variables. N.B. Not all these variables need be used. + // The rest of fDual is initialised in AddDualCoeffs. + + numT Derivative1(QcFloat &p, int pIndex, QcLinPoly &lpoly); + numT Derivative2(QcFloat &p, int pIndex, QcLinPoly &lpoly); + numT Derivative(QcFloat &p, int pIndex, QcLinPoly &lpoly, bool phaseII); + // Generate the expression (lpoly,rhs): df'/dp + dual(p). + // where f' = least squares objective function with basic variables + // eliminated and dual(p) is the column coeffs of the original + // tableau for p applied to new dual variables. + // The variable coefficients are accumulated in lpoly, the rhs value + // is returned. + + void GenerateKT1(); + // Generate the constraint df'/dp + dual(p) == 0 for each unconstrained + // primal parameter p. Then generate the constraint + // df'/dp + dual(p) >= 0 for each constrained (i.e. slack) primal + // parameter. Add the new constraint directly to the subsystem. + // Where f' = least squares objective function with basic variables + // eliminated, and dual(p) is the column coeffs of the original + // tableau for p applied to new dual variables. + void GenerateKT2(); + // Generate the constraint df'/dp + dual(p) == 0 for each unconstrained + // primal parameter p. Then generate the constraint + // df'/dp + dual(p) >= 0 for each constrained (i.e. slack) primal + // parameter. Add the new constraint directly to the subsystem. + // Where f' = least squares objective function with basic variables + // eliminated, and dual(p) is the column coeffs of the original + // tableau for p applied to new dual variables. + void LoadDesVarCache(); + // Required for desval variables. + void MakeFeasible(); + // Make the subsystem tableau feasible + void MakeFeasibleComplex(); + // Make the subsystem tableau feasible + void PrepareVariables(); + void SubSysEqSolve(); + +public: + virtual void Print(ostream &os) const; + virtual void Restart(); + void TransitiveClosure(); + // Calculate fDepBasicVars and fDepPars as transitive closure of + // variables in constraints which mention EditVars. + +private: + class DualHolder + { + public: + + DualHolder() + : fDual(), + fDualIndex() + { } + + private: + DualHolder( DualHolder const &tmpl); + +#ifndef NDEBUG + void assertInvar() const + { + assert( fDual.size() == fDualIndex.size()); + } +#endif + + public: + ~DualHolder() + { } + + unsigned size() const + { return fDual.size(); } + + void clear() + { + fDual.clear(); + fDualIndex.clear(); + } + + void push_back( QcNullableFloat &var, unsigned vi) + { + qcAssertPre( var.pointer() != 0); + fDual.push_back( var); + fDualIndex.push_back( vi); + dbg(assertInvar()); + } + + void push_back( QcFloatRep *var, unsigned vi) + { + qcAssertPre( var != 0); + fDual.push_back( QcNullableFloat( var)); + fDualIndex.push_back( vi); + dbg(assertInvar()); + } + + QcFloatRep *varPtr( unsigned ix) const + { + qcAssertPre( ix < fDual.size()); + QcFloatRep *ret = fDual[ix].pointer(); + qcAssertPost( ret != 0); + return ret; + } + + unsigned varIx( unsigned ix) const + { + qcAssertPre( ix < fDualIndex.size()); + return fDualIndex[ix]; + } + + void setIndex( unsigned ix, unsigned varIx) + { + qcAssertPre( ix < fDualIndex.size()); + fDualIndex[ix] = varIx; + } + + private: + vector fDual; // The complementary variables. + vector fDualIndex; // The complementary variable indices. + }; + + +protected: + /** Each variable in the dual problem (fSubSystem) has a + complementary variable. This correspondance is that for all j: + +

    +
  • If variable j in the primal problem is a parameter, then, there is a + corresponding dual constraint, and fDuals.var(j) is its slack + variable. + +
  • Otherwise (i.e. if variable j in the primal problem is a basic + variable), there is a corresponding dual variable fDuals.var(j) + (as used in AddDualCoeffs). + +
+ +

The total number of variables in the dual problem is hence (primal + parametric vars + 2 × primal basic vars + artificial var). The artificial + variable is entered as fDual[fAI], though this entry is not used anywhere + except for debug state output. + +

For each i, fDuals.varIx(i) provides the index of + fDuals.var(i) in fSubSystem. + **/ + DualHolder fDuals; + + /** Artificial variable used for complementary pivot. */ + QcFloat fAV; + + /** Index of artificial variable in fSubSystem. */ + int fAI; + + vector fDepPars; + vector fVarsByIndex; + vector fDepBasicVars; + vector fDepParVars; + vector fDesValVar; + vector fDesValIndex; + + QcVariableBiMap &fVBiMap; + const QcBiMapNotifier &fNotifier; + QcConstraintBiMap &fOCBiMap; + QcDelLinInEqTableau &fTableau; + + QcCompPivotSystem fSubSystem; + QcCompPivotTableau &fSubTableau; + + QcVariableBiMap &fSubVBiMap; + const QcBiMapNotifier &fSubNotifier; + QcConstraintBiMap &fSubOCBiMap; + +private: + QcSparseMatrix fCacheCoeff; + +}; + + +inline QcLinInEqSolver::QcLinInEqSolver() + : QcIneqSolverBase(), + fAV("Artificial Var"), + fAI(QcTableau::fInvalidVariableIndex), + fVBiMap(fSystem.GetVBiMap()), + fNotifier(fSystem.GetNotifier()), + fOCBiMap(fSystem.GetOCBiMap()), + fTableau((QcDelLinInEqTableau &)fSystem.GetTableau()), + fSubTableau((QcCompPivotTableau &)fSubSystem.GetTableau()), + fSubVBiMap(fSubSystem.GetVBiMap()), + fSubNotifier(fSubSystem.GetNotifier()), + fSubOCBiMap(fSubSystem.GetOCBiMap()), + fCacheCoeff() +{ +} + +inline QcLinInEqSolver::QcLinInEqSolver(unsigned hintNumConstraints, + unsigned hintNumVariables) + : QcIneqSolverBase( hintNumConstraints, hintNumVariables), + fAV("Artificial Var"), + fAI(QcTableau::fInvalidVariableIndex), + fVBiMap(fSystem.GetVBiMap()), + fNotifier(fSystem.GetNotifier()), + fOCBiMap(fSystem.GetOCBiMap()), + fTableau((QcDelLinInEqTableau &)fSystem.GetTableau()), + fSubSystem(hintNumConstraints, hintNumVariables), + fSubTableau((QcCompPivotTableau &)fSubSystem.GetTableau()), + fSubVBiMap(fSubSystem.GetVBiMap()), + fSubNotifier(fSubSystem.GetNotifier()), + fSubOCBiMap(fSubSystem.GetOCBiMap()), + fCacheCoeff() +{ +} + +inline void QcLinInEqSolver::Restart() +{ + fSystem.Restart(); + fSubSystem.Restart(); +} + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcLinInEqSystem.cc b/src/kits/interface/qoca/QcLinInEqSystem.cc new file mode 100644 index 0000000000..a7ea096751 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqSystem.cc @@ -0,0 +1,1361 @@ +// $Id: QcLinInEqSystem.cc,v 1.18 2001/01/31 07:37:13 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// Unlike identifiers, indexes start from 0 since they are used as array and // +// matrix subscripts in the tableau. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcLinInEqSystem.hh" +#include "qoca/QcBasicVarIndexIterator.hh" +#include "qoca/QcVariableIndexIterator.hh" +#include "qoca/QcConstraintIndexIterator.hh" +#include "qoca/QcStructVarIndexIterator.hh" +#include "qoca/QcParamVarIndexIterator.hh" +#include "qoca/QcTableauRowIterator.hh" +#include "qoca/QcTableauColIterator.hh" +#include "qoca/QcDenseTableauRowIterator.hh" + +bool QcLinInEqSystem::AddConstraint(QcConstraint &c) +{ + return doAddConstraint(c, -1); +} + +bool QcLinInEqSystem::AddConstraint(QcConstraint &c, QcFloat &hint) +{ +#if qcCheckPre + int hintIx = fVBiMap.safeIndex(hint); + qcAssertExternalPre(hintIx >= 0); +#else + int hintIx = fVBiMap.Index(hint); +#endif + return doAddConstraint(c, hintIx); +} + +bool QcLinInEqSystem::doAddConstraint(QcConstraint &c, int hintIx) +{ + // If in batch mode and the one of more preceeding add-constraint + // operations failed, then should not proceed to do any more constraint + // addition. + if (fBatchAddConst && fBatchAddConstFail) + return false; + + bool success = true; + int co = AddToTableau(c); + // co is now the original constraint index + int cs = fTableau.Eliminate(co); + // cs is solved form constraint index + + if (hintIx >= 0) { + fTableau.fPivotHints.resize(0); + fTableau.fPivotHints.push_back(hintIx); + } + + if (cs == QcTableau::fInvalidConstraintIndex) { + fInconsistant.push_back(c); + fEditVarsSetup = false; + return false; + } + + if (fBatchAddConst) { + // Check if it has unrestricted variables. + QcTableauRowIterator varCoeffs(fTableau, cs); + + while (!varCoeffs.AtEnd()) { + if (!fTableau.IsSlack (varCoeffs.getIndex())) + break; + varCoeffs.Increment(); + } + + // If there is, then do the normal add constraint. + if (!varCoeffs.AtEnd()) { + /* TODO: It's not clear that the "hintIx < 0 || " part + is deliberate. */ + if (hintIx < 0 || !fTableau.IsRedundant(cs)) { + success = ApplyHints(cs); + if (!success) + fTableau.DeleteRow(co); + } + } else { + // If the constraint has a new slack variable. + if (c.Operator() != QcConstraintRep::coEQ) { + numT rhs = fTableau.GetRHS(cs); + numT value = fTableau.GetValue(cs, fTableau.GetColumns() - 1); + + if (QcUtility::IsNegative(value) + ? !QcUtility::IsPositive(rhs) + : !QcUtility::IsNegative(rhs)) { + fTableau.Pivot(cs, fTableau.GetColumns() - 1); + // Should consider just setting the state of the + // row and column instead of calling Pivot. This + // is because we know the variable to be make + // basic is not in any other rows. + } else { + int vi = fTableau.AddArtificial( + QcUtility::IsPositive(rhs) ? 1.0 : -1.0); + fArtVars.push_back(vi); + fTableau.Pivot(cs, vi); + // May scale row by -1 to make the newly added + // artifical variable to +1. This method may + // require explicit management of column and row + // state. + } + } + } + + if (success) { + fOCBiMap.Update(c, co); + fBatchConstraints.push_back(c); + } else + fBatchAddConstFail = true; + } else { + if (!fTableau.IsRedundant(cs)) { + success = ApplyHints(cs); + if (!success) + fTableau.DeleteRow(co); + } + + if (success) + fOCBiMap.Update(c, co); + } + + fEditVarsSetup = false; + return success; +} + +bool QcLinInEqSystem::AddInEq(QcConstraint &c) +{ + bool success = true; + + #ifdef qcSafetyChecks + if (c.Operator() == QcConstraintRep::coEQ) + throw QcWarning("QcLinInEqSystem::AddInEq supplied with an equation"); + #endif + + int co = AddToTableau(c); + + if (co < 0) + return false; + + int cs = fTableau.Eliminate(co); // cs is solved form constraint index + + if (cs == QcTableau::fInvalidConstraintIndex) { + fInconsistant.push_back(c); + success = false; + } else if (!fTableau.IsRedundant(cs)) { // Pivot on new slack variable + success = fTableau.Pivot(cs, fTableau.GetColumns() - 1); + + // Should get the slack var index returned from AddToTableau + // rather than just knowing how it is implemented. + if (!success) + fTableau.DeleteRow(co); + } + + if (success) + fOCBiMap.Update(c, co); + + fEditVarsSetup = false; + return success; +} + +bool QcLinInEqSystem::ApplyHints(int cs) +{ + bool pivoted = false; + + if (cs < 0 || cs >= fTableau.GetRows() || fTableau.IsRedundant(cs)) + throw QcWarning("ApplyHints called for invalid constraint", + cs, fTableau.GetRows() - 1); + else { + for (unsigned int i = 0; i < fTableau.fPivotHints.size() && !pivoted; i++) { + int hint = fTableau.fPivotHints[i]; + if (!fTableau.IsConstrained(hint)) + pivoted = fTableau.Pivot(cs, hint); + } + + vector slackCoeffs; + + // If PivotHints failed, this means all the pivot hints variables + // have zero coeffs or are constrained (slack). + // Now try all the rest of the parametric variables with non-zero + // coeffs in the solved form constraint. First try non-slack + // variables, saving the indices of any slack parameters for later use. + if (!pivoted) + { +#ifdef qcUseSafeIterator + { + QcDenseTableauRowIterator varCoeffs(fTableau, cs); + + while (!varCoeffs.AtEnd() && !pivoted) + { + if (!fTableau.IsBasic(varCoeffs.getIndex())) { + if (fTableau.IsConstrained(varCoeffs.getIndex())) + slackCoeffs.push_back( + QcSparseCoeff(varCoeffs.getValue(), varCoeffs.getIndex())); + else + pivoted = fTableau.Pivot(cs, varCoeffs.getIndex()); + } + varCoeffs.Increment(); + } + } +#else + // Cache tableau column coefficients since it is possible that + // the iterator may be invalidated during iteration. + { + QcTableauRowIterator varCoeffs(fTableau, cs); + vector coeffCache; + + while (!varCoeffs.AtEnd()) + { + coeffCache.push_back( QcSparseCoeff( varCoeffs.getValue(), + varCoeffs.getIndex())); + varCoeffs.Increment(); + } + + for (vector::iterator cIt = coeffCache.begin(); + (cIt != coeffCache.end()) && !pivoted; + cIt++) + { + QcSparseCoeff &coeff = (*cIt); + unsigned const coeff_ix = coeff.getIndex(); + + if (!fTableau.IsBasic( coeff_ix)) + { + if (fTableau.IsConstrained( coeff_ix)) + slackCoeffs.push_back( QcSparseCoeff( coeff.getValue(), coeff_ix)); + else + pivoted = fTableau.Pivot( cs, coeff_ix); + } + } + } +#endif + } + + if (!pivoted) + { // try the new slack variable + numT rhs = fTableau.GetRHS(cs); + qcAssert(slackCoeffs.size() != 0); + QcSparseCoeff &s = slackCoeffs.back(); + slackCoeffs.pop_back(); + + if (s.getIndex() == fTableau.getNColumns() - 1) + { // new slack belongs to cs + qcAssert( QcUtility::IsOne( fabs( s.getValue()))); + + if (QcUtility::IsNegative( s.getValue()) + ? !QcUtility::IsPositive( rhs) + : !QcUtility::IsNegative( rhs)) + { + pivoted = fTableau.Pivot( cs, s.getIndex()); + qcAssert(pivoted); + } + } + + // Call SimplexI here as have rhs and new slack is popped off. + if (!pivoted) + pivoted = SimplexI(cs); + } + } + + return pivoted; +} + +/** Does first part of addConstraint, calling the correct tableau + function. + + @return fTableau.add* + @precondition c is non-null, and has a valid relation (eq, le, ge). + @postcondition ret ≥ 0 +**/ +int QcLinInEqSystem::AddToTableau(QcConstraint &c) +{ + int co; + QcRowAdaptor ra(c.LinPoly(), fVBiMap, fTableau); + + switch (c.Operator()) { + case QcConstraintRep::coEQ: + co = fTableau.AddEq(ra, c.RHS()); + goto out; + + case QcConstraintRep::coLE: + co = fTableau.AddLtEq(ra, c.RHS()); + /* TODO: Consider making this a QcFixedFloat. + (Similarly below.) */ + fVBiMap.Update( + QcFloat("", 0.0, 0.0, 0.0, true), fTableau.GetColumns() - 1); + goto out; + + case QcConstraintRep::coGE: + co = fTableau.AddGtEq(ra, c.RHS()); + fVBiMap.Update( + QcFloat("", 0.0, 0.0, 0.0, true), fTableau.GetColumns() - 1); + goto out; + + default: + throw QcWarning("AddConstraint: invalid constraint operator"); + abort(); + } + + out: + qcAssertPost( co >= 0); + return co; +} + +void QcLinInEqSystem::BeginEdit() + // This is the same as LinEqSystem::BeginEdit except where noted with the + // comment ++++. +{ + vector::iterator voiIt; + + #ifdef qcSafetyChecks + qcAssert(fTableau.IsBasicFeasibleSolved()); // ++++ + #endif + + // build a version of fEditVars by index. + vector::iterator viIt, viIt2; + fVarsByIndex.resize(0); + + for (voiIt = fEditVars.begin(); voiIt != fEditVars.end(); ++voiIt) + if (IsRegistered(*voiIt)) + fVarsByIndex.push_back(fVBiMap.Index(*voiIt)); + + // try to make all variables of interest into parameters. + // but not at the expense of creating a new restricted row. + for (viIt = fVarsByIndex.begin(); viIt != fVarsByIndex.end(); ++viIt) { + int vi = *viIt; + if (fTableau.IsBasic(vi)) { + int ci = fTableau.IsBasicIn(vi); + + #ifdef qcUseSafeIterator + { + QcDenseTableauRowIterator varCoeffs(fTableau, ci); + + while (!varCoeffs.AtEnd()) { + bool reject = fTableau.IsConstrained(varCoeffs.getIndex()); // ++++ + + for (viIt2 = fVarsByIndex.begin(); + viIt2 != fVarsByIndex.end(); ++viIt2) + if (varCoeffs.getIndex() == *viIt2) + reject = true; + + if (!reject) { + #ifdef qcSafetyChecks + qcAssert(fTableau.IsBasic(vi)); + qcAssert(fTableau.GetBasicVar(ci) == vi); + qcAssert(!fTableau.IsBasic(varCoeffs.getIndex())); + qcAssert(fVBiMap.Identifier(varCoeffs.getIndex()) != *voiIt); + #endif + #ifdef qcSafetyChecks + bool pivoted = fTableau.Pivot(ci, varCoeffs.getIndex()); + qcAssert(pivoted); + #else + fTableau.Pivot(ci, varCoeffs.getIndex()); + #endif + break; + } + varCoeffs.Increment(); + } + } + #else + // Cache tableau column coefficients since it is possible that + // the iterator may be invalidated during iteration. + { + QcTableauRowIterator varCoeffs(fTableau, ci); + vector coeffCache; + + while (!varCoeffs.AtEnd()) + { + coeffCache.push_back( QcSparseCoeff( varCoeffs.getValue(), + varCoeffs.getIndex())); + varCoeffs.Increment(); + } + + for (vector::iterator cIt = coeffCache.begin(); + cIt != coeffCache.end(); + cIt++) + { + QcSparseCoeff const &coeff = (*cIt); + unsigned const coeff_ix = coeff.getIndex(); + + bool reject = fTableau.IsConstrained( coeff_ix); // ++++ + for (viIt2 = fVarsByIndex.begin(); + !reject && (viIt2 != fVarsByIndex.end()); + ++viIt2) + if (coeff_ix == *viIt2) + reject = true; + + if (!reject) + { + qcAssert( fTableau.IsBasic( vi)); + qcAssert( fTableau.GetBasicVar( ci) == vi); + qcAssert( !fTableau.IsBasic( coeff_ix)); + qcAssert( fVBiMap.Identifier( coeff_ix) != *voiIt); + dbg(bool pivoted =) + fTableau.Pivot(ci, coeff_ix); + assert( pivoted); + break; + } + } + } + #endif + } + } + + Solve(); // Compute new solution here. + + // setup fParsOfInterest + fParsOfInterest.resize(0); + + for (viIt = fVarsByIndex.begin(); viIt != fVarsByIndex.end(); ++viIt) + if (!fTableau.IsBasic(*viIt) && !IsParOfInterest(*viIt)) + fParsOfInterest.push_back(*viIt); + + // setup fDepVars + fDepVars.resize(0); + + // setup fDepVarCoeffs + // extend fDepVarCoeffs so 0..fTableau.GetColumns()-1 are legal indices. + fDepVarCoeffs.resize(fTableau.GetColumns()); + fDepVarBaseVals.resize(fTableau.GetColumns()); + + for (unsigned int i = 0; i < fDepVarCoeffs.size(); i++) + fDepVarCoeffs[i].resize(0); + + QcBasicVarIndexIterator bvIt(fTableau); + while (!bvIt.AtEnd()) { + unsigned bvi = bvIt.getIndex(); + qcAssert(fTableau.IsBasic(bvi)); + unsigned ci = bvIt.getConstraintBasicIn(); + numT rhs = fTableau.GetRHS (ci); + fDepVarBaseVals[bvi] = rhs; + QcTableauRowIterator varCoeffs(fTableau, ci); + while (!varCoeffs.AtEnd()) { + /* TODO: This code occurs elsewhere too (minus the dodgy formatting). + See if it can be merged to a routine. */ + if (IsParOfInterest (varCoeffs.getIndex())) { + if (!IsDepVar(bvi)) fDepVars.push_back(bvi); + fDepVarCoeffs[bvi].push_back( + QcSparseCoeff (varCoeffs.getValue(), + varCoeffs.getIndex())); + } else if (bvi != varCoeffs.getIndex()) { + if (fTableau.IsStructural (varCoeffs.getIndex())) { // ++++ + numT val = fVBiMap.Identifier (varCoeffs.getIndex()).Value(); + fDepVarBaseVals[bvIt.getIndex()] -= val * varCoeffs.getValue(); + } + } + varCoeffs.Increment(); + } + bvIt.Increment(); + } + + fEditVarsSetup = true; +} + +bool QcLinInEqSystem::DualSimplexII() +{ + int n = 1; + + #ifdef qcSafetyChecks + qcAssert(fTableau.IsBasicOptimalSolved()); + unsigned nRestrictedRows = fTableau.getNRestrictedRows(); + qcAssert( nRestrictedRows != 0); + #endif + + // This loop contains 2 exits, a "return true" and a "return false". + while (true) { + #ifdef qcSafetyChecks + qcAssert(nRestrictedRows == fTableau.getNRestrictedRows()); + + for (int vi = 0; vi < fTableau.GetColumns(); vi++) + if (fTableau.GetObjValue(vi) != 0.0) { + qcAssert(!fTableau.IsBasic(vi)); + qcAssert(fTableau.IsConstrained(vi)); + } + + qcAssert(fTableau.IsBasicOptimalSolved()); + + if (n == 1000) + throw QcWarning( + "QcLinInEqSystem::DualSimplexII appears to be cycling"); + #endif + + // May be better than inf loop + if (++n == qcMaxLoopCycles) + return false; + + // Find pivot row. + int ei = SelectDualExitVar(); + + // Feasible + if (ei < 0) + return true; + + #ifdef qcSafetyChecks + qcAssert(fTableau.IsConstrained(fTableau.GetBasicVar(ei))); + #endif + + // Select parameter to make basic + int vi = SelectDualEntryVar(ei); + + if (vi < 0) + return false; + + // Do a full pivot for the now. Later we may choose to implement a + // slack pivot which only eliminates the new basic slack variable + // from the restricted portion of the tableau. This would violate + // some of the integrity constraints for lineqtableau - so more + // thought is needed first (maybe use two separate tableaus). + fEditVarsSetup = false; // for when called by Resolve + fTableau.SimplexPivot(ei, vi); + } +} + +bool QcLinInEqSystem::EndAddConstraint() +{ + QcSolver::EndAddConstraint(); + + if (fBatchAddConstFail) + return false; + + if (fArtVars.size() == 0) + return true; + + // Set objective function based on the added artifical + // variables, and perform Simplex phase II. + + // First, initialize the objective function. + for (unsigned c = 0; c < fTableau.getNColumns(); c++) + fTableau.SetObjValue (c, 0.0); + + // Then, set the objective function base on the artifical + // variables. + vector::iterator aIt = fArtVars.begin(); + + while (aIt != fArtVars.end()) { + QcFloat &v = fVBiMap.Identifier(*aIt); + fTableau.SetObjValue((*aIt), v.Weight()); + aIt++; + } + + fTableau.EliminateObjective(); + SimplexII(); + + // Remove the added artifical variables from the tableau. + aIt = fArtVars.begin(); + + while (aIt != fArtVars.end()) { + unsigned vi = (*aIt); + + if (!fTableau.IsBasic(vi)) + fTableau.RemoveVarix( vi); + else { + int r = fTableau.IsBasicIn (vi); + int maxcol = -1; + { + numT max = QcUtility::qcMaxZeroVal; + QcTableauRowIterator iR (fTableau, r); + + while (!iR.AtEnd()) + { + numT absVal = fabs (iR.getValue()); + if ((max < absVal) + && (iR.getIndex() != vi)) + { + max = absVal; + maxcol = iR.getIndex(); + assert (maxcol >= 0); + } + + iR.Increment(); + } + } + + // If there is at least one non-zero coefficient in the + // current column. + if (maxcol != -1) { + fTableau.Pivot(r, maxcol); + fTableau.RemoveVarix( vi); + } else { + if (QcUtility::IsZero(fTableau.GetRHS(r))) { + fTableau.SetRowCondition(r, QcLinEqRowState::fRedundant); + fTableau.RemoveVarix( vi); + } else { + fTableau.SetRowCondition(r, QcLinEqRowState::fInvalid); + } + } + } + aIt++; + } + return true; +} + +void QcLinInEqSystem::EqSolve() +{ + #ifdef qcSafetyChecks + if (!fTableau.IsBasicFeasibleSolved()) + throw QcWarning(qcPlace, + "tableau is not in basic feasible solved form"); + #endif + + // The following loop is equiavalent to LinEqSystem::LoadDesValCache() + // N.B. QcLinEqTableau::EvalBasicVar needs caching of non-structural + // variables hence QcLinInEqSystem::LoadDesValCache() will not do. + QcVariableIndexIterator vIt(fTableau); + + while (!vIt.AtEnd()) { + unsigned vi = vIt.getIndex(); + fTableau.SetDesireValue(vi, + fVBiMap.Identifier(vi).DesireValue()); + vIt.Increment(); + } + + vIt.Reset(); + + while (!vIt.AtEnd()) { + unsigned vi = vIt.getIndex(); + QcFloat &v = fVBiMap.Identifier(vi); + + if (fTableau.IsBasic(vi)) { + numT value = fTableau.QcLinEqTableau::EvalBasicVar(vi); + v.SetValue(QcUtility::Zeroise(value)); + } else + v.SetVariable(); + + vIt.Increment(); + } +} + +void QcLinInEqSystem::InitObjective() +{ + // Build objective function SIGMA(x.weight * x) for structural + // variables x. Replace basic variables by their parametric + // representation but don't include any non-slack parameters. + QcStructVarIndexIterator vIt (fTableau); + while (!vIt.AtEnd()) + { + unsigned vi = vIt.getIndex(); + // TODO: The Java version has an isStructural test as well as isBasic. + if (fTableau.IsBasic (vi)) + { + QcFloat &v = fVBiMap.Identifier (vi); + fTableau.SetObjValue (vi, v.Weight()); + } + else + fTableau.SetObjValue (vi, 0.0); + vIt.Increment(); + } + + fTableau.EliminateObjective(); + +#ifdef qcSafetyChecks + for (unsigned i = 0; i < fTableau.getNColumns(); i++) + if (fTableau.GetObjValue (i) != 0.0) + { + qcAssert (!fTableau.IsBasic (i)); + qcAssert (fTableau.IsConstrained (i)); + } +#endif +} + +void QcLinInEqSystem::LoadDesValCache() +{ + QcStructVarIndexIterator vIt (fTableau); + while (!vIt.AtEnd()) + { + unsigned vi = vIt.getIndex(); + fTableau.SetDesireValue (vi, fVBiMap.Identifier(vi).DesireValue()); + vIt.Increment(); + } +} + +void QcLinInEqSystem::RawSolve() +{ + #ifdef qcSafetyChecks + if (!fTableau.IsBasicFeasibleSolved()) + throw QcWarning(qcPlace, + "tableau is not in basic feasible solved form"); + #endif + + LoadDesValCache(); + QcStructVarIndexIterator vIt(fTableau); + + while (!vIt.AtEnd()) { + unsigned vi = vIt.getIndex(); + QcFloat &v = fVBiMap.Identifier(vi); + + if (fTableau.IsBasic(vi)) { + numT value = fTableau.EvalBasicVar(vi); + v.SetValue(QcUtility::Zeroise(value)); + } else + v.SetVariable(); + vIt.Increment(); + } +} + +bool QcLinInEqSystem::Reset() +{ + bool result = true; + + // Record the columns of the previous basic variables so to make them + // basic after this Reset() method. + bool *rbasic = new bool[fTableau.GetColumns()]; + bool *urbasic = new bool[fTableau.GetColumns()]; + + for (int c = 0; c < fTableau.GetColumns(); c++) { + if (fTableau.IsBasic(c)) { + if (fTableau.IsSlack(c)) { + rbasic[c] = true; + urbasic[c] = false; + } else { + rbasic[c] = false; + urbasic[c] = true; + } + } else { + rbasic[c] = false; + urbasic[c] = false; + } + } + + fEditVarsSetup = false; + fTableau.Restore(); // Reset variable state information + + // Establish solved form and quasi-inverse from original constraints. + // Step 1: Pivot using unrestricted variables. + for (int c = 0; c < fTableau.GetColumns(); c++) { + if (urbasic[c]) { + int maxrow = -1; + { + /* TODO: This code (or similar) appears very often. + Find the cousins and merge them into a single routine. */ + numT max = QcUtility::qcMaxZeroVal; + QcTableauColIterator iC (fTableau, c); + + while (!iC.AtEnd()) + { + numT absVal = fabs (iC.getValue()); + if (max < absVal) + { + max = absVal; + maxrow = iC.getIndex(); + assert (maxrow >= 0); + } + + iC.Increment(); + } + } + + // If there is at least one non-zero coefficient in the current + // column. + if (maxrow != -1) + fTableau.Pivot(maxrow, c); + } + } + + // Step 2: Make sure that all solved form constraints with unrestricted + // variables are assigned a basic variable. + for (int r = 0; r < fTableau.GetRows(); r++) { + if (fTableau.GetRowCondition(r) != QcLinEqRowState::fRegular) { + QcTableauRowIterator iR(fTableau, r); + + if (iR.AtEnd()) + { + /* Verify that the Reset operation is successful. + It fails if one of more of the solved form row is + marked as "invalid". */ + if (QcUtility::IsZero(fTableau.GetRHS(r))) + fTableau.SetRowCondition(r, QcLinEqRowState::fRedundant); + else + { + fTableau.SetRowCondition(r, QcLinEqRowState::fInvalid); + result = false; + } + } + else + { + int maxcol = -1; + { + numT max = QcUtility::qcMaxZeroVal; + assert (!iR.AtEnd()); + do + { + if (!fTableau.IsSlack (iR.getIndex())) + { + numT absVal = fabs (iR.getValue()); + if (max < absVal) + { + max = absVal; + maxcol = iR.getIndex(); + assert (maxcol >= 0); + } + } + + iR.Increment(); + } + while (!iR.AtEnd()); + } + + /* If there is at least one non-zero coefficient in + the current row. */ + if (maxcol != -1) + fTableau.Pivot(r, maxcol); + } + } + } + + // Step 3: Pivot using restricted variables. + for (int c = 0; c < fTableau.GetColumns(); c++) { + if (rbasic[c]) { + int maxrow = -1; + { + numT max = QcUtility::qcMaxZeroVal; + QcTableauColIterator iC (fTableau, c); + + while (!iC.AtEnd()) + { + numT absVal = fabs (iC.getValue()); + if (max < absVal) + { + max = absVal; + maxrow = iC.getIndex(); + assert (maxrow >= 0); + } + + iC.Increment(); + } + } + + // If there is at least one non-zero coefficient in the current + // column. + if (maxrow != -1) + fTableau.Pivot(maxrow, c); + } + } + + // Step 4: Pivot on any variables to make all the solved form rows with + // a basic variables. + for (unsigned r = 0; r < fTableau.getNRows(); r++) + { + if (fTableau.GetRowCondition (r) == QcLinEqRowState::fRegular) + continue; + + int maxcol = -1; + { + numT max = QcUtility::qcMaxZeroVal; + QcTableauRowIterator iR (fTableau, r); + while (!iR.AtEnd()) + { + numT absVal = fabs (iR.getValue()); + if (max < absVal) + { + max = absVal; + maxcol = iR.getIndex(); + assert (maxcol >= 0); + } + iR.Increment(); + } + } + + // If there is at least one non-zero coefficient in the current + // row. + if (maxcol != -1) + fTableau.Pivot (r, maxcol); + else + { + /* Verify that the Reset operation is successful. It fails if + one of more of the solved form row is marked as "invalid". */ + if (QcUtility::IsZero (fTableau.GetRHS (r))) + fTableau.SetRowCondition (r, QcLinEqRowState::fRedundant); + else + { + fTableau.SetRowCondition (r, QcLinEqRowState::fInvalid); + result = false; + } + } + } + + // Step 5: For each restricted rows with negative RHS, add an artifical + // variable with -1 coefficient. This is followed by doing a pivot on it. + vector artVars; + bool moreProcess = false; + + for (unsigned r = 0; r < fTableau.getNRows(); r++) + { + if (fTableau.IsRestricted (r) + && QcUtility::IsNegative (fTableau.GetRHS (r))) + { + int vi = fTableau.AddArtificial (-1.0); + assert (vi >= 0); + artVars.push_back (vi); + fTableau.Pivot (r, vi); + // May scale row by -1 to make the newly added artifical + // variable to +1. This method may require explicit + // management of column and row state. + moreProcess = true; + } + } + + if (!moreProcess) + return result; + + // Step 6: Set objective function based on the added artifical variables, + // and perform Simplex phase II. + + // First, initialize the objective function. + for (unsigned c = 0; c < fTableau.getNColumns(); c++) + fTableau.SetObjValue (c, 0.0); + + // Then, set the objective function base on the artifical variables. + vector::iterator aIt = artVars.begin(); + + while (aIt != artVars.end()) { + QcFloat &v = fVBiMap.Identifier(*aIt); + fTableau.SetObjValue((*aIt), v.Weight()); + aIt++; + } + + fTableau.EliminateObjective(); + SimplexII(); + + // Step 7: Remove the added artifical variables from the tableau. + aIt = artVars.begin(); + + while (aIt != artVars.end()) { + unsigned vi = (*aIt); + + if (!fTableau.IsBasic(vi)) + fTableau.RemoveVarix( vi); + else { + int maxcol = -1; + unsigned r = fTableau.IsBasicIn(vi); + { + numT max = QcUtility::qcMaxZeroVal; + QcTableauRowIterator iR (fTableau, r); + + while (!iR.AtEnd()) + { + numT absVal = fabs (iR.getValue()); + unsigned ix = iR.getIndex(); + if ((max < absVal) + && (ix != vi)) + { + max = absVal; + maxcol = ix; + assert (maxcol >= 0); + } + + iR.Increment(); + } + } + + // If there is at least one non-zero coefficient in the current + // column. + if (maxcol != -1) { + fTableau.Pivot(r, maxcol); + fTableau.RemoveVarix( vi); + } else { + if (QcUtility::IsZero(fTableau.GetRHS(r))) { + fTableau.SetRowCondition(r, QcLinEqRowState::fRedundant); + fTableau.RemoveVarix( vi); + } else { + fTableau.SetRowCondition(r, QcLinEqRowState::fInvalid); + result = false; + } + } + } + aIt++; + } + + delete [] rbasic; // no longer needed. + delete [] urbasic; // no longer needed. + + return result; +} + + +void QcLinInEqSystem::Resolve() + // This is the same as LinEqSystem::Resolve except where noted with the + // comment ++++. +{ + if (!fEditVarsSetup) + BeginEdit(); + +#ifdef qcSafetyChecks + if (!fTableau.IsBasicFeasibleSolved()) + throw QcWarning("QcLinInEqSystem::Resolve: tableau is not in basic feasible solved form"); +#endif + + // This paragraph not in LinEqSystem::Resolve ++++ + if (fTableau.getNRestrictedRows() != 0) + { + // Perform second phase of revised simplex algorithm on restricted + // portion of the tableau. + InitObjective(); + + if (SimplexII()) + qcAssert( fTableau.IsBasicOptimal()); + } + + // Adjust the dependent basic variables. + for (vector::iterator vIt = fDepVars.begin(); + vIt != fDepVars.end(); + ++vIt) + { + QcFloatRep *dvr = fVBiMap.getIdentifierPtr( *vIt); + qcAssert( fTableau.IsBasic( *vIt)); + vector &Coeffs = fDepVarCoeffs[*vIt]; + numT dvValue = fDepVarBaseVals[*vIt]; + + for (vector::iterator pIt = Coeffs.begin(); + pIt != Coeffs.end(); + ++pIt) + { + QcFloatRep const *pr = fVBiMap.getIdentifierPtr( pIt->getIndex()); + dvValue -= (*pIt).getValue() * pr->DesireValue(); + } + + dvr->SetValue( QcUtility::Zeroise( dvValue)); + } + + // Adjust the parameters of interest. + for (vector::iterator vIt = fParsOfInterest.begin(); + vIt != fParsOfInterest.end(); + ++vIt) + fVBiMap.getIdentifierPtr( *vIt)->SetToGoal(); +} + + +void QcLinInEqSystem::RestSolver() +{ + QcStructVarIndexIterator vIt(fTableau); + + while (!vIt.AtEnd()) { + fVBiMap.Identifier(vIt.getIndex()).RestVariable(); + vIt.Increment(); + } +} + +int QcLinInEqSystem::SelectEntryVar() + // Returns parameter for SimplexII to make basic. + // Or returns qcInvalidVIndex if there are no candidates. + // Any constrained parameter with negative objective coefficient will + // do. But to implement Bland's anti-cycling rule, we choose the + // parameter with the lowest index. +{ + QcParamVarIndexIterator vIt(fTableau); + + while (!vIt.AtEnd()) { + unsigned vi = vIt.getIndex(); + if (fTableau.IsConstrained(vi)) { + numT objCoeff = fTableau.GetObjValue(vi); + if (QcUtility::IsNegative(objCoeff)) + return vi; + } + vIt.Increment(); + } + + return QcTableau::fInvalidVariableIndex; +} + +int QcLinInEqSystem::SelectExitVar (unsigned vi) +{ + qcAssertPre (vi < fTableau.getNColumns()); + + int ei = QcTableau::fInvalidConstraintIndex; + numT minval = DBL_MAX; + int bi = fTableau.GetColumns(); // Bland Index + + #ifdef qcSafetyChecks + qcAssert(!fTableau.IsBasic(vi) && fTableau.IsConstrained(vi)); + #endif + + QcTableauColIterator colCoeffs (fTableau, vi); + while (!colCoeffs.AtEnd()) { + qcAssert (fTableau.GetBasicVar (colCoeffs.getIndex()) != (int) vi); + if (fTableau.IsRestricted (colCoeffs.getIndex())) { + numT rhs = fTableau.GetRHS (colCoeffs.getIndex()); + if (CannotIncrease (colCoeffs.getValue(), rhs)) { + numT coeff = rhs / colCoeffs.getValue(); + if ((coeff < minval) + || ((coeff == minval) + && (fTableau.GetBasicVar (colCoeffs.getIndex()) + < bi))) + { + minval = coeff; + ei = colCoeffs.getIndex(); + bi = fTableau.GetBasicVar (ei); + qcAssert (!QcUtility::IsNegative (minval)); + } + } + } + colCoeffs.Increment(); + } + + #ifdef qcSafetyChecks + qcAssert(fTableau.IsBasicFeasibleSolved()); + if (ei < 0) + throw QcWarning("SelectExitVar: No suitable variable"); + #endif + + return ei; +} + +int QcLinInEqSystem::SelectDualEntryVar(int ei) +{ + int vi = QcTableau::fInvalidVariableIndex; + numT maxval = -DBL_MAX; + + qcAssert(fTableau.IsRestricted(ei)); + + QcTableauRowIterator varCoeffs(fTableau,ei); + + while (!varCoeffs.AtEnd()) { + if (fTableau.IsConstrained (varCoeffs.getIndex())) { + if (QcUtility::IsNegative(varCoeffs.getValue())) { + numT coeff = (fTableau.GetObjValue (varCoeffs.getIndex()) + / varCoeffs.getValue()); + if (coeff > maxval) { + maxval = coeff; + vi = varCoeffs.getIndex(); + } + } + } + varCoeffs.Increment(); + } + + #ifdef qcSafetyChecks + if (vi == QcTableau::fInvalidVariableIndex) + throw QcWarning("SelectDualEntryVar: No suitable variable"); + #endif + + return vi; +} + +int QcLinInEqSystem::SelectDualExitVar() + // Select the basic variable to leave the basis so that optimality + // is maintained (in the narrow sense - feasibility is not assumed). + // And feasibility is approached. + // Returns qcInvalidCIndex if no such pivot is possible (i.e. optimal feasible). +{ + numT minval = 0.0; + int ei = QcTableau::fInvalidConstraintIndex; // Result constraint index + + // Find the the constrainted basic with the most negative value. + QcBasicVarIndexIterator bvIt(fTableau); + while (!bvIt.AtEnd()) { + unsigned bvi = bvIt.getIndex(); + if (fTableau.IsConstrained(bvi)) { + int ci = fTableau.IsBasicIn(bvi); + numT rhs = fTableau.GetRHS(ci); + + if (QcUtility::IsNegative(rhs) && (rhs < minval)) { + minval = rhs; + ei = ci; + } + } + bvIt.Increment(); + } + + qcAssert(fTableau.IsBasicOptimalSolved()); + return ei; +} + +bool QcLinInEqSystem::SimplexI (unsigned cs) +{ + qcAssertPre (cs < fTableau.getNRows()); + + unsigned nIterationsDone = 0; + unsigned ei; + fTableau.Normalize (cs); + + do + { + numT rhs = fTableau.GetRHS (cs); + + // May be better than inf loop + if (nIterationsDone++ == qcMaxLoopCycles) + { +#ifdef qcSafetyChecks + throw QcWarning( + "QcLinInEqSystem::SimplexI appears to be cycling"); +#endif + return false; + } + + // Find parameter to make basic (any with positive coefficient) + unsigned vi; // Index of variable to become basic. + numT val; + bool found = false; + for (QcTableauRowIterator varCoeffs (fTableau, cs); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + vi = varCoeffs.getIndex(); + val = varCoeffs.getValue(); + + if (!fTableau.IsBasic (vi) + && fTableau.IsConstrained (vi) + && QcUtility::IsPositive (val)) + { + found = true; + break; + } + } + + // New constraint is inconsistant. + if (!found) + return false; + + // Choose basic variable to make parametric (ei) + ei = cs; // The prefered row to choose from. + numT minval = rhs / val; + QcTableauColIterator colCoeffs(fTableau, vi); + while (!colCoeffs.AtEnd()) + { + numT rhs2 = fTableau.GetRHS (colCoeffs.getIndex()); + numT minval2 = rhs2 / colCoeffs.getValue(); + if (QcUtility::IsPositive (colCoeffs.getValue()) + && fTableau.IsRestricted (colCoeffs.getIndex()) + && ((minval2 < minval) + || ((minval2 == minval) + && (colCoeffs.getIndex() != cs) + && (fTableau.GetBasicVar (colCoeffs.getIndex()) + < fTableau.GetBasicVar (ei))))) + { + minval = minval2; + ei = colCoeffs.getIndex(); + } + colCoeffs.Increment(); + } + +#ifdef qcSafetyChecks + bool pivoted = +#endif + fTableau.Pivot (ei, vi); + qcAssert (pivoted); + } + while (ei != cs); + + qcAssert (fTableau.IsBasicFeasibleSolved()); + return true; +} + +bool QcLinInEqSystem::SimplexII() + // Perform simplex optimisation on the restricted rows of the tableau. + // Should only be called if there are some restricted rows. + // The objective function should be initialised before this call. + // Bland's anti-cycling rule is implemented and depends upon tableau + // column iterators providing coeffs in order of increasing + // variable index. +{ + int n = 1; + + /* FIXME: These "safety checks" can fail (e.g. TestCassSolver.cc line + 111, after AddConstraint), yet still produce the right answer (TODO: + actually, haven't checked this). + + In the abovementioned example, IsBasicFeasible fails. */ + #if qcSafetyChecks + qcAssert(fTableau.IsBasicFeasibleSolved()); + unsigned const nRestrictedRows = fTableau.getNRestrictedRows(); + qcAssert(nRestrictedRows != 0); + #endif + + // This loop contains 2 exits, a "return true" and a "return false". + while (true) { + #if 0 && qcSafetyChecks + qcAssert(nRestrictedRows == fTableau.getNRestrictedRows()); + + for (int vi=0; vi < fTableau.GetColumns(); vi++) + if (fTableau.GetObjValue(vi)!=0.0) { + qcAssert(!fTableau.IsBasic(vi)); + qcAssert(fTableau.IsConstrained(vi)); + } + + qcAssert(fTableau.IsBasicFeasibleSolved()); + + if (n == 1000) + throw QcWarning( + "QcLinInEqSystem::SimplexII appears to be cycling"); + #endif + + // may be better than inf loop + if (++n == qcMaxLoopCycles) + return false; + + // Find parameter to make basic. + int vi = SelectEntryVar(); + + // All objective coeffs are non-negative + if (vi < 0) + return true; + + // Choose row index of basic slack variable to make parametric (ei) + int ei = SelectExitVar(vi); + + if (ei < 0) + return false; + + #ifdef qcSafetyChecks + qcAssert(fTableau.IsConstrained(fTableau.GetBasicVar(ei))); + #endif + + // Do a full pivot for the now. Later we may choose to implement a + // slack pivot which only eliminates the new basic slack variable + // from the restricted portion of the tableau. This would violate + // some of the integrity constraints for lineqtableau - so more + // thought is needed first (maybe use two separate tableaus). + fEditVarsSetup = false; // for when called by Resolve + + #ifdef qcSafetyChecks + qcAssert(fTableau.SimplexPivot(ei, vi)); + #else + fTableau.SimplexPivot(ei, vi); + #endif + } +} + +void QcLinInEqSystem::Solve() +{ + #ifdef qcSafetyChecks + if (!fTableau.IsBasicFeasibleSolved()) + throw QcWarning( + "QcLinInEqSystem::Solve: tableau is not in basic feasible solved form"); + #endif + + if (fTableau.getNRestrictedRows() != 0) { + // Perform second phase of revised simplex algorithm on restricted + // portion of the tableau. + InitObjective(); + + if (SimplexII()) + qcAssert(fTableau.IsBasicOptimal()); + } + + qcAssert(fTableau.IsSolved()); + qcAssert(fTableau.IsBasicFeasible()); + + // Calculate the value for each variable depending upon + // whether it is basic or parametric. + RawSolve(); +} diff --git a/src/kits/interface/qoca/QcLinInEqSystem.hh b/src/kits/interface/qoca/QcLinInEqSystem.hh new file mode 100644 index 0000000000..dbb877ede7 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqSystem.hh @@ -0,0 +1,250 @@ +// $Id: QcLinInEqSystem.hh,v 1.9 2000/12/15 07:06:20 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcInEqSystemH +#define __QcInEqSystemH + +#include "qoca/QcDelLinEqSystem.hh" +#include "qoca/QcLinInEqTableau.hh" + +class QcLinInEqSystem : public QcDelLinEqSystem +{ +public: + QcLinInEqTableau &fTableau; + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcLinInEqSystem(); + QcLinInEqSystem(unsigned hintRows, unsigned hintCols); + QcLinInEqSystem(QcLinInEqTableau &tab); + + //-----------------------------------------------------------------------// + // Variable management methods (see QcSolver.java for descriptions) // + //-----------------------------------------------------------------------// + virtual bool RemoveVar(QcFloat &v); + virtual void RestSolver(); + + //-----------------------------------------------------------------------// + // High Level Edit Variable Interface for use by solver clients. // + //-----------------------------------------------------------------------// + virtual void BeginEdit(); + + //-----------------------------------------------------------------------// + // Constraint management methods // + //-----------------------------------------------------------------------// + virtual bool AddConstraint(QcConstraint &c); + // Extracts the various components and enters them in the tableau + // as well as updating the bimapnotifier for the tableau + // if successful. The return value indicates success or failure. + // If AddConstraint fails the state of the tableau is unchanged. + virtual bool AddConstraint(QcConstraint &c, QcFloat &hint); + virtual bool AddInEq(QcConstraint &c); + // Used for adding inequalities only. Always pivots on the new slack + // variable (hence making it basic). + virtual bool ApplyHints(int cs); + // This version of applyHints is similar to QcLinEqSystem::applyHints + // only it is aware of slack variables and calls SimplexI if none of + // the slack variables can be made basic with a single pivot. + // This is a convenience function to pivot an independent new + // solved form constraint according to the PivotHints. + virtual void BeginAddConstraint(); + // Marks the beginning of a batch of AddConstraint operation. + virtual bool EndAddConstraint(); + // Marks the end of a batch of AddConstraint operation. + virtual bool Reset(); + // While this routine is in progress the tableau is slowly + // rebuilt from row 0 forwards retaining the original constraint + // matrix fA. + // The implementation used here only relies on the rest + // of the tableau methods being able to cope with multiple + // undetermined constraints. + // Reset starts by calling Restore to establish a state equivalent + // to the original constraints having been all entered using AddEq + // and nothing else apart from the deleted entries being left alone. + virtual bool RemoveConstraint(QcConstraint &c); + + //-----------------------------------------------------------------------// + // Constraint Solving methods // + //-----------------------------------------------------------------------// + virtual void EqSolve(); + // Equivalent to QcLinEqSystem::Solve + virtual void Resolve(); + // This is the same as QcLinEqSystem::resolve. + virtual void Solve(); + +protected: + vector fArtVars; + + virtual int AddToTableau(QcConstraint &c); + // Does first part of addConstraint, calling the correct tableau + // function. + virtual void InitObjective(); + // Build objective function SIGMA(x.weight * x) for structural + // variables x. Replace basic variables by their parametric + // representation but don't include any non-slack parameters. + virtual void RawSolve(); + // Evaluate basic Variables from parameters + + //-----------------------------------------------------------------------// + // Advanced methods. // + //-----------------------------------------------------------------------// +public: + virtual bool DualSimplexII(); + // As for SimplexII only this algorithm uses the dual algorithm and + // needs an initially optimal (but infeasible) solution. + // Maintains optimality while searching for a feasible solution. + virtual int SelectEntryVar(); + // Returns parameter for SimplexII to make basic. + // Or returns invalid index if there are no candidates. + // Any constrained parameter with negative objective coefficient will + // do. But to implement Bland's anti-cycling rule, we choose the + // parameter with the lowest index. + + + /** Select the pivot row for pivot variable vi (slack parameter) + maintaining Basic Feasible Solved Form. + Returns fInvalidConstraintIndex if no such pivot is possible. + This version implement's Bland's anticycling rule. + Used by SimplexII, BeginEdit and in derived classes. + + @precondition vi < fTableau.getNColumns() + **/ + virtual int SelectExitVar (unsigned vi); + + virtual int SelectDualEntryVar(int ei); + // Select a slack parameter to enter the basis which will approach + // feasibility. Used by DualSimplexII. + virtual int SelectDualExitVar(); + // Select the basic variable to leave the basis so that optimality + // is maintained (in the narrow sense - feasibility is not assumed). + // And feasibility is approached. + // Returns InvalidCIndex if no such pivot is possible (i.e. optimal + // feasible). + virtual void SetObjective(QcLinPoly &obj); + // Simplex objective minimise function + + /** Uses the first phase of the revised simplex algorithm to obtain a + basic feasible solution for the new constraint with index + cs. Returns false only if the problem is not satisfiable + (or if it does an "unreasonable" number of iterations, + viz. qcMaxLoopCycles). SimplexI tries to + find a basic feasible solution when adding a new row to a tableau + previously in basic feasible form. It has not been possible to find + an unconstrained variable to make basic. Hence a restricted row is + being created. The slackCoeffs vector parameter does not include + the new slack variable, this has already been tried in Applyhints. + A precondition for this call is that the tableau is basic feasible + apart from the new row cs which is being added. + + @precondition cs < fTableau.getNRows() + **/ + virtual bool SimplexI (unsigned cs); + + virtual bool SimplexII(); + // Uses the second phase of the revised simplex algorithm to + // find a solution minimising the objecive function. + // Perform simplex optimisation on the restricted rows of the tableau. + // Should only be called if there are some restricted rows. + // The objective function should be initialised before this call. + // Bland's anti-cycling rule is implemented and depends upon tableau + // column iterators providing coeffs in order of increasing + // variable index. + +protected: + virtual void LoadDesValCache(); + // Used for Solve + + bool CannotIncrease(numT coeff, numT rhs); + // Used by SimplexI and applied to rhs = QcLinTableau::getRHS. + // The sign of coeff and rhs is critical hence the extra check. + +private: + bool doAddConstraint(QcConstraint &c, int hintIx); +}; + +inline QcLinInEqSystem::QcLinInEqSystem() + : QcDelLinEqSystem(*new QcLinInEqTableau(0, 0, *new QcBiMapNotifier())), + fTableau((QcLinInEqTableau &)QcDelLinEqSystem::fTableau) +{ +} + +inline QcLinInEqSystem::QcLinInEqSystem(unsigned hintRows, unsigned hintCols) + : QcDelLinEqSystem(*new QcLinInEqTableau(hintRows, hintCols, + *new QcBiMapNotifier())), + fTableau((QcLinInEqTableau &)QcDelLinEqSystem::fTableau) +{ +} + +inline QcLinInEqSystem::QcLinInEqSystem(QcLinInEqTableau &tab) + : QcDelLinEqSystem(tab), + fTableau(tab) +{ +} + +inline void QcLinInEqSystem::BeginAddConstraint() +{ + QcSolver::BeginAddConstraint(); + fArtVars.clear(); +} + +inline bool QcLinInEqSystem::CannotIncrease(numT coeff, numT rhs) + // Used by SimplexI and applied to rhs = LinTableau::GetRHS. + // The sign of coeff and rhs is critical hence the extra check +{ + qcAssert(!QcUtility::IsZero(coeff)); + + if (QcUtility::IsNearZero(coeff)) + return false; + + if (rhs < 0.0) + return (coeff < 0.0); + // rhs is zeroised already, otherwise use `if qcIsNeg(rhs)' + else + return (coeff > 0.0); +} + +inline bool QcLinInEqSystem::RemoveVar(QcFloat &v) +{ + UNUSED(v); + throw QcWarning("Error: Should not call QcLinInEqSystem::RemoveVar"); + return false; +} + +inline bool QcLinInEqSystem::RemoveConstraint(QcConstraint &c) +{ + UNUSED(c); + throw QcWarning("Error: Should not call QcLinInEqSystem::removeConstraint"); + return false; +} + +inline void QcLinInEqSystem::SetObjective(QcLinPoly &obj) +{ + QcRowAdaptor objIt(obj, fVBiMap, fTableau); + fTableau.SetObjective(objIt); +} + +#endif /* !__QcInEqSystemH */ diff --git a/src/kits/interface/qoca/QcLinInEqTableau.cc b/src/kits/interface/qoca/QcLinInEqTableau.cc new file mode 100644 index 0000000000..ab3ffbb2d2 --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqTableau.cc @@ -0,0 +1,278 @@ +// $Id: QcLinInEqTableau.cc,v 1.10 2001/01/04 05:20:11 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include +#include "qoca/QcDefines.hh" +#include "qoca/QcLinInEqTableau.hh" +#include "qoca/QcConstraintIndexIterator.hh" +#include "qoca/QcBasicVarIndexIterator.hh" +#include "qoca/QcParamVarIndexIterator.hh" +#include "qoca/QcVariableIndexIterator.hh" +#include "qoca/QcTableauRowIterator.hh" + +int QcLinInEqTableau::AddArtificial(numT coeff) +{ + unsigned vi = IncreaseColumns(); + SetColCondition (vi, QcLinInEqColState::fArtificial); + SetConstrained (vi, true); + QcConstraintIndexIterator cIt (*this); + + while (!cIt.AtEnd()) { + unsigned ci = cIt.getIndex(); + fCoreTableau->fSF.SetValue (ci, vi, coeff); + cIt.Increment(); + } + return vi; +} + +int QcLinInEqTableau::AddGtEq(QcRowAdaptor &varCoeffs, numT rhs) +{ + unsigned r = AddEq(varCoeffs, rhs); + + // Add new slack variable with coeff -1.0 + unsigned vi = AddSlack(); +#ifdef qcRealTableauCoeff + fCoreTableau->fSF.SetValue(r, vi, -1.0); +#endif + + qcAssertPost( (int) vi >= 0); + qcAssertPost( vi == getNColumns() - 1); + qcAssertPost( r < getNRows()); + return r; +} + +int QcLinInEqTableau::AddLtEq(QcRowAdaptor &varCoeffs, numT rhs) +{ + int r = AddEq( varCoeffs, rhs); + + // Add new slack variable with coeff 1.0. + unsigned vi = AddSlack(); +#ifdef qcRealTableauCoeff + fCoreTableau->fSF.SetValue(r, vi, 1.0); +#endif + + qcAssertPost( int( vi) >= 0); + qcAssertPost( vi == getNColumns() - 1); + qcAssertPost( unsigned( r) < getNRows()); + return r; +} + +unsigned QcLinInEqTableau::AddSlack() +{ + unsigned vi = NewVariable(); + SetColCondition( vi, (QcLinInEqColState::fSlack + | QcLinInEqColState::fStructural)); + SetConstrained( vi, true); + + qcAssertPost( (int) vi >= 0); + qcAssertPost( vi == getNColumns() - 1); + return vi; +} + +void QcLinInEqTableau::EliminateObjective() +{ + QcBasicVarIndexIterator bvIt (*this); + + while (!bvIt.AtEnd()) + { + unsigned bvi = bvIt.getIndex(); + numT objcoeff = GetObjValue (bvi); + + if (objcoeff != 0.0) + { + SetObjValue (bvi, 0.0); + int ci = IsBasicIn (bvi); + assert (ci >= 0); + QcTableauRowIterator varCoeffs (*this, ci); + while (!varCoeffs.AtEnd()) + { // deduct constrained parameter coeffs + if (IsConstrained (varCoeffs.getIndex()) + && (varCoeffs.getIndex() != bvi)) + SetObjValue (varCoeffs.getIndex(), + (GetObjValue (varCoeffs.getIndex()) + - (objcoeff * varCoeffs.getValue()))); + varCoeffs.Increment(); + } + } + bvIt.Increment(); + } +} + + +numT +QcLinInEqTableau::EvalBasicVar(unsigned vi) const +{ + qcAssertPre( IsBasic( vi)); + + int ci = IsBasicIn( vi); + assert( ci != QcTableau::fInvalidConstraintIndex); + + numT value = GetRHS( ci); // rhs sign is not critical here + + for (QcTableauRowIterator varCoeffs( *this, ci); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + unsigned coeff_vi = varCoeffs.getIndex(); + if ((coeff_vi != vi) + && IsStructural( coeff_vi)) + value -= (varCoeffs.getValue() * GetDesireValue( coeff_vi)); + } + + return value; +} + +unsigned QcLinInEqTableau::getNRestrictedRows() const +{ + unsigned count = 0; + + for (unsigned i = 0; i < getNRows(); i++) + if (IsRestricted( i)) + count++; + + qcAssertPost( count <= getNRows()); + return count; +} + +bool QcLinInEqTableau::IsBasicFeasible() const +{ + for (QcConstraintIndexIterator cIt( *this); + !cIt.AtEnd(); + cIt.Increment()) + { + unsigned const ci = cIt.getIndex(); + if (IsRestricted( ci) + && (GetRHS( ci) < 0.0)) // N.B. We rely on GetRHS to do zeroisation here. + return false; + } + return true; +} + +bool QcLinInEqTableau::IsBasicOptimal() const +{ + QcParamVarIndexIterator pIt(*this); + + while (!pIt.AtEnd()) { + unsigned pi = pIt.getIndex(); + if (IsConstrained(pi)) { // Check this with Kim + numT obj = GetObjValue(pi); + if (QcUtility::IsNegative(obj)) + return false; + } + pIt.Increment(); + } + + return true; +} + +#if PROVIDE_LoadArtificial +int QcLinInEqTableau::LoadArtificial(const QcLinInEqTableau &other) + // Used to add artificial variable in complementary pivot algorithm +{ + int ocs; // Solved form constraint index for other tableau. + int *cassoc; // Associate each ocs with new ci + + cassoc = new int[other.GetRows()]; + Restart(); // Start with a fresh tableau + + // Preallocate the variable indices and initialise column properties + while (GetColumns() < other.GetColumns()) + NewVariable(); + + for (ocs = 0; ocs < other.GetRows(); ocs++) + if (other.IsRestricted(ocs)) { + QcTableauRowIterator varCoeffs(other, ocs); + cassoc[ocs] = AddEq(varCoeffs, other.GetRHS(ocs)); + } else + cassoc[ocs] = QcTableau::fInvalidConstraintIndex; + + for (int vi = 0; vi < other.GetColumns(); vi++) + if (other.IsSlack(vi)) + SetConstrained(vi, true); + + int ai = AddArtificial(-1.0); + + for (ocs = 0; ocs < other.GetRows(); ocs++) { + int co = cassoc[ocs]; + + if (co != QcTableau::fInvalidConstraintIndex) { + int cs = Eliminate(co); + #ifdef qcSafetyChecks + qcAssert(Pivot(cs, other.GetBasicVar(ocs))); + #else + Pivot(cs, other.GetBasicVar(ocs)); + #endif + } + } + + delete[] cassoc; + return ai; +} +#endif + +void QcLinInEqTableau::SetObjective(QcRowAdaptor &objCoeffs) +{ + QcVariableIndexIterator vIt(*this); + + while (!vIt.AtEnd()) { + SetObjValue(vIt.getIndex(), 0.0); + vIt.Increment(); + } + + while (!objCoeffs.AtEnd()) { + SetObjValue(objCoeffs.getIndex(), objCoeffs.getValue()); + objCoeffs.Increment(); + } +} + +bool QcLinInEqTableau::SimplexPivot(unsigned ci, unsigned vi) +{ + bool pivoted = Pivot( ci, vi); + + if (pivoted) + { + // express new basic var coeff in objective function using parameters + numT const objCoeff = GetObjValue( vi); + + for (QcTableauRowIterator varCoeffs( *this, ci); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + unsigned const coeff_ix = varCoeffs.getIndex(); + + qcAssert( IsConstrained( coeff_ix)); + + // Checking varCoeffs.Index()!=vi is not worth the time. + SetObjValue( coeff_ix, + (GetObjValue( coeff_ix) + - (objCoeff * varCoeffs.getValue()))); + } + assert( GetObjValue( vi) == 0.0); + } + + return pivoted; +} diff --git a/src/kits/interface/qoca/QcLinInEqTableau.hh b/src/kits/interface/qoca/QcLinInEqTableau.hh new file mode 100644 index 0000000000..7ffbed8e2a --- /dev/null +++ b/src/kits/interface/qoca/QcLinInEqTableau.hh @@ -0,0 +1,274 @@ +// $Id: QcLinInEqTableau.hh,v 1.18 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcLinInEqTableauH +#define __QcLinInEqTableauH + +#include "qoca/QcLinInEqRowColStateVector.hh" +#include "qoca/QcDelLinEqTableau.hh" +#include "qoca/QcRowAdaptor.hh" + +class QcLinInEqTableau : public QcDelLinEqTableau +{ +protected: + QcLinInEqRowColStateVector *fRowColState; + QcLinInEqColStateVector *fColState; + +public: + //-----------------------------------------------------------------------// + // Constructors. // + //-----------------------------------------------------------------------// + QcLinInEqTableau(unsigned hintRows, unsigned hintCols, QcBiMapNotifier &n); + QcLinInEqTableau(QcCoreTableau &tab, QcBiMapNotifier &n); + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + virtual numT EvalBasicVar(unsigned vi) const; + // Use the desired value cache and tableau coeffs to evaluate + // the basic variable with index vi. + virtual numT GetRHS(unsigned ci) const; + // This version of getRHS for QcLinInEqTableau is needed because the + // sign of the RHS value is critical for deciding feasibility. + // Can still use QcLinEqTableau::getRHS where sign is not critical. + + int GetColCondition(unsigned vi) const + { return fColState->GetCondition(vi); } + + numT GetObjValue(unsigned vi) const + { return fColState->GetObjValue(vi); } + + /** Returns the number of restricted rows, i.e. n({i: IsRestricted(i)}). + @postcondition 0 ≤ ret ≤ getNRows() + **/ + unsigned getNRestrictedRows() const; + + bool IsArtificial(unsigned vi) const + { return fColState->IsArtificial(vi); } + + /** Returns true iff ∀[unrestricted undeleted rows ci] + GetRHS(ci) ≥ 0. */ + bool IsBasicFeasible() const; + + bool IsBasicFeasibleSolved() const + { return (IsSolved() && IsBasicFeasible()); } + + bool IsBasicOptimal() const; + // But not necessarily feasible. + + bool IsBasicOptimalSolved() const + { return (IsSolved() && IsBasicOptimal()); } + + /** See documentation of QcLinInEqColState::fConstrained. */ + bool IsConstrained(unsigned vi) const + { return fColState->IsConstrained(vi); } + + bool IsDesire(unsigned vi) const + { return fColState->IsDesire(vi); } + + bool IsDual(unsigned vi) const + { return fColState->IsDual(vi); } + + bool IsError(unsigned vi) const + { return fColState->IsError(vi); } + + /** Indicates the constraint is solved and has a constrained basic + var. But not necessarily optimal. True iff ci's row condition + is fRegular, and ci's basic var is constrained. + **/ + bool IsRestricted(unsigned ci) const; + + bool IsSlack(unsigned vi) const + { return fColState->IsSlack(vi); } + + bool IsStructural(unsigned vi) const + { return fColState->IsStructural(vi); } + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + virtual int AddArtificial(numT coeff); + // Adds an artificial variable with given coefficient to all + // original constraints in the tableau. Used for complementary pivot. + + /** Identical to addLtEq, except uses a negative slack variable coeff. */ + virtual int AddGtEq(QcRowAdaptor &varCoeffs, numT rhs); + + /** Does the same as AddEq but also introduces a new slack variable so the + varCoeffs will represent a less-than-or-equal-to constraint. The slack + variable is added after any other new regular variables. + + @postcondition ret ≥ 0 + **/ + virtual int AddLtEq(QcRowAdaptor &varCoeffs, numT rhs); + + virtual unsigned NewVariable(); + // Create a new non basic structural variable and return its index. + virtual int RemoveEq(unsigned ci); + virtual bool RemoveVarix(unsigned vi); + + + /** Adds a restricted dual variable. Used for complementary pivot. + + @postcondition 0 ≤ ret < new getNColumns(). + + @return The index of the new variable. + **/ + unsigned AddDual(); + + + int AddError(); + // Add an error (slack) variable. + unsigned AddSlack(); + // Add an error (slack) variable. + void EliminateObjective(); + // Eliminate basic variable coeffs from objective function. + // Only constrained parameters are included. Constant terms have + // no effect on the objective function so are not included. +#if PROVIDE_LoadArtificial + int LoadArtificial(const QcLinInEqTableau &other); + // Restarts the tableau and loads it with copies of the solved form + // constraints from the other tableau. Also an artificial variable + // is introduced and its index is returned. +#endif + + void SetConstrained(unsigned vi, bool c) + { fColState->SetConstrained(vi, c); } + + void SetColCondition(unsigned vi, int c) + { fColState->SetCondition(vi, c); } + + void SetObjective(QcRowAdaptor &objCoeffs); + // Loads the objective function coefficients and calls eliminateObj. + + void SetObjValue(unsigned vi, numT obj) + { fColState->SetObjValue(vi, obj); } + + bool SimplexPivot(unsigned ci, unsigned vi); + // This does a QcLinEqTableau::Pivot but also maintains the objective + // function coefficients for restricted rows. + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const + { QcLinEqTableau::Print(os); } + +protected: + //-----------------------------------------------------------------------// + // Constructors. // + //-----------------------------------------------------------------------// + QcLinInEqTableau(QcBiMapNotifier &n); +}; + +inline QcLinInEqTableau::QcLinInEqTableau(unsigned hintRows, unsigned hintCols, + QcBiMapNotifier &n) + : QcDelLinEqTableau(*new QcDelCoreTableau(hintRows, hintCols, + *new QcLinInEqRowColStateVector()), + n), + fRowColState((QcLinInEqRowColStateVector *)QcLinEqTableau::fRowColState), + fColState((QcLinInEqColStateVector *)&fRowColState->GetColState()) +{ +} + +inline QcLinInEqTableau::QcLinInEqTableau(QcCoreTableau &tab, QcBiMapNotifier &n) + : QcDelLinEqTableau(tab, n), + fRowColState((QcLinInEqRowColStateVector *)QcLinEqTableau::fRowColState), + fColState((QcLinInEqColStateVector *)&fRowColState->GetColState()) +{ +} + +inline QcLinInEqTableau::QcLinInEqTableau(QcBiMapNotifier &n) + : QcDelLinEqTableau(n) +{ +} + +inline unsigned QcLinInEqTableau::AddDual() +{ + unsigned vi = IncreaseColumns(); + SetColCondition(vi, QcLinInEqColState::fDual); + SetConstrained(vi, true); + return vi; +} + +inline int QcLinInEqTableau::AddError() +{ + unsigned vi = NewVariable(); + SetColCondition(vi, + (QcLinInEqColState::fSlack | + QcLinInEqColState::fStructural | + QcLinInEqColState::fError)); + SetConstrained(vi, true); + return vi; +} + +inline numT QcLinInEqTableau::GetRHS(unsigned ci) const +{ + numT rhs = QcLinEqTableau::GetRHS(ci); + + /* [pjm:] TODO: Should this be QcUtility::IsZero? */ + if (QcUtility::IsNearZero(rhs)) + { +#ifndef NDEBUG + if (!QcUtility::IsZero (rhs)) + { + cerr << "DBG: N.B.: found near-zero non-zero RHS.\n"; + //*(char *)0=0; + //return rhs; + } +#endif + return 0.0; + } + return rhs; +} + +inline bool QcLinInEqTableau::IsRestricted(unsigned ci) const +{ + return GetRowCondition(ci) == QcLinEqRowState::fRegular && + IsConstrained(GetBasicVar(ci)); +} + +inline unsigned QcLinInEqTableau::NewVariable() +{ + unsigned vi = QcLinEqTableau::NewVariable(); + return vi; +} + +inline int QcLinInEqTableau::RemoveEq(unsigned ci) +{ + UNUSED(ci); + throw QcWarning("Error: Should not call QcLinInEqTableau::RemoveEq"); + return fInvalidConstraintIndex; +} + +inline bool QcLinInEqTableau::RemoveVarix(unsigned vi) +{ + UNUSED(vi); + throw QcWarning("Error: Should not call QcLinInEqTableau::RemoveVarix"); + return false; +} + +#endif /* !__QcLinInEqTableauH */ diff --git a/src/kits/interface/qoca/QcLinPoly.cc b/src/kits/interface/qoca/QcLinPoly.cc new file mode 100644 index 0000000000..166b45007c --- /dev/null +++ b/src/kits/interface/qoca/QcLinPoly.cc @@ -0,0 +1,172 @@ +// $Id: QcLinPoly.cc,v 1.11 2000/12/14 02:28:54 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcDefines.hh" +#include "qoca/QcLinPoly.hh" + +QcLinPoly::QcLinPoly(const QcLinPoly& rhs) +{ + size_t n = rhs.fTerms.size(); + fTerms.resize(n); + for (unsigned int i = n; i-- != 0;) + fTerms[i] = new QcLinPolyTerm(*rhs.fTerms[i]); +} + +QcLinPoly::~QcLinPoly() +{ + unsigned n = fTerms.size(); + for (unsigned int i = 0; i < n; i++) + delete fTerms[i]; + + fTerms.resize(0); +} + +#ifndef NDEBUG +void QcLinPoly::assertInvar() const +{ + unsigned n = getNTerms(); + for(unsigned i = 0; i < n; i++) { + QcLinPolyTerm *ti = fTerms[i]; + qcAssertInvar(ti != NULL); + ti->assertInvar(); + qcAssertInvar(ti->GetCoeff() != 0.0); + /* effic: If we expect largish (n >= 6) termsets, then we could + use a marking technique (using a flag in each QcFloatRep). */ + for(unsigned j = i; j--;) + qcAssertInvar(fTerms[j]->GetVariable() != ti->GetVariable()); + } +} +#endif + +numT QcLinPoly::getValue() const +{ + numT v = 0.0; + for (unsigned i = fTerms.size(); i-- != 0;) + v += fTerms[i]->GetValue(); + return v; +} + +bool QcLinPoly::hasVar (QcFloatRep const *v) const +{ + for (unsigned i = fTerms.size(); i-- != 0;) + if (fTerms[i]->hasVar (v)) + return true; + return false; +} + +void QcLinPoly::Negate() +{ + for (unsigned int i = fTerms.size(); i-- != 0;) + fTerms[i]->Negate(); +} + +void QcLinPoly::Print(ostream &os) const +{ + os << "("; + + if (fTerms.size() > 0) { + os << *fTerms[0]; + + for (unsigned int i = 1; i < fTerms.size(); i++) + os << ", " << *fTerms[i]; + } + + os << ")"; +} + +QcLinPoly &QcLinPoly::operator=(const QcLinPoly &rhs) +{ + if (this != &rhs) { + for (unsigned int i = 0; i < fTerms.size(); i++) + delete fTerms[i]; + + fTerms.resize(0); + + for (unsigned int i = 0; i < rhs.fTerms.size(); i++) + fTerms.push_back(new QcLinPolyTerm(*rhs.fTerms[i])); + } + + dbg(assertInvar()); + return *this; +} + +void QcLinPoly::add(numT coeff, QcFloatRep *var) +{ + if (!QcUtility::IsZero( coeff)) + doPlus( coeff, var); +} + +void QcLinPoly::add(numT coeff, QcFloat const &var) +{ + if (!QcUtility::IsZero( coeff)) + doPlus( coeff, var.pointer()); +} + +QcLinPoly &QcLinPoly::operator+=(const QcLinPolyTerm& rhs) + // If rhs is not zero then; if rhs does not exists in fTerms, add it, + // otherwise add the existing lin_poly_term together with rhs +{ + numT coeff = rhs.GetCoeff(); + if (coeff != 0.0) + doPlus( coeff, rhs.getVariable()); + return *this; +} + +QcLinPoly& QcLinPoly::operator-=(const QcLinPolyTerm& rhs) + //If rhs is not zero then; if rhs does not exists in fTerms, add it, + // otherwise subtract rhs from the existing lin_poly_term. +{ + numT coeff = rhs.GetCoeff(); + if (coeff != 0.0) + doPlus( -coeff, rhs.getVariable()); + return *this; +} + +void QcLinPoly::doPlus(numT coeff, QcFloatRep *var) +{ + // First try to find existing term of same variable. + for (TTermsVector::iterator i = fTerms.begin(); + i != fTerms.end(); + i++) + { + if ((*i)->getVariable() != var) + continue; + numT result = (*i)->addToCoeff( coeff); + assert( QcUtility::IsZeroised( result)); + if (result == 0.0) + { + delete( *i); + fTerms.erase( i); + } + goto out; + } + + // No existing term with variable var, so append new term to list. + fTerms.push_back( new QcLinPolyTerm( coeff, var)); + + out: + dbg(assertInvar()); +} diff --git a/src/kits/interface/qoca/QcLinPoly.hh b/src/kits/interface/qoca/QcLinPoly.hh new file mode 100644 index 0000000000..451359a8f6 --- /dev/null +++ b/src/kits/interface/qoca/QcLinPoly.hh @@ -0,0 +1,209 @@ +// $Id: QcLinPoly.hh,v 1.10 2000/12/14 02:28:54 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// Note that although LinPoly uses a VectorOfLinPolyTermPtr and allocates the // +// LinPolyTerm values on the heap, the semantics of LinPoly costructors, // +// copy, assignment, and destructor all create, copy or destroy private // +// copies of the LinPolyTerm values. // +//============================================================================// + +#ifndef __QcLinPolyH +#define __QcLinPolyH + +#include "qoca/QcUnsortedListSet.hh" +#include "qoca/QcLinPolyTerm.hh" + +class QcLinPoly +{ +public: + friend QcLinPoly operator+(const QcLinPolyTerm &lhs, const QcLinPolyTerm &rhs); + friend QcLinPoly operator-(const QcLinPolyTerm &lhs, const QcLinPolyTerm &rhs); + friend QcLinPoly operator+(const QcLinPolyTerm &lhs, QcLinPoly &rhs); + friend QcLinPoly operator-(const QcLinPolyTerm &lhs, QcLinPoly &rhs); + + //typedef vector TTermsVector; + typedef QcUnsortedListSet TTermsVector; + +public: + //-----------------------------------------------------------------------// + // Constructors // + //-----------------------------------------------------------------------// + QcLinPoly(); + QcLinPoly(const QcLinPoly &p); + QcLinPoly(const QcLinPolyTerm &lpt); + virtual ~QcLinPoly(); + + //-----------------------------------------------------------------------// + // Query functions // + //-----------------------------------------------------------------------// + +#ifndef NDEBUG + void assertInvar() const; +#endif + + const TTermsVector &GetTerms() const + { return fTerms; } + + const QcLinPolyTerm &GetTerm(int i) const + { return *fTerms[i]; } + + bool hasVar (QcFloatRep const *v) const; + + unsigned GetSize() const + { return fTerms.size(); } + + unsigned getNTerms() const + { return fTerms.size(); } + + numT getValue() const; + + //-----------------------------------------------------------------------// + // Manipulation functions // + //-----------------------------------------------------------------------// + void Negate(); + + /** Push does not check the LinPoly to consolidate coeffs for the same + variable. Hence it should only be used when this can be guaranteed. + It checks and does nothing if the coeff is zero. + [Roughly equivalent to addUniqueTerm in Java version.] + **/ + void Push(numT coeff, QcFloat &var); + + void push (numT coeff, QcFloatRep *var); + + /** Like operator+=: coeff is allowed to be zero, and var is allowed to be already present. */ + void add(numT coeff, QcFloatRep *var); + void add(numT coeff, QcFloat const &var); + + QcLinPoly &operator=(const QcLinPoly &rhs); + QcLinPoly &operator+=(const QcLinPolyTerm &rhs); + QcLinPoly &operator-=(const QcLinPolyTerm &rhs); + QcLinPoly &operator+(const QcLinPolyTerm &rhs); + QcLinPoly &operator-(const QcLinPolyTerm &rhs); + + QcLinPoly &operator-() + { Negate(); return (*this); } + + //-----------------------------------------------------------------------// + // Utility functions // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; + +private: + void doPlus(numT coeff, QcFloatRep *var); + + TTermsVector fTerms; +}; + +inline QcLinPoly::QcLinPoly() +{ +} + +inline QcLinPoly::QcLinPoly(const QcLinPolyTerm &term) +{ + if (term.GetCoeff() != 0.0) + fTerms.push_back(new QcLinPolyTerm(term)); +} + +inline void QcLinPoly::Push(numT coeff, QcFloat &var) +{ +#if qcCheckPre + for (unsigned int i = fTerms.size(); i-- != 0;) + qcAssertExternalPre(var != fTerms[i]->GetVariable()); +#endif + if (!QcUtility::IsZero(coeff)) + fTerms.push_back(new QcLinPolyTerm(coeff, var)); + dbg(assertInvar()); +} + +inline void QcLinPoly::push (numT coeff, QcFloatRep *var) +{ +#if qcCheckPre + for (unsigned int i = fTerms.size(); i-- != 0;) + qcAssertExternalPre(var != fTerms[i]->getVariable()); +#endif + if (!QcUtility::IsZero(coeff)) + fTerms.push_back (new QcLinPolyTerm (coeff, var)); + dbg(assertInvar()); +} + +inline QcLinPoly &QcLinPoly::operator+(const QcLinPolyTerm& rhs) +{ + if (rhs.GetCoeff() != 0.0) + *this += rhs; + + return *this; +} + + +inline QcLinPoly& QcLinPoly::operator-(const QcLinPolyTerm& rhs) +{ + if (rhs.GetCoeff() != 0.0) + *this -= rhs; + + return *this; +} + +inline QcLinPoly operator+(const QcLinPolyTerm &lhs, QcLinPoly &rhs) +{ + if (lhs.GetCoeff() != 0.0) + rhs += lhs; + + return rhs; +} + +inline QcLinPoly operator-(const QcLinPolyTerm &lhs, QcLinPoly &rhs) +{ + rhs.Negate(); + + if (lhs.GetCoeff() != 0.0) + rhs += lhs; + + return rhs; +} + +inline QcLinPoly operator+(const QcLinPolyTerm &lhs, const QcLinPolyTerm &rhs) +{ + QcLinPoly new_lin_poly(lhs); + new_lin_poly += rhs; + return new_lin_poly; +} + +inline QcLinPoly operator-(const QcLinPolyTerm &lhs, const QcLinPolyTerm &rhs) +{ + QcLinPoly new_lin_poly(lhs); + new_lin_poly -= rhs; + return new_lin_poly; +} + +#ifndef qcNoStream +inline ostream& operator<<(ostream &os, const QcLinPoly &p) +{ + p.Print(os); + return os; +} +#endif + +#endif diff --git a/src/kits/interface/qoca/QcLinPolyTerm.hh b/src/kits/interface/qoca/QcLinPolyTerm.hh new file mode 100644 index 0000000000..a50f5496ae --- /dev/null +++ b/src/kits/interface/qoca/QcLinPolyTerm.hh @@ -0,0 +1,218 @@ +// $Id: QcLinPolyTerm.hh,v 1.10 2001/01/05 02:43:48 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// Constants are no longer accepted as valid LinPolyTerms. It will be easy // +// to extend linpolyterm (and call it polyterm) to allow quadratic, cubic, // +// etc terms. // +//============================================================================// + +#ifndef __QcLinPolyTermH +#define __QcLinPolyTermH + +#include "qoca/QcDefines.hh" +#include "qoca/QcFloat.hh" +#include "qoca/QcUtility.hh" + +class QcLinPolyTerm +{ +public: + //-----------------------------------------------------------------------// + // Constructor // + //-----------------------------------------------------------------------// + QcLinPolyTerm(numT coeff, const QcFloat &var); + QcLinPolyTerm(numT coeff, QcFloatRep *var); + QcLinPolyTerm(const QcFloat &var); + QcLinPolyTerm(const QcLinPolyTerm &term); + virtual ~QcLinPolyTerm() {} + + //-----------------------------------------------------------------------// + // Data Structure access functions. // + //-----------------------------------------------------------------------// + QcFloat &GetVariable() + { return fVariable; } + + QcFloatRep *getVariable() const + { return fVariable.pointer(); } + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + + void assertInvar() const + { + assert( QcUtility::IsZeroised( fCoeff)); + } + + /** @postcondition IsZeroised( ret) */ + numT GetCoeff() const + { + qcAssertPost( QcUtility::IsZeroised( fCoeff)); + return fCoeff; + } + + QcFloat const &GetVariable() const + { return fVariable; } + +#if 0 + QcFloat &GetVariable() + { return fVariable; } +#endif + + bool hasVar (QcFloatRep const *v) const + { return fVariable.pointer() == v; } + + numT GetValue() const + { return QcUtility::Zeroise( fCoeff * fVariable.Value()); } + + bool operator==(const QcLinPolyTerm &rhs) const; + + int operator!=(const QcLinPolyTerm &rhs) const + { return !(*this == rhs); } + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + void Negate() + { make_neg( fCoeff); } + + /** Used only by QcLinPoly. + @postcondition IsZeroised(ret) + **/ + numT addToCoeff( numT delta) + { + fCoeff = QcUtility::Zeroise( fCoeff + delta); + dbg(assertInvar()); + return fCoeff; + } + + void SetCoeff(numT coeff) + { + fCoeff = QcUtility::Zeroise( coeff); + dbg(assertInvar()); + } + +private: + QcLinPolyTerm &operator+=(const QcLinPolyTerm &rhs); + QcLinPolyTerm &operator-=(const QcLinPolyTerm &rhs); + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// +public: + virtual void Print(ostream &os) const; + +private: + numT fCoeff; + QcFloat fVariable; +}; + +inline QcLinPolyTerm::QcLinPolyTerm(numT coeff, const QcFloat &var) + : fCoeff( QcUtility::Zeroise( coeff)), fVariable( var) +{ + dbg(assertInvar()); +} + +inline QcLinPolyTerm::QcLinPolyTerm(numT coeff, QcFloatRep *var) + : fCoeff( QcUtility::Zeroise( coeff)), fVariable( *var) +{ + dbg(assertInvar()); +} + +inline QcLinPolyTerm::QcLinPolyTerm(const QcFloat &var) + : fCoeff( 1u), fVariable( var) +{ + dbg(assertInvar()); +} + +inline QcLinPolyTerm::QcLinPolyTerm(const QcLinPolyTerm &term) + : fCoeff(term.fCoeff), fVariable(term.fVariable) +{ + dbg(assertInvar()); +} + +#if 0 /* unused */ +inline void QcLinPolyTerm::assertDeepInvar() const +{ + fVariable.assertDeepInvar(); +} +#endif + +inline void QcLinPolyTerm::Print(ostream &os) const +{ + const char *name = fVariable.Name(); + + os << fCoeff << " * " + << ((name) ? name : "") + << "#" << fVariable.Id(); +} + + +#if 0 +inline QcLinPolyTerm &QcLinPolyTerm::operator+=(const QcLinPolyTerm &other) +{ + qcAssertPre( fVariable == other.fVariable); + + fCoeff = QcUtility::Zeroise( fCoeff + other.fCoeff); + dbg(assertInvar()); + return( *this); +} + +inline QcLinPolyTerm &QcLinPolyTerm::operator-=(const QcLinPolyTerm& other) +{ + qcAssertPre( fVariable == other.fVariable); + + fCoeff = QcUtility::Zeroise( fCoeff - other.fCoeff); + dbg(assertInvar()); + return( *this); +} +#endif + + +inline bool QcLinPolyTerm::operator==(const QcLinPolyTerm &rhs) const +{ + return (QcUtility::IsZero(fCoeff - rhs.fCoeff) + && ((fCoeff == 0) + || (fVariable == rhs.fVariable))); +} + +inline QcLinPolyTerm operator-(QcLinPolyTerm const &pos) +{ + QcLinPolyTerm ret( pos); + ret.Negate(); + return ret; +} + +inline QcLinPolyTerm operator*(numT coeff, QcFloat &var) +{ + return QcLinPolyTerm( coeff, var); +} + +inline ostream& operator<<(ostream &os, const QcLinPolyTerm &term) +{ + term.Print( os); + return os; +} + +#endif diff --git a/src/kits/interface/qoca/QcMatrix.hh b/src/kits/interface/qoca/QcMatrix.hh new file mode 100644 index 0000000000..179ab5cc40 --- /dev/null +++ b/src/kits/interface/qoca/QcMatrix.hh @@ -0,0 +1,187 @@ +// $Id: QcMatrix.hh,v 1.16 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcMatrixH +#define __QcMatrixH + +#include "qoca/QcDefines.hh" +//#include "qoca/QcMatrixIterator.hh" + +class QcMatrix +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcMatrix(); + virtual ~QcMatrix() {} + +#ifndef NDEBUG + void assertInvar() const + { + assert (fRows <= fAllocRows); + assert ((int) fAllocRows >= 0); + assert (fColumns <= fAllocColumns); + assert ((int) fAllocColumns >= 0); + } +#endif + + //-----------------------------------------------------------------------// + // Enquiry functions. // + //-----------------------------------------------------------------------// + virtual numT GetValue(unsigned row, unsigned col) const = 0; + + unsigned GetColumns() const + { return fColumns; } + + unsigned getNColumns() const + { return fColumns; } + + unsigned GetRows() const + { return fRows; } + + unsigned getNRows() const + { return fRows; } + + //-----------------------------------------------------------------------// + // Matrix size management functions. // + //-----------------------------------------------------------------------// + + /** Ensure that future resizes up to these limits will take place in constant + time -- i.e. preallocate if necessary. Never shrinks the allocation: + equivalent to Reserve(MAX(rows, fAllocRows), MAX(cols, + fAllocColumns)). Reserve(fAllocRows, fAllocColumns) is a + no-op. + **/ + virtual void Reserve(unsigned rows, unsigned cols) = 0; + + void clear() + { + Resize( 0, 0); + } + + virtual void Resize(unsigned rows, unsigned cols) = 0; + // Change the size of the used part of the array up or down. + // Increases may take time up to O(rows * cols). + // New elements are initialised to zero. + + //-----------------------------------------------------------------------// + // Basic matrix data management functions. // + //-----------------------------------------------------------------------// + //virtual void CopyRow(unsigned row, QcMatrixIterator &i) = 0; + //virtual void IncreaseValue(unsigned row, unsigned col, numT inc) = 0; + virtual void SetValue(unsigned row, unsigned col, numT val) = 0; + //virtual void SwapColumns(unsigned c1, unsigned c2) = 0; + //virtual void SwapRows(unsigned r1, unsigned r2) = 0; + virtual void Zero() = 0; + virtual void ZeroColumn(unsigned col) = 0; + virtual void ZeroRow(unsigned row) = 0; + + //-----------------------------------------------------------------------// + // Numerical computation functions. // + //-----------------------------------------------------------------------// + + // /** Equivalent to AddScaledRow(destRow, srcRow, 1.0). */ + // virtual void AddRow(unsigned destRow, unsigned srcRow) = 0; + + + /** Set destRow to ((old destRow) + ((old srcRow) * factor)). + + @precondition destRow < getNRows() + @precondition srcRow < getNRows() + @precondition QcUtility::isFinite(factor) + + @return !QcUtility::IsZero(factor) + **/ + virtual bool AddScaledRow( unsigned destRow, unsigned srcRow, + numT factor) = 0; + + + /** Equivalent to ScaleRow(row, 1.0/factor), but with sometimes + slightly less round-off error. */ + virtual void FractionRow(unsigned row, numT factor) = 0; + + + /** Do a pivot operation on row, col. + +

In the following conditions, Mi, j means + getValue(i, j), and p means old Mrow, col. + + @precondition !IsZero(p) + @precondition row < getNRows() + @precondition col < getNColumns() + +

The last two postconditions follow from the first two. + + @postcondition row row is 1/p times its old value + + @postcondition ∀[i: i &ne row] row i is its old + value minus Mi, col times the new row row. + + @postcondition getValue(row, col) = 1 + @postcondition ∀[i ≠ row] Mi, col = 0 + **/ + virtual void Pivot(unsigned row, unsigned col) = 0; + + /** Set row to old row * factor. */ + virtual bool ScaleRow(unsigned row, numT factor) = 0; + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; + +protected: + unsigned fAllocRows; // Used only by Reserve + unsigned fAllocColumns; // Used only by Reserve + unsigned fRows; // Number of rows + unsigned fColumns; // Number of columns +}; + +inline QcMatrix::QcMatrix() + : fAllocRows(0), fAllocColumns(0), fRows(0), fColumns(0) +{ +} + +inline void QcMatrix::Print(ostream &os) const +{ + for (unsigned i = 0; i < fRows; i++) { + os << i << ":"; + for (unsigned j = 0; j < fColumns; j++) + os << "\t" << GetValue(i, j); + os << endl; + } +} + +#ifndef qcNoStream +inline ostream &operator<<(ostream &os, const QcMatrix &m) +{ + m.Print(os); + return os; +} +#endif + +#endif diff --git a/src/kits/interface/qoca/QcMatrixIterator.hh b/src/kits/interface/qoca/QcMatrixIterator.hh new file mode 100644 index 0000000000..e7305da7b8 --- /dev/null +++ b/src/kits/interface/qoca/QcMatrixIterator.hh @@ -0,0 +1,103 @@ +// $Id: QcMatrixIterator.hh,v 1.9 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcMatrixIteratorH +#define __QcMatrixIteratorH + +#include +#include + +class QcMatrixIterator : public QcIterator +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcMatrixIterator(unsigned vec); + +#ifndef NDEBUG + void assertInvar() const + { + assert ((int) fIndex >= 0); + } +#endif + + //-----------------------------------------------------------------------// + // Enquiry functions. // + //-----------------------------------------------------------------------// + int GetIndex() const + { + qcAssertPre (!AtEnd()); + qcAssertPost( int( fIndex) >= 0); + return (int) fIndex; + } + + unsigned getIndex() const + { + qcAssertPre (!AtEnd()); + qcAssertPost ((int) fIndex >= 0); + return fIndex; + } + + numT GetValue() const + { + qcAssertPre( !AtEnd()); + qcAssertPost( !QcUtility::IsZero( fValue)); + return fValue; + } + + numT getValue() const + { + qcAssertPre( !AtEnd()); + qcAssertPost( !QcUtility::IsZero( fValue)); + return fValue; + } + + //-----------------------------------------------------------------------// + // Iteration functions. // + //-----------------------------------------------------------------------// + void SetToBeginOf(unsigned vec); + +protected: + unsigned fVector; + unsigned fIndex; + numT fValue; +}; + +inline QcMatrixIterator::QcMatrixIterator(unsigned vec) + : QcIterator(), + fVector(vec), + fValue() +{ +} + +inline void QcMatrixIterator::SetToBeginOf(unsigned vec) +{ + fVector = vec; + Reset(); +} + +#endif diff --git a/src/kits/interface/qoca/QcNlpSolver.H b/src/kits/interface/qoca/QcNlpSolver.H new file mode 100644 index 0000000000..e7e835823a --- /dev/null +++ b/src/kits/interface/qoca/QcNlpSolver.H @@ -0,0 +1,288 @@ +// Generated automatically from QcNlpSolver.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcNlpSolverDCL +#define QcNlpSolverDCL +#line 1 "QcNlpSolver.ch" +#include +#ifdef QC_USING_NLPSOLVER + +#include +#include +#include +extern "C" { +#include +#include +#include +} +#undef bool + + +#line 21 "QcNlpSolver.ch" +/* TODO: For every var added, check if it is restricted; if it is, then add an + explicit constraint. */ + +/** A solver suitable for non-linear constraints. The constraints should + be continuous and differentiable. + +

Currently only linear constraints are implemented :-) but adding + non-linear constraints should be little work; mainly just creating the + non-linear constraint object (see buildObjective for how this is + done) and adding it to the fWnConstraints singly-linked list; + though there'll also be a bit of fiddling to allow removeConstraint + and changeConstraint to work. + +

Improvements: +

    + +
  • Obviously linear constraints ought to be handled differently. At + least linear equality constraints should be handled by elimination. + Probably inequalities can be handled the same way, once the active set has + been determined. + +

  • The line search in the underlying unconstrained problem is currently + done with a golden section search. Should probably solve a (sequence of) + Taylor approximation(s) if the functions are polynomials. (It's OK for the + line search to consider only the section of the barrier function that + applies at the start of the line search... hmm, need to consider the + start-in-flat-section case.) + +

  • Currently doSolve makes a feasibility step (ignoring the + goal function) immediately after solving. This is obviously suboptimal: it + will tend to lose optimality. However, without that step, we often had + infeasible "solutions" returned. Maybe should reduce the scale of the + [user] goal function with each iteration, as well as or instead of the + current barrier offset method. + +

    Could experiment with "big-M" arithmetic: use an explicit (symbolic) + big-M to represent the ratio between the weight of the constraints and the + weight of the user goal function. This means that only a single call to the + underlying unconstrained optimizer is needed, at the cost of doing numerical + operations in a quasi-symbolic form. The number representation might be + {int power_of_bigM_in_first_term; double term_coeffs[];}. One + problem is when to decide that the high-order term should be considered + zero. + +

+ +**/ +class QcNlpSolver + : public QcSolver +{ +public: + + +QcNlpSolver(); +#line 84 "QcNlpSolver.ch" +QcNlpSolver(unsigned hintNumConstraints, unsigned hintNumVariables); +#line 97 "QcNlpSolver.ch" +virtual ~QcNlpSolver() +{ +} + + +#ifndef NDEBUG + +void +assertInvar() const; +#line 114 "QcNlpSolver.ch" +void +assertConstraintsInvar() const; +#line 141 "QcNlpSolver.ch" +unsigned +nWnConstraints() const; +#line 153 "QcNlpSolver.ch" +#endif + + + +virtual void +AddVar(QcFloat &v); +#line 164 "QcNlpSolver.ch" +void +addVar(QcFloatRep *v); +#line 171 "QcNlpSolver.ch" +virtual bool +RemoveVar(QcFloat &v); +#line 178 "QcNlpSolver.ch" +bool +removeVar(QcFloatRep *v); +#line 185 "QcNlpSolver.ch" +virtual bool +IsRegistered(QcFloat const &v) const; +#line 192 "QcNlpSolver.ch" +bool +isRegistered(QcFloatRep *v) const; +#line 198 "QcNlpSolver.ch" +/** Begin a sequence of constraint operations. The changes are not necessarily + applied until the corresponding EndAddConstraint call. + +

Batches are not (currently) nestable. + + @precondition !isInBatchMode() +**/ + +virtual void +BeginAddConstraint(); +#line 214 "QcNlpSolver.ch" +virtual bool +EndAddConstraint(); +#line 234 "QcNlpSolver.ch" +virtual bool +AddConstraint(QcConstraint &c); +#line 241 "QcNlpSolver.ch" +virtual bool +AddConstraint(QcConstraint &c, QcFloat &hint); +#line 249 "QcNlpSolver.ch" +/** @precondition c != 0 + + @precondition c (i.e. something returning the same + Id() as c; values of LHS and RHS are irrelevant) is not + already present. + + @postcondition All vars in c.LinPoly() are registered with this + solver, with fVarStow.getUsage(v) incremented by 1. +**/ + +bool +addConstraint(QcConstraintRep *c); +#line 297 "QcNlpSolver.ch" +virtual bool +RemoveConstraint(QcConstraint &c); +#line 304 "QcNlpSolver.ch" +bool +removeConstraint(QcConstraintRep *c); +#line 325 "QcNlpSolver.ch" +virtual bool +ChangeConstraint( QcConstraint &c, numT rhs); +#line 332 "QcNlpSolver.ch" +bool +changeConstraint( QcConstraintRep *c, numT rhs); +#line 372 "QcNlpSolver.ch" +virtual void +RestSolver(); +#line 381 "QcNlpSolver.ch" +virtual bool +IsFree(QcFloat const &v) const; +#line 388 "QcNlpSolver.ch" +bool +isFree(QcFloatRep *v) const; +#line 397 "QcNlpSolver.ch" +virtual bool +IsBasic(QcFloat const &v) const; +#line 405 "QcNlpSolver.ch" +virtual void +BeginEdit(); +#line 413 "QcNlpSolver.ch" +virtual void +EndEdit(); +#line 432 "QcNlpSolver.ch" +virtual void +Resolve(); +#line 443 "QcNlpSolver.ch" +virtual bool +Reset(); +#line 453 "QcNlpSolver.ch" +virtual void +Solve(); +#line 461 "QcNlpSolver.ch" +void +solveNoRest(); +#line 500 "QcNlpSolver.ch" +private: + + +void +commitSolution(); +#line 518 "QcNlpSolver.ch" +void +restDesVals(); +#line 533 "QcNlpSolver.ch" +bool +isFeasible(); +#line 547 "QcNlpSolver.ch" +#ifndef NDEBUG + +bool +wnConstraintsSatisfied() const; +#line 586 "QcNlpSolver.ch" +#endif + + +/** Solve fWnConstraints, storing the results only in + fVarStow.getSolvedValArray(). Ignores fConstraints. + + @precondition fVarStow.constrCacheValid() +**/ + +int +doSolve( wn_nonlinear_constraint_type objective, int offset_iterations); +#line 647 "QcNlpSolver.ch" +typedef hash_map fConstraints_T; + + + +void +doRemoveConstraint( QcNlpSolver::fConstraints_T::iterator i); +#line 681 "QcNlpSolver.ch" +void +refVars(QcConstraintRep const *c); +#line 695 "QcNlpSolver.ch" +/** Decrement variable usage counts (reversing refVars). */ + +void +derefVars(QcConstraintRep const *c); +#line 712 "QcNlpSolver.ch" +void +fixWnConstraints(); +#line 730 "QcNlpSolver.ch" +wn_sll +makeAndInsertWnConstraint(QcConstraintRep *c); +#line 763 "QcNlpSolver.ch" +void +fixWnConstraint(QcConstraintRep *c, wn_linear_constraint_type wn_c); +#line 780 "QcNlpSolver.ch" +#ifndef NDEBUG + +bool +sameConstraint(wn_linear_constraint_type wn_c, QcConstraintRep const *c) const; +#line 816 "QcNlpSolver.ch" +#endif + + +void +trimWnConstraints(); +#line 885 "QcNlpSolver.ch" +wn_nonlinear_constraint_type +buildObjective(); +#line 901 "QcNlpSolver.ch" +wn_nonlinear_constraint_type +buildZeroObjective(); +#line 911 "QcNlpSolver.ch" +private: +QcVarStow fVarStow; +unsigned fNBatchConstraints; +fConstraints_T fConstraints; +wn_sll fWnConstraints; +bool fIsEditMode; + +}; + +#else /* !QC_USING_NLPSOLVER */ +// Make the linker happy. + + +void +QcNlpSolver_dummy(); +#line 929 "QcNlpSolver.ch" +#endif /* !QC_USING_NLPSOLVER */ + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcNlpSolverDCL */ diff --git a/src/kits/interface/qoca/QcNlpSolver.cc b/src/kits/interface/qoca/QcNlpSolver.cc new file mode 100644 index 0000000000..c5e51ada34 --- /dev/null +++ b/src/kits/interface/qoca/QcNlpSolver.cc @@ -0,0 +1,853 @@ +// Generated automatically from QcNlpSolver.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcNlpSolver.hh" +#line 1 "QcNlpSolver.ch" + +#ifdef QC_USING_NLPSOLVER + +#line 15 "QcNlpSolver.ch" +#include + + +#include + + +/* TODO: For every var added, check if it is restricted; if it is, then add an + explicit constraint. */ + + +#line 74 "QcNlpSolver.ch" +QcNlpSolver::QcNlpSolver() + : QcSolver(), + fVarStow(), + fConstraints(), + fWnConstraints( 0), + fIsEditMode( false) +{ +} + + +QcNlpSolver::QcNlpSolver(unsigned hintNumConstraints, unsigned hintNumVariables) + : QcSolver(), + fVarStow(), + fConstraints(), + fWnConstraints( 0), + fIsEditMode( false) +{ + UNUSED( hintNumConstraints); + UNUSED( hintNumVariables); + // effic: resize fVarStow, fConstraints. +} + + +#line 102 "QcNlpSolver.ch" +#ifndef NDEBUG + +void +QcNlpSolver::assertInvar() const +{ + /* TODO: assert(∀[c ∈ constraints] + ∀[v ∈ c.LinPoly()] + fVarStow.varPresent( v) + ∧ (fVarStow.getUsage(v) is correct) */ +} + + +void +QcNlpSolver::assertConstraintsInvar() const +{ + assert( !fVarStow.constrCacheValid() + || (nWnConstraints() == checkedConstraints_size())); + assert( fConstraints.size() == checkedConstraints_size()); + + for (vector::const_iterator ci = checkedConstraints_abegin(), + ciEnd = checkedConstraints_aend(); + ci != ciEnd; ci++) + { + QcConstraintRep *cc = *ci; + fConstraints_T::const_iterator p = fConstraints.find( cc); + assert( p != fConstraints.end()); + if (fVarStow.constrCacheValid()) + { + wn_sll el = p->second; + assert( el != 0); + wn_linear_constraint_type wn_c + = (wn_linear_constraint_type) el->contents; + assert( wn_c != 0); + assert( sameConstraint( wn_c, cc)); + } + } +} + + +unsigned +QcNlpSolver::nWnConstraints() const +{ + unsigned n = 0; + for (wn_sll el = fWnConstraints; el != 0; el = el->next) + { + if (el->contents) + n++; + } + return n; +} + +#endif + + + +void +QcNlpSolver::AddVar(QcFloat &v) +{ + fVarStow.ensurePresent( v.pointer()); +} + + +void +QcNlpSolver::addVar(QcFloatRep *v) +{ + fVarStow.ensurePresent( v); +} + + +bool +QcNlpSolver::RemoveVar(QcFloat &v) +{ + return fVarStow.tryRemove( v.pointer()); +} + + +bool +QcNlpSolver::removeVar(QcFloatRep *v) +{ + return fVarStow.tryRemove( v); +} + + +bool +QcNlpSolver::IsRegistered(QcFloat const &v) const +{ + return fVarStow.isPresent( v.pointer()); +} + + +bool +QcNlpSolver::isRegistered(QcFloatRep *v) const +{ + return fVarStow.isPresent( v); +} + + +#line 206 "QcNlpSolver.ch" +void +QcNlpSolver::BeginAddConstraint() +{ + QcSolver::BeginAddConstraint(); + fNBatchConstraints = 0; +} + + +bool +QcNlpSolver::EndAddConstraint() +{ + /* TODO: Actually, some of this is handled in QcSolver. */ + qcAssertExternalPre( inBatch()); + if (fNBatchConstraints == 0) + return true; + // fixme: make sure fConstraints is up-to-date. + bool success = isFeasible(); + if (!success) + { + /* fixme: roll back, using wnsll_edel n times, and add to fInconsistent. */ + abort(); + } + dbg( assertConstraintsInvar()); + return success; +} + + + +bool +QcNlpSolver::AddConstraint(QcConstraint &c) +{ + return addConstraint( c.pointer()); +} + + +bool +QcNlpSolver::AddConstraint(QcConstraint &c, QcFloat &hint) +{ + // QcNlpSolver is non-parametric, so we ignore the basic variable hint. + UNUSED( hint); + return addConstraint( c.pointer()); +} + + +#line 259 "QcNlpSolver.ch" +bool +QcNlpSolver::addConstraint(QcConstraintRep *c) +{ + qcAssertExternalPre( c != 0); + qcAssertExternalPre( fConstraints.count( c) == 0); + + /* QcConstraintRep's are user-changeable, so we make a copy. */ + c = new QcConstraintRep( *c); + + refVars( c); + + pair + ins( c, 0); + if (fVarStow.constrCacheValid()) + ins.second = makeAndInsertWnConstraint( c); + pair + res( fConstraints.insert( ins)); + assert( res.second); + + if (inBatch() + || c->isSatisfied() + || isFeasible()) + { +#if qcCheckPost + addCheckedConstraint( c); +#endif + dbg( assertConstraintsInvar()); + return true; + } + else + { + doRemoveConstraint( res.first); + dbg( assertConstraintsInvar()); + return false; + } +} + + +bool +QcNlpSolver::RemoveConstraint(QcConstraint &c) +{ + return removeConstraint( c.pointer()); +} + + +bool +QcNlpSolver::removeConstraint(QcConstraintRep *c) +{ + qcAssertExternalPre( c != 0); + + fConstraints_T::iterator i( fConstraints.find( c)); + if (i == fConstraints.end()) + return false; + +#if qcCheckPost + removeCheckedConstraint( i->first); + /* impl: Reason for putting this first is only so that the c->Counter == 1 + assertion in doRemoveConstraint succeeds. */ +#endif + doRemoveConstraint( i); + + dbg( assertConstraintsInvar()); + return true; +} + + +bool +QcNlpSolver::ChangeConstraint( QcConstraint &c, numT rhs) +{ + return changeConstraint( c.pointer(), rhs); +} + + +bool +QcNlpSolver::changeConstraint( QcConstraintRep *c, numT rhs) +{ + /* TODO: handle inBatch() case. */ + assert( !inBatch()); + fConstraints_T::iterator i( fConstraints.find( c)); + + qcAssertExternalPre( i != fConstraints.end()); + + if (!fVarStow.constrCacheValid()) + fixWnConstraints(); + + QcConstraintRep *qc_c = i->first; + numT old_rhs( qc_c->RHS()); + qc_c->SetRHS( rhs); + assert( i->second != 0); + /* proof: fixWnConstraints call above */ + wn_linear_constraint_type wn_c + = (wn_linear_constraint_type) i->second->contents; + assert( wn_c != 0); + wn_c->rhs = dbl_val( rhs); + + bool success = (qc_c->isSatisfied() + || isFeasible()); + if (success) + { +#if qcCheckPost + changeCheckedConstraint( qc_c, rhs); +#endif + } + else + { + qc_c->SetRHS( old_rhs); + wn_c->rhs = dbl_val( old_rhs); + } + dbg( assertConstraintsInvar()); + return success; +} + + +void +QcNlpSolver::RestSolver() +{ + /* TODO: What's RestSolver supposed to do anyway? */ + return; +} + + + +bool +QcNlpSolver::IsFree(QcFloat const &v) const +{ + return isFree( v.pointer()); +} + + +bool +QcNlpSolver::isFree(QcFloatRep *v) const +{ + qcAssertExternalPre( isRegistered( v)); + + return fVarStow.getUsage( v) == 0; +} + + +bool +QcNlpSolver::IsBasic(QcFloat const &v) const +{ + UNUSED( v); + bad_call("QcNlpSolver::IsBasic"); +} + + +void +QcNlpSolver::BeginEdit() +{ + qcAssertExternalPre( !fIsEditMode); + fIsEditMode = true; +} + + +void +QcNlpSolver::EndEdit() +{ + // Not an assertion, as BeginEdit is optional. + if (!fIsEditMode) + return; + fIsEditMode = false; + + for (QcVarStow::var_iterator i = fVarStow.vars_begin(), + iEnd = fVarStow.vars_end(); + i != iEnd; + i++) + (*i)->RestDesVal(); + + QcSolver::EndEdit(); +} + + + +void +QcNlpSolver::Resolve() +{ + if (!fIsEditMode) + BeginEdit(); + + solveNoRest(); +} + + + +bool +QcNlpSolver::Reset() +{ + solveNoRest(); + restDesVals(); + return true; +} + + + +void +QcNlpSolver::Solve() +{ + solveNoRest(); + restDesVals(); +} + + +void +QcNlpSolver::solveNoRest() +{ + qcAssertExternalPre( !inBatch()); + /* relevance: may simplify things wrt feasibility. We know that the problem + is feasible. */ + + unsigned nVars = fVarStow.size(); + if (nVars == 0) + return; + + if (!fVarStow.fConstrCacheValid) + fixWnConstraints(); + + int result; + { + int const offset_iterations = 15; + wn_nonlinear_constraint_type objective = buildObjective(), + zeroObjective = buildZeroObjective(); + + result = doSolve( objective, offset_iterations); + doSolve( zeroObjective, 1); + + wn_free( zeroObjective); + wn_free( objective); + } + if (result == WN_SUBOPTIMAL) + cerr << "Warning: returning suboptimal solution.\n"; + + commitSolution(); + +#if qcCheckPost + checkSatisfied(); + assertConstraintsInvar(); +#endif +} + + + + + + +void +QcNlpSolver::commitSolution() +{ + double *s = fVarStow.getSolvedValArray(); + for (QcVarStow::var_iterator vi = fVarStow.vars_begin(), + viEnd = fVarStow.vars_end(); + vi != viEnd; + vi++, s++) + { + QcFloatRep *v = *vi; + v->SetValue( numT( *s)); + } +} + + +void +QcNlpSolver::restDesVals() +{ + for (QcVarStow::var_iterator vi = fVarStow.vars_begin(), + viEnd = fVarStow.vars_end(); + vi != viEnd; + vi++) + { + QcFloatRep *v = *vi; + v->RestDesVal(); + } +} + + + +bool +QcNlpSolver::isFeasible() +{ + static wn_nonlinear_constraint_type objective = buildZeroObjective(); + + if (!fVarStow.constrCacheValid()) + fixWnConstraints(); + + int result = doSolve( objective, 1); + if (result != WN_SUCCESS) + cerr << "DBG: isFeasible: doSolve returned " << result << '\n'; + return wnConstraintsSatisfied(); +} + +#ifndef NDEBUG + +bool +QcNlpSolver::wnConstraintsSatisfied() const +{ + qcAssertPre( fVarStow.constrCacheValid()); + double const *solvedVals = fVarStow.getSolvedValArray(); + + for (wn_sll i = fWnConstraints; i != NULL; i = i->next) + { + wn_linear_constraint_type wn_c = (wn_linear_constraint_type) i->contents; + if (wn_c == 0) + continue; + + double balance = wn_c->rhs; + double *w = wn_c->weights; + for (int *vi = wn_c->vars, *viEnd = wn_c->vars + wn_c->size; + vi != viEnd; + vi++, w++) + { + assert( unsigned( *vi) < fVarStow.size()); + balance -= *w * solvedVals[*vi]; + } + + double eps = (1.0 / (1<<27)); + double tst; + switch (wn_c->comparison_type) + { + case WN_EQ_COMPARISON: tst = fabs( balance); break; + case WN_LT_COMPARISON: tst = -balance; break; + case WN_GT_COMPARISON: tst = balance; break; + default: + qcDurchfall( "wn comparison_type"); + } + if (!(tst <= eps)) // i.e. if tst > eps || isNaN(tst) + return false; + } + return true; +} +#endif + + + +#line 595 "QcNlpSolver.ch" +int +QcNlpSolver::doSolve( wn_nonlinear_constraint_type objective, int offset_iterations) +{ + qcAssertPre( fVarStow.constrCacheValid()); + + double solved_val; + int result; + unsigned nVars = fVarStow.size(); + if (nVars == 0) + return WN_SUCCESS; + + trimWnConstraints(); + wn_nlp_conj_method( &result, &solved_val, fVarStow.getSolvedValArray(), + 0, objective, + fWnConstraints, nVars, + 0x7fffffff /* conj_iterations */, + offset_iterations, + 1.0); + /* Increasing conj_iterations reduces the chance of having WN_SUBOPTIMAL + returned. */ + assert( result != WN_UNBOUNDED); + /* proof (assumes wn_nlp behaves like an exact solver): goal fn is positive + semi-definite, and ∀[i] there are no first-order terms in x_i unless + there is also a second-order term in x_i. */ + + return result; +} + + + +static int +qc2wn_relation(QcConstraintRep const *c) +{ + switch(c->getRelation()) + { + case QcConstraintRep::coEQ: + return WN_EQ_COMPARISON; + + case QcConstraintRep::coLE: + case QcConstraintRep::coLT: + return WN_LT_COMPARISON; + + case QcConstraintRep::coGE: + case QcConstraintRep::coGT: + return WN_GT_COMPARISON; + } + + qcDurchfall( "constraint relation"); +} + + + +typedef hash_map fConstraints_T; + + + +void +QcNlpSolver::doRemoveConstraint( QcNlpSolver::fConstraints_T::iterator i) +{ + /* The user could have changed c since it was added; we must use the version + that we added. */ + QcConstraintRep *c = i->first; + wn_sll el = i->second; + if (el != 0) + { + assert( el->contents != 0); + wn_free( el->contents); + el->contents = 0; + /* impl: We don't yet actually delete the sll element because we don't + have the address of what points to this element (whether the previous + `next' pointer or fWnConstraints). And we can't just copy in the next + element, because we'd need to update the hash table entry that points + to that next element. So instead the element continues to exist until + the next trimWnConstraints call. */ + } + + derefVars( c); + + fConstraints.erase( i); + assert( c->Counter() == 1); + delete( c); +} + + + +void +QcNlpSolver::refVars(QcConstraintRep const *c) +{ + QcLinPoly::TTermsVector const &terms = c->LinPoly().GetTerms(); + for (QcLinPoly::TTermsVector::const_iterator ti = terms.abegin(), + tiEnd = terms.aend(); + ti != tiEnd; + ti++) + { + QcFloatRep *v = (*ti)->getVariable(); + fVarStow.addReference( v); + } +} + + + +void +QcNlpSolver::derefVars(QcConstraintRep const *c) +{ + QcLinPoly::TTermsVector const &terms = c->LinPoly().GetTerms(); + for (QcLinPoly::TTermsVector::const_iterator ti = terms.abegin(), + tiEnd = terms.aend(); + ti != tiEnd; + ti++) + { + QcFloatRep *v = (*ti)->getVariable(); + fVarStow.decUsage( v); + } +} + + +void +QcNlpSolver::fixWnConstraints() +{ + for (fConstraints_T::iterator + i( fConstraints.begin()), iEnd( fConstraints.end()); + i != iEnd; i++) + { + QcConstraintRep *c = i->first; + wn_sll el = i->second; + if (el == 0) + i->second = makeAndInsertWnConstraint( c); + else + fixWnConstraint( c, (wn_linear_constraint_type) el->contents); + } + fVarStow.fConstrCacheValid = true; +} + + +wn_sll +QcNlpSolver::makeAndInsertWnConstraint(QcConstraintRep *c) +{ + wn_linear_constraint_type wn_c; + unsigned cNVars = c->getNVars(); + wn_make_linear_constraint( &wn_c, cNVars, c->RHS(), + qc2wn_relation( c)); + assert( wn_c != 0); + + { + int *wn_v = wn_c->vars; + double *wn_w = wn_c->weights; + QcLinPoly::TTermsVector const &terms = c->LinPoly().GetTerms(); + for (QcLinPoly::TTermsVector::const_iterator ti = terms.abegin(), + tiEnd = terms.aend(); + ti != tiEnd; + ti++, wn_v++, wn_w++) + { + assert( unsigned( wn_v - wn_c->vars) < unsigned( wn_c->size)); + *wn_v = fVarStow.getVarIx( (*ti)->getVariable()); + + assert( wn_w - wn_c->weights + == wn_v - wn_c->vars); + *wn_w = dbl_val( (*ti)->GetCoeff()); + } + } + + wn_sllins( &fWnConstraints, wn_c); + + return fWnConstraints; +} + + +void +QcNlpSolver::fixWnConstraint(QcConstraintRep *c, wn_linear_constraint_type wn_c) +{ + qcAssertPre( wn_c != 0); + + int *wn_v = wn_c->vars; + QcLinPoly::TTermsVector const &terms = c->LinPoly().GetTerms(); + for (QcLinPoly::TTermsVector::const_iterator ti = terms.abegin(), + tiEnd = terms.aend(); + ti != tiEnd; + ti++, wn_v++) + { + assert( unsigned( wn_v - wn_c->vars) < unsigned( wn_c->size)); + *wn_v = fVarStow.getVarIx( (*ti)->getVariable()); + } +} + +#ifndef NDEBUG + +bool +QcNlpSolver::sameConstraint(wn_linear_constraint_type wn_c, QcConstraintRep const *c) const +{ + qcAssertPre( wn_c != 0); + qcAssertPre( c != 0); + + unsigned cNVars = c->getNVars(); + if ((unsigned( wn_c->size) != cNVars) + || (wn_c->comparison_type != qc2wn_relation( c)) + || (wn_c->rhs != dbl_val( c->RHS()))) + return false; + + + { + int const *wn_v = wn_c->vars; + double const *wn_w = wn_c->weights; + QcLinPoly::TTermsVector const &terms = c->LinPoly().GetTerms(); + for (QcLinPoly::TTermsVector::const_iterator ti = terms.abegin(), + tiEnd = terms.aend(); + ti != tiEnd; + ti++, wn_v++, wn_w++) + { + assert( unsigned( wn_v - wn_c->vars) < unsigned( wn_c->size)); + if (unsigned( *wn_v) != fVarStow.getVarIx( (*ti)->getVariable())) + return false; + + assert( wn_w - wn_c->weights + == wn_v - wn_c->vars); + if (*wn_w != dbl_val( (*ti)->GetCoeff())) + return false; + } + } + return true; +} +#endif + + +void +QcNlpSolver::trimWnConstraints() +{ + wn_sll *pptr = &fWnConstraints; + for (wn_sll el = fWnConstraints; el != 0; el = el->next) + { + if (el->contents) + { + assert( *pptr == el); + pptr = &el->next; + } + else + *pptr = el->next; + } + +#ifdef qcCheckInternalPost + for (wn_sll el = fWnConstraints; el != 0; el = el->next) + assert( el->contents); +#endif +} + + +static double const scale = 1.0 / (1L << 30); + +double +goalFnVal(int size, double *values, ptr varStowPtr) +{ + QcVarStow *varStow = (QcVarStow *) varStowPtr; + double ret = 0.0; + /* effic: Check if this function's return value actually matters. + It's probably safe to return zero. */ + QcVarStow::var_const_iterator vi = varStow->vars_begin(), + viEnd = varStow->vars_end(); + assert( viEnd - vi == size); + for(; vi != viEnd; vi++, values++) + { + QcFloatRep *v = *vi; + double err = *values - dbl_val( v->DesireValue()); + ret += dbl_val( v->Weight()) * err * err; + } + + assert( !(ret < 0.0)); + // not the same as `ret >= 0.0': ret may be NaN + // (unless SuggestValue asserts against that). + + return ret * scale; +} + +void +goalFnGradient(double *grad, int size, double *values, ptr varStowPtr) +{ + QcVarStow *varStow = (QcVarStow *) varStowPtr; + QcVarStow::var_const_iterator vi = varStow->vars_begin(), + viEnd = varStow->vars_end(); + assert( viEnd - vi == size); + for(; vi != viEnd; + vi++, values++, grad++) + { + QcFloatRep *v = *vi; + double err = *values - dbl_val( v->DesireValue()); + *grad = 2.0 * dbl_val( v->Weight()) * err * scale; + } +} + + + +wn_nonlinear_constraint_type +QcNlpSolver::buildObjective() +{ + wn_nonlinear_constraint_type obj; + + wn_make_nonlinear_constraint( &obj, fVarStow.size(), WN_EQ_COMPARISON); + for (int i = fVarStow.size(); --i >= 0;) + obj->vars[i] = i; + obj->offset = 0.0; // make sure not NaN or infinite. + obj->client_data = (ptr) &fVarStow; + obj->pfunction = goalFnVal; + obj->pgradient = goalFnGradient; + return obj; +} + + +wn_nonlinear_constraint_type +QcNlpSolver::buildZeroObjective() +{ + wn_linear_constraint_type obj; + + wn_make_linear_constraint( &obj, 0, 0.0, WN_EQ_COMPARISON); + return (wn_nonlinear_constraint_type) obj; +} + + +#line 920 "QcNlpSolver.ch" +#else /* !QC_USING_NLPSOLVER */ +// Make the linker happy. + + +void +QcNlpSolver_dummy() +{ +} + +#endif /* !QC_USING_NLPSOLVER */ + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcNlpSolver.ch b/src/kits/interface/qoca/QcNlpSolver.ch new file mode 100644 index 0000000000..76315b358b --- /dev/null +++ b/src/kits/interface/qoca/QcNlpSolver.ch @@ -0,0 +1,938 @@ +//o[d] #include +#ifdef QC_USING_NLPSOLVER +//begin o[d] +#include +#include +#include +extern "C" { +#include +#include +#include +} +#undef bool +//end o[d] +//begin o[ci] +#include +//end o[ci] +//begin o[c] +#include +//end o[c] + +/* TODO: For every var added, check if it is restricted; if it is, then add an + explicit constraint. */ + +/** A solver suitable for non-linear constraints. The constraints should + be continuous and differentiable. + +

Currently only linear constraints are implemented :-) but adding + non-linear constraints should be little work; mainly just creating the + non-linear constraint object (see buildObjective for how this is + done) and adding it to the fWnConstraints singly-linked list; + though there'll also be a bit of fiddling to allow removeConstraint + and changeConstraint to work. + +

Improvements: +

    + +
  • Obviously linear constraints ought to be handled differently. At + least linear equality constraints should be handled by elimination. + Probably inequalities can be handled the same way, once the active set has + been determined. + +

  • The line search in the underlying unconstrained problem is currently + done with a golden section search. Should probably solve a (sequence of) + Taylor approximation(s) if the functions are polynomials. (It's OK for the + line search to consider only the section of the barrier function that + applies at the start of the line search... hmm, need to consider the + start-in-flat-section case.) + +

  • Currently doSolve makes a feasibility step (ignoring the + goal function) immediately after solving. This is obviously suboptimal: it + will tend to lose optimality. However, without that step, we often had + infeasible "solutions" returned. Maybe should reduce the scale of the + [user] goal function with each iteration, as well as or instead of the + current barrier offset method. + +

    Could experiment with "big-M" arithmetic: use an explicit (symbolic) + big-M to represent the ratio between the weight of the constraints and the + weight of the user goal function. This means that only a single call to the + underlying unconstrained optimizer is needed, at the cost of doing numerical + operations in a quasi-symbolic form. The number representation might be + {int power_of_bigM_in_first_term; double term_coeffs[];}. One + problem is when to decide that the high-order term should be considered + zero. + +

+ +**/ +//ho class QcNlpSolver +//ho : public QcSolver +//ho { +//ho public: + +//cf +QcNlpSolver() + : QcSolver(), + fVarStow(), + fConstraints(), + fWnConstraints( 0), + fIsEditMode( false) +{ +} + +//cf +QcNlpSolver(unsigned hintNumConstraints, unsigned hintNumVariables) + : QcSolver(), + fVarStow(), + fConstraints(), + fWnConstraints( 0), + fIsEditMode( false) +{ + UNUSED( hintNumConstraints); + UNUSED( hintNumVariables); + // effic: resize fVarStow, fConstraints. +} + +//begin ho +virtual ~QcNlpSolver() +{ +} +//end ho + +#ifndef NDEBUG +//cf +void +assertInvar() const +{ + /* TODO: assert(∀[c ∈ constraints] + ∀[v ∈ c.LinPoly()] + fVarStow.varPresent( v) + ∧ (fVarStow.getUsage(v) is correct) */ +} + +//cf +void +assertConstraintsInvar() const +{ + assert( !fVarStow.constrCacheValid() + || (nWnConstraints() == checkedConstraints_size())); + assert( fConstraints.size() == checkedConstraints_size()); + + for (vector::const_iterator ci = checkedConstraints_abegin(), + ciEnd = checkedConstraints_aend(); + ci != ciEnd; ci++) + { + QcConstraintRep *cc = *ci; + fConstraints_T::const_iterator p = fConstraints.find( cc); + assert( p != fConstraints.end()); + if (fVarStow.constrCacheValid()) + { + wn_sll el = p->second; + assert( el != 0); + wn_linear_constraint_type wn_c + = (wn_linear_constraint_type) el->contents; + assert( wn_c != 0); + assert( sameConstraint( wn_c, cc)); + } + } +} + +//cf +unsigned +nWnConstraints() const +{ + unsigned n = 0; + for (wn_sll el = fWnConstraints; el != 0; el = el->next) + { + if (el->contents) + n++; + } + return n; +} + +#endif + + +//cf +virtual void +AddVar(QcFloat &v) +{ + fVarStow.ensurePresent( v.pointer()); +} + +//cf +void +addVar(QcFloatRep *v) +{ + fVarStow.ensurePresent( v); +} + +//cf +virtual bool +RemoveVar(QcFloat &v) +{ + return fVarStow.tryRemove( v.pointer()); +} + +//cf +bool +removeVar(QcFloatRep *v) +{ + return fVarStow.tryRemove( v); +} + +//cf +virtual bool +IsRegistered(QcFloat const &v) const +{ + return fVarStow.isPresent( v.pointer()); +} + +//cf +bool +isRegistered(QcFloatRep *v) const +{ + return fVarStow.isPresent( v); +} + +/** Begin a sequence of constraint operations. The changes are not necessarily + applied until the corresponding EndAddConstraint call. + +

Batches are not (currently) nestable. + + @precondition !isInBatchMode() +**/ +//cf +virtual void +BeginAddConstraint() +{ + QcSolver::BeginAddConstraint(); + fNBatchConstraints = 0; +} + +//cf +virtual bool +EndAddConstraint() +{ + /* TODO: Actually, some of this is handled in QcSolver. */ + qcAssertExternalPre( inBatch()); + if (fNBatchConstraints == 0) + return true; + // fixme: make sure fConstraints is up-to-date. + bool success = isFeasible(); + if (!success) + { + /* fixme: roll back, using wnsll_edel n times, and add to fInconsistent. */ + abort(); + } + dbg( assertConstraintsInvar()); + return success; +} + + +//cf +virtual bool +AddConstraint(QcConstraint &c) +{ + return addConstraint( c.pointer()); +} + +//cf +virtual bool +AddConstraint(QcConstraint &c, QcFloat &hint) +{ + // QcNlpSolver is non-parametric, so we ignore the basic variable hint. + UNUSED( hint); + return addConstraint( c.pointer()); +} + +/** @precondition c != 0 + + @precondition c (i.e. something returning the same + Id() as c; values of LHS and RHS are irrelevant) is not + already present. + + @postcondition All vars in c.LinPoly() are registered with this + solver, with fVarStow.getUsage(v) incremented by 1. +**/ +//cf +bool +addConstraint(QcConstraintRep *c) +{ + qcAssertExternalPre( c != 0); + qcAssertExternalPre( fConstraints.count( c) == 0); + + /* QcConstraintRep's are user-changeable, so we make a copy. */ + c = new QcConstraintRep( *c); + + refVars( c); + + pair + ins( c, 0); + if (fVarStow.constrCacheValid()) + ins.second = makeAndInsertWnConstraint( c); + pair + res( fConstraints.insert( ins)); + assert( res.second); + + if (inBatch() + || c->isSatisfied() + || isFeasible()) + { +#if qcCheckPost + addCheckedConstraint( c); +#endif + dbg( assertConstraintsInvar()); + return true; + } + else + { + doRemoveConstraint( res.first); + dbg( assertConstraintsInvar()); + return false; + } +} + +//cf +virtual bool +RemoveConstraint(QcConstraint &c) +{ + return removeConstraint( c.pointer()); +} + +//cf +bool +removeConstraint(QcConstraintRep *c) +{ + qcAssertExternalPre( c != 0); + + fConstraints_T::iterator i( fConstraints.find( c)); + if (i == fConstraints.end()) + return false; + +#if qcCheckPost + removeCheckedConstraint( i->first); + /* impl: Reason for putting this first is only so that the c->Counter == 1 + assertion in doRemoveConstraint succeeds. */ +#endif + doRemoveConstraint( i); + + dbg( assertConstraintsInvar()); + return true; +} + +//cf +virtual bool +ChangeConstraint( QcConstraint &c, numT rhs) +{ + return changeConstraint( c.pointer(), rhs); +} + +//cf +bool +changeConstraint( QcConstraintRep *c, numT rhs) +{ + /* TODO: handle inBatch() case. */ + assert( !inBatch()); + fConstraints_T::iterator i( fConstraints.find( c)); + + qcAssertExternalPre( i != fConstraints.end()); + + if (!fVarStow.constrCacheValid()) + fixWnConstraints(); + + QcConstraintRep *qc_c = i->first; + numT old_rhs( qc_c->RHS()); + qc_c->SetRHS( rhs); + assert( i->second != 0); + /* proof: fixWnConstraints call above */ + wn_linear_constraint_type wn_c + = (wn_linear_constraint_type) i->second->contents; + assert( wn_c != 0); + wn_c->rhs = dbl_val( rhs); + + bool success = (qc_c->isSatisfied() + || isFeasible()); + if (success) + { +#if qcCheckPost + changeCheckedConstraint( qc_c, rhs); +#endif + } + else + { + qc_c->SetRHS( old_rhs); + wn_c->rhs = dbl_val( old_rhs); + } + dbg( assertConstraintsInvar()); + return success; +} + +//cf +virtual void +RestSolver() +{ + /* TODO: What's RestSolver supposed to do anyway? */ + return; +} + + +//cf +virtual bool +IsFree(QcFloat const &v) const +{ + return isFree( v.pointer()); +} + +//cf +bool +isFree(QcFloatRep *v) const +{ + qcAssertExternalPre( isRegistered( v)); + + return fVarStow.getUsage( v) == 0; +} + +//cf +virtual bool +IsBasic(QcFloat const &v) const +{ + UNUSED( v); + bad_call("QcNlpSolver::IsBasic"); +} + +//cf +virtual void +BeginEdit() +{ + qcAssertExternalPre( !fIsEditMode); + fIsEditMode = true; +} + +//cf +virtual void +EndEdit() +{ + // Not an assertion, as BeginEdit is optional. + if (!fIsEditMode) + return; + fIsEditMode = false; + + for (QcVarStow::var_iterator i = fVarStow.vars_begin(), + iEnd = fVarStow.vars_end(); + i != iEnd; + i++) + (*i)->RestDesVal(); + + QcSolver::EndEdit(); +} + + +//cf +virtual void +Resolve() +{ + if (!fIsEditMode) + BeginEdit(); + + solveNoRest(); +} + + +//cf +virtual bool +Reset() +{ + solveNoRest(); + restDesVals(); + return true; +} + + +//cf +virtual void +Solve() +{ + solveNoRest(); + restDesVals(); +} + +//cf +void +solveNoRest() +{ + qcAssertExternalPre( !inBatch()); + /* relevance: may simplify things wrt feasibility. We know that the problem + is feasible. */ + + unsigned nVars = fVarStow.size(); + if (nVars == 0) + return; + + if (!fVarStow.fConstrCacheValid) + fixWnConstraints(); + + int result; + { + int const offset_iterations = 15; + wn_nonlinear_constraint_type objective = buildObjective(), + zeroObjective = buildZeroObjective(); + + result = doSolve( objective, offset_iterations); + doSolve( zeroObjective, 1); + + wn_free( zeroObjective); + wn_free( objective); + } + if (result == WN_SUBOPTIMAL) + cerr << "Warning: returning suboptimal solution.\n"; + + commitSolution(); + +#if qcCheckPost + checkSatisfied(); + assertConstraintsInvar(); +#endif +} + + + +//ho private: + +//cf +void +commitSolution() +{ + double *s = fVarStow.getSolvedValArray(); + for (QcVarStow::var_iterator vi = fVarStow.vars_begin(), + viEnd = fVarStow.vars_end(); + vi != viEnd; + vi++, s++) + { + QcFloatRep *v = *vi; + v->SetValue( numT( *s)); + } +} + +//cf +void +restDesVals() +{ + for (QcVarStow::var_iterator vi = fVarStow.vars_begin(), + viEnd = fVarStow.vars_end(); + vi != viEnd; + vi++) + { + QcFloatRep *v = *vi; + v->RestDesVal(); + } +} + + +//cf +bool +isFeasible() +{ + static wn_nonlinear_constraint_type objective = buildZeroObjective(); + + if (!fVarStow.constrCacheValid()) + fixWnConstraints(); + + int result = doSolve( objective, 1); + if (result != WN_SUCCESS) + cerr << "DBG: isFeasible: doSolve returned " << result << '\n'; + return wnConstraintsSatisfied(); +} + +#ifndef NDEBUG +//cf +bool +wnConstraintsSatisfied() const +{ + qcAssertPre( fVarStow.constrCacheValid()); + double const *solvedVals = fVarStow.getSolvedValArray(); + + for (wn_sll i = fWnConstraints; i != NULL; i = i->next) + { + wn_linear_constraint_type wn_c = (wn_linear_constraint_type) i->contents; + if (wn_c == 0) + continue; + + double balance = wn_c->rhs; + double *w = wn_c->weights; + for (int *vi = wn_c->vars, *viEnd = wn_c->vars + wn_c->size; + vi != viEnd; + vi++, w++) + { + assert( unsigned( *vi) < fVarStow.size()); + balance -= *w * solvedVals[*vi]; + } + + double eps = (1.0 / (1<<27)); + double tst; + switch (wn_c->comparison_type) + { + case WN_EQ_COMPARISON: tst = fabs( balance); break; + case WN_LT_COMPARISON: tst = -balance; break; + case WN_GT_COMPARISON: tst = balance; break; + default: + qcDurchfall( "wn comparison_type"); + } + if (!(tst <= eps)) // i.e. if tst > eps || isNaN(tst) + return false; + } + return true; +} +#endif + + +/** Solve fWnConstraints, storing the results only in + fVarStow.getSolvedValArray(). Ignores fConstraints. + + @precondition fVarStow.constrCacheValid() +**/ +//cf +int +doSolve( wn_nonlinear_constraint_type objective, int offset_iterations) +{ + qcAssertPre( fVarStow.constrCacheValid()); + + double solved_val; + int result; + unsigned nVars = fVarStow.size(); + if (nVars == 0) + return WN_SUCCESS; + + trimWnConstraints(); + wn_nlp_conj_method( &result, &solved_val, fVarStow.getSolvedValArray(), + 0, objective, + fWnConstraints, nVars, + 0x7fffffff /* conj_iterations */, + offset_iterations, + 1.0); + /* Increasing conj_iterations reduces the chance of having WN_SUBOPTIMAL + returned. */ + assert( result != WN_UNBOUNDED); + /* proof (assumes wn_nlp behaves like an exact solver): goal fn is positive + semi-definite, and ∀[i] there are no first-order terms in x_i unless + there is also a second-order term in x_i. */ + + return result; +} + + +//begin o[c] +static int +qc2wn_relation(QcConstraintRep const *c) +{ + switch(c->getRelation()) + { + case QcConstraintRep::coEQ: + return WN_EQ_COMPARISON; + + case QcConstraintRep::coLE: + case QcConstraintRep::coLT: + return WN_LT_COMPARISON; + + case QcConstraintRep::coGE: + case QcConstraintRep::coGT: + return WN_GT_COMPARISON; + } + + qcDurchfall( "constraint relation"); +} +//end o[c] + + +typedef hash_map fConstraints_T; + + +//cf +void +doRemoveConstraint( QcNlpSolver::fConstraints_T::iterator i) +{ + /* The user could have changed c since it was added; we must use the version + that we added. */ + QcConstraintRep *c = i->first; + wn_sll el = i->second; + if (el != 0) + { + assert( el->contents != 0); + wn_free( el->contents); + el->contents = 0; + /* impl: We don't yet actually delete the sll element because we don't + have the address of what points to this element (whether the previous + `next' pointer or fWnConstraints). And we can't just copy in the next + element, because we'd need to update the hash table entry that points + to that next element. So instead the element continues to exist until + the next trimWnConstraints call. */ + } + + derefVars( c); + + fConstraints.erase( i); + assert( c->Counter() == 1); + delete( c); +} + + +//cf +void +refVars(QcConstraintRep const *c) +{ + QcLinPoly::TTermsVector const &terms = c->LinPoly().GetTerms(); + for (QcLinPoly::TTermsVector::const_iterator ti = terms.abegin(), + tiEnd = terms.aend(); + ti != tiEnd; + ti++) + { + QcFloatRep *v = (*ti)->getVariable(); + fVarStow.addReference( v); + } +} + +/** Decrement variable usage counts (reversing refVars). */ +//cf +void +derefVars(QcConstraintRep const *c) +{ + QcLinPoly::TTermsVector const &terms = c->LinPoly().GetTerms(); + for (QcLinPoly::TTermsVector::const_iterator ti = terms.abegin(), + tiEnd = terms.aend(); + ti != tiEnd; + ti++) + { + QcFloatRep *v = (*ti)->getVariable(); + fVarStow.decUsage( v); + } +} + +//cf +void +fixWnConstraints() +{ + for (fConstraints_T::iterator + i( fConstraints.begin()), iEnd( fConstraints.end()); + i != iEnd; i++) + { + QcConstraintRep *c = i->first; + wn_sll el = i->second; + if (el == 0) + i->second = makeAndInsertWnConstraint( c); + else + fixWnConstraint( c, (wn_linear_constraint_type) el->contents); + } + fVarStow.fConstrCacheValid = true; +} + +//cf +wn_sll +makeAndInsertWnConstraint(QcConstraintRep *c) +{ + wn_linear_constraint_type wn_c; + unsigned cNVars = c->getNVars(); + wn_make_linear_constraint( &wn_c, cNVars, c->RHS(), + qc2wn_relation( c)); + assert( wn_c != 0); + + { + int *wn_v = wn_c->vars; + double *wn_w = wn_c->weights; + QcLinPoly::TTermsVector const &terms = c->LinPoly().GetTerms(); + for (QcLinPoly::TTermsVector::const_iterator ti = terms.abegin(), + tiEnd = terms.aend(); + ti != tiEnd; + ti++, wn_v++, wn_w++) + { + assert( unsigned( wn_v - wn_c->vars) < unsigned( wn_c->size)); + *wn_v = fVarStow.getVarIx( (*ti)->getVariable()); + + assert( wn_w - wn_c->weights + == wn_v - wn_c->vars); + *wn_w = dbl_val( (*ti)->GetCoeff()); + } + } + + wn_sllins( &fWnConstraints, wn_c); + + return fWnConstraints; +} + +//cf +void +fixWnConstraint(QcConstraintRep *c, wn_linear_constraint_type wn_c) +{ + qcAssertPre( wn_c != 0); + + int *wn_v = wn_c->vars; + QcLinPoly::TTermsVector const &terms = c->LinPoly().GetTerms(); + for (QcLinPoly::TTermsVector::const_iterator ti = terms.abegin(), + tiEnd = terms.aend(); + ti != tiEnd; + ti++, wn_v++) + { + assert( unsigned( wn_v - wn_c->vars) < unsigned( wn_c->size)); + *wn_v = fVarStow.getVarIx( (*ti)->getVariable()); + } +} + +#ifndef NDEBUG +//cf +bool +sameConstraint(wn_linear_constraint_type wn_c, QcConstraintRep const *c) const +{ + qcAssertPre( wn_c != 0); + qcAssertPre( c != 0); + + unsigned cNVars = c->getNVars(); + if ((unsigned( wn_c->size) != cNVars) + || (wn_c->comparison_type != qc2wn_relation( c)) + || (wn_c->rhs != dbl_val( c->RHS()))) + return false; + + + { + int const *wn_v = wn_c->vars; + double const *wn_w = wn_c->weights; + QcLinPoly::TTermsVector const &terms = c->LinPoly().GetTerms(); + for (QcLinPoly::TTermsVector::const_iterator ti = terms.abegin(), + tiEnd = terms.aend(); + ti != tiEnd; + ti++, wn_v++, wn_w++) + { + assert( unsigned( wn_v - wn_c->vars) < unsigned( wn_c->size)); + if (unsigned( *wn_v) != fVarStow.getVarIx( (*ti)->getVariable())) + return false; + + assert( wn_w - wn_c->weights + == wn_v - wn_c->vars); + if (*wn_w != dbl_val( (*ti)->GetCoeff())) + return false; + } + } + return true; +} +#endif + +//cf +void +trimWnConstraints() +{ + wn_sll *pptr = &fWnConstraints; + for (wn_sll el = fWnConstraints; el != 0; el = el->next) + { + if (el->contents) + { + assert( *pptr == el); + pptr = &el->next; + } + else + *pptr = el->next; + } + +#ifdef qcCheckInternalPost + for (wn_sll el = fWnConstraints; el != 0; el = el->next) + assert( el->contents); +#endif +} + +//begin o[c] +static double const scale = 1.0 / (1L << 30); + +double +goalFnVal(int size, double *values, ptr varStowPtr) +{ + QcVarStow *varStow = (QcVarStow *) varStowPtr; + double ret = 0.0; + /* effic: Check if this function's return value actually matters. + It's probably safe to return zero. */ + QcVarStow::var_const_iterator vi = varStow->vars_begin(), + viEnd = varStow->vars_end(); + assert( viEnd - vi == size); + for(; vi != viEnd; vi++, values++) + { + QcFloatRep *v = *vi; + double err = *values - dbl_val( v->DesireValue()); + ret += dbl_val( v->Weight()) * err * err; + } + + assert( !(ret < 0.0)); + // not the same as `ret >= 0.0': ret may be NaN + // (unless SuggestValue asserts against that). + + return ret * scale; +} + +void +goalFnGradient(double *grad, int size, double *values, ptr varStowPtr) +{ + QcVarStow *varStow = (QcVarStow *) varStowPtr; + QcVarStow::var_const_iterator vi = varStow->vars_begin(), + viEnd = varStow->vars_end(); + assert( viEnd - vi == size); + for(; vi != viEnd; + vi++, values++, grad++) + { + QcFloatRep *v = *vi; + double err = *values - dbl_val( v->DesireValue()); + *grad = 2.0 * dbl_val( v->Weight()) * err * scale; + } +} +//end o[c] + +//cf +wn_nonlinear_constraint_type +buildObjective() +{ + wn_nonlinear_constraint_type obj; + + wn_make_nonlinear_constraint( &obj, fVarStow.size(), WN_EQ_COMPARISON); + for (int i = fVarStow.size(); --i >= 0;) + obj->vars[i] = i; + obj->offset = 0.0; // make sure not NaN or infinite. + obj->client_data = (ptr) &fVarStow; + obj->pfunction = goalFnVal; + obj->pgradient = goalFnGradient; + return obj; +} + +//cf +wn_nonlinear_constraint_type +buildZeroObjective() +{ + wn_linear_constraint_type obj; + + wn_make_linear_constraint( &obj, 0, 0.0, WN_EQ_COMPARISON); + return (wn_nonlinear_constraint_type) obj; +} + +//begin ho +private: +QcVarStow fVarStow; +unsigned fNBatchConstraints; +fConstraints_T fConstraints; +wn_sll fWnConstraints; +bool fIsEditMode; +//end ho +//ho }; + +#else /* !QC_USING_NLPSOLVER */ +// Make the linker happy. +//$class_prefix= +//cf +void +QcNlpSolver_dummy() +{ +} + +#endif /* !QC_USING_NLPSOLVER */ + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcNlpSolver.hh b/src/kits/interface/qoca/QcNlpSolver.hh new file mode 100644 index 0000000000..8d3cf20e77 --- /dev/null +++ b/src/kits/interface/qoca/QcNlpSolver.hh @@ -0,0 +1,64 @@ +// Generated automatically from QcNlpSolver.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcNlpSolver.H" +#ifndef QcNlpSolverIFN +#define QcNlpSolverIFN +#line 1 "QcNlpSolver.ch" + +#ifdef QC_USING_NLPSOLVER + +#line 15 "QcNlpSolver.ch" +#include + + +#line 21 "QcNlpSolver.ch" +/* TODO: For every var added, check if it is restricted; if it is, then add an + explicit constraint. */ + + +#line 102 "QcNlpSolver.ch" +#ifndef NDEBUG + +#line 153 "QcNlpSolver.ch" +#endif + + + +#line 547 "QcNlpSolver.ch" +#ifndef NDEBUG + +#line 586 "QcNlpSolver.ch" +#endif + + + +#line 647 "QcNlpSolver.ch" +typedef hash_map fConstraints_T; + + + +#line 780 "QcNlpSolver.ch" +#ifndef NDEBUG + +#line 816 "QcNlpSolver.ch" +#endif + + +#line 920 "QcNlpSolver.ch" +#else /* !QC_USING_NLPSOLVER */ +// Make the linker happy. + + +#line 929 "QcNlpSolver.ch" +#endif /* !QC_USING_NLPSOLVER */ + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcNlpSolverIFN */ diff --git a/src/kits/interface/qoca/QcNomadicFloatRep.H b/src/kits/interface/qoca/QcNomadicFloatRep.H new file mode 100644 index 0000000000..0c87df4fd7 --- /dev/null +++ b/src/kits/interface/qoca/QcNomadicFloatRep.H @@ -0,0 +1,80 @@ +// Generated automatically from QcNomadicFloatRep.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcNomadicFloatRepDCL +#define QcNomadicFloatRepDCL +#line 1 "QcNomadicFloatRep.ch" +// $Id: QcNomadicFloatRep.ch,v 1.7 2000/12/12 09:59:27 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include + + +#define qcDefaultStayWeight 1.0 +#define qcDefaultEditWeight 10000.0 + +class QcNomadicFloatRep + : public QcFloatRep +{ +public: + + +//-----------------------------------------------------------------------// +// Constructor // +//-----------------------------------------------------------------------// +QcNomadicFloatRep (bool restricted) + : QcFloatRep ("", 0.0, qcDefaultStayWeight, qcDefaultEditWeight, restricted) { } +QcNomadicFloatRep (const char *name, bool restricted) + : QcFloatRep (name, 0.0, qcDefaultStayWeight, qcDefaultEditWeight, restricted) { } +QcNomadicFloatRep(const char *name, numT desval, bool restricted) + : QcFloatRep (name, desval, qcDefaultStayWeight, qcDefaultEditWeight, restricted) { } +QcNomadicFloatRep(const char *name, numT desval, numT sw, numT ew, bool restricted) + : QcFloatRep (name, desval, sw, ew, restricted) { } + + +//-----------------------------------------------------------------------// +// Manipulatiom functions. // +//-----------------------------------------------------------------------// + +virtual bool RestDesVal_changed(); +#line 65 "QcNomadicFloatRep.ch" +virtual void RestDesVal(); +#line 71 "QcNomadicFloatRep.ch" +virtual void SetToEditWeight(); +#line 77 "QcNomadicFloatRep.ch" +virtual void SetToStayWeight(); +#line 82 "QcNomadicFloatRep.ch" +}; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcNomadicFloatRepDCL */ diff --git a/src/kits/interface/qoca/QcNomadicFloatRep.cc b/src/kits/interface/qoca/QcNomadicFloatRep.cc new file mode 100644 index 0000000000..777dccc58a --- /dev/null +++ b/src/kits/interface/qoca/QcNomadicFloatRep.cc @@ -0,0 +1,82 @@ +// Generated automatically from QcNomadicFloatRep.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcNomadicFloatRep.hh" +#line 1 "QcNomadicFloatRep.ch" +// $Id: QcNomadicFloatRep.ch,v 1.7 2000/12/12 09:59:27 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include + + + +#define qcDefaultStayWeight 1.0 +#define qcDefaultEditWeight 10000.0 + + + + + + + +#line 53 "QcNomadicFloatRep.ch" +//-----------------------------------------------------------------------// +// Manipulatiom functions. // +//-----------------------------------------------------------------------// + +bool QcNomadicFloatRep::RestDesVal_changed() +{ + bool changed = fDesireValue != fValue; + fDesireValue = fValue; + return changed; +} + + +void QcNomadicFloatRep::RestDesVal() +{ + fDesireValue = fValue; +} + + +void QcNomadicFloatRep::SetToEditWeight() +{ + fWeight = EditWeight(); +} + + +void QcNomadicFloatRep::SetToStayWeight() +{ + fWeight = StayWeight(); +} + + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcNomadicFloatRep.ch b/src/kits/interface/qoca/QcNomadicFloatRep.ch new file mode 100644 index 0000000000..4f55d20a6c --- /dev/null +++ b/src/kits/interface/qoca/QcNomadicFloatRep.ch @@ -0,0 +1,91 @@ +// $Id: QcNomadicFloatRep.ch,v 1.7 2000/12/12 09:59:27 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +//o[d] #include +//o[i] #include + +#define qcDefaultStayWeight 1.0 +#define qcDefaultEditWeight 10000.0 + +//ho class QcNomadicFloatRep +//ho : public QcFloatRep +//ho { +//ho public: + +//begin ho +//-----------------------------------------------------------------------// +// Constructor // +//-----------------------------------------------------------------------// +QcNomadicFloatRep (bool restricted) + : QcFloatRep ("", 0.0, qcDefaultStayWeight, qcDefaultEditWeight, restricted) { } +QcNomadicFloatRep (const char *name, bool restricted) + : QcFloatRep (name, 0.0, qcDefaultStayWeight, qcDefaultEditWeight, restricted) { } +QcNomadicFloatRep(const char *name, numT desval, bool restricted) + : QcFloatRep (name, desval, qcDefaultStayWeight, qcDefaultEditWeight, restricted) { } +QcNomadicFloatRep(const char *name, numT desval, numT sw, numT ew, bool restricted) + : QcFloatRep (name, desval, sw, ew, restricted) { } +//end ho + +//-----------------------------------------------------------------------// +// Manipulatiom functions. // +//-----------------------------------------------------------------------// +//cf +virtual bool RestDesVal_changed() +{ + bool changed = fDesireValue != fValue; + fDesireValue = fValue; + return changed; +} + +//cf +virtual void RestDesVal() +{ + fDesireValue = fValue; +} + +//cf +virtual void SetToEditWeight() +{ + fWeight = EditWeight(); +} + +//cf +virtual void SetToStayWeight() +{ + fWeight = StayWeight(); +} + +//ho }; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcNomadicFloatRep.hh b/src/kits/interface/qoca/QcNomadicFloatRep.hh new file mode 100644 index 0000000000..650579b3ab --- /dev/null +++ b/src/kits/interface/qoca/QcNomadicFloatRep.hh @@ -0,0 +1,60 @@ +// Generated automatically from QcNomadicFloatRep.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcNomadicFloatRep.H" +#ifndef QcNomadicFloatRepIFN +#define QcNomadicFloatRepIFN +#line 1 "QcNomadicFloatRep.ch" +// $Id: QcNomadicFloatRep.ch,v 1.7 2000/12/12 09:59:27 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include + +#include + +#define qcDefaultStayWeight 1.0 +#define qcDefaultEditWeight 10000.0 + + + + + + + +#line 53 "QcNomadicFloatRep.ch" +//-----------------------------------------------------------------------// +// Manipulatiom functions. // +//-----------------------------------------------------------------------// + +#line 84 "QcNomadicFloatRep.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcNomadicFloatRepIFN */ diff --git a/src/kits/interface/qoca/QcNullIterator.H b/src/kits/interface/qoca/QcNullIterator.H new file mode 100644 index 0000000000..09e5cabd5e --- /dev/null +++ b/src/kits/interface/qoca/QcNullIterator.H @@ -0,0 +1,18 @@ +// Generated automatically from QcNullIterator.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcNullIteratorDCL +#define QcNullIteratorDCL +#line 1 "QcNullIterator.ch" + +#include + +class QcNullIterator +{ + bool AtEnd() const { return true; } + unsigned getIndex() const { abort(); } + numT getValue() const { abort(); } + unsigned Increment() { abort(); } +} + + + +#endif /* !QcNullIteratorDCL */ diff --git a/src/kits/interface/qoca/QcNullIterator.ch b/src/kits/interface/qoca/QcNullIterator.ch new file mode 100644 index 0000000000..79f1b5af8a --- /dev/null +++ b/src/kits/interface/qoca/QcNullIterator.ch @@ -0,0 +1,12 @@ +//begin o[d] +#include + +class QcNullIterator +{ + bool AtEnd() const { return true; } + unsigned getIndex() const { abort(); } + numT getValue() const { abort(); } + unsigned Increment() { abort(); } +} + +//end o[d] diff --git a/src/kits/interface/qoca/QcNullableConstraint.hh b/src/kits/interface/qoca/QcNullableConstraint.hh new file mode 100644 index 0000000000..b1dc683620 --- /dev/null +++ b/src/kits/interface/qoca/QcNullableConstraint.hh @@ -0,0 +1,10 @@ +#ifndef __QcNullableConstraintH +#define __QcNullableConstraintH + +#include "qoca/QcConstraintRep.hh" +#include "qoca/QcConstraint.hh" +#include "qoca/QcNullableElement.hh" + +typedef QcNullableElement QcNullableConstraint; + +#endif /* !__QcNullableConstraintH */ diff --git a/src/kits/interface/qoca/QcNullableElement.hh b/src/kits/interface/qoca/QcNullableElement.hh new file mode 100644 index 0000000000..d4d0611dfa --- /dev/null +++ b/src/kits/interface/qoca/QcNullableElement.hh @@ -0,0 +1,170 @@ +#ifndef __QcNullableElementH +#define __QcNullableElementH + +#include "qoca/QcDefines.hh" + + +#if qcReportAlloc +# define reportAction(_action) \ + do { \ + cerr << "0: " << &fRep << _action << fRep << '\n'; \ + } while(0) +# define reportConstruction() reportAction(" constructed from QcFloatRep ") +# define reportIncrease() reportAction(" increasing ") +# define reportDecrease() reportAction(" decreasing ") +# undef reportAction +#else /* !qcReportAlloc */ +# define reportConstruction() do { } while(0) +# define reportIncrease() do { } while(0) +# define reportDecrease() do { } while(0) +#endif /* !qcReportAlloc */ + + +/** Reference-counting handle. Its data is a single pointer, and the + constructor and deconstructor do reference counting. + +

The semantics of constrant handles are sharing on assignment + with automatic destruction when the last handle is lost. + +

Pass-by-reference versus pass-by-value: Passing by reference + avoids having the constructor and destructor called, at the cost + of an extra level of indirection per method call. So + pass-by-reference is best for short routines, while pass-by-value + is best for routines that make many method calls on this handle. +**/ +template +class QcNullableElement +{ +public: + friend class QcFloat; + friend class QcConstraint; + + QcNullableElement() + : fRep(0) + { + reportConstruction(); + } + + explicit QcNullableElement(ElementRep *rep) + : fRep(rep) + { + reportConstruction(); + Increase(); + } + + QcNullableElement(QcNullableElement const &other) + : fRep(other.fRep) + { + reportConstruction(); + Increase(); + assertInvar(); + } + + explicit QcNullableElement(ElementRef const &other) + : fRep(other.fRep) + { + reportConstruction(); + Increase(); + assertInvar(); + } + + ~QcNullableElement() + { Decrease(); } + + void assertInvar() const + { +#if qcCheckInternalInvar + if (fRep != 0) + fRep->assertInvar(); +#endif + } + + ElementRep *pointer() const + { return fRep; } + + int getId() const + { return fRep->Id(); } + + QcNullableElement &operator=(const QcNullableElement &other); + + QcNullableElement &operator=(const ElementRef &other); + + bool operator <(const QcNullableElement &other) const + { return *fRep < *other.fRep; } + + /* [pjm]: I'm not too sure why `<' compares fId's whereas `==' and `!=' + compare pointers. See the comment in QcFloat.hh. */ + bool operator ==(const QcNullableElement &other) const + { return fRep == other.fRep; } + + bool operator !=(const QcNullableElement &other) const + { return fRep != other.fRep; } + + bool isDead() const + { return (fRep == 0); } + + bool notDead() const + { return (fRep != 0); } + + char const *Name() const + { return fRep->Name(); } + + /** Called when number of references decreases. */ + void Decrease(); + +private: + /** Call when number of references increases. */ + void Increase() + { + reportIncrease(); + if (fRep != 0) + fRep->Increase(); + } + + ElementRep *fRep; +}; + +template +inline void QcNullableElement::Decrease() +{ + reportDecrease(); + if (fRep == 0) + return; + fRep->Decrease(); + if (fRep->Counter() == 0) { + fRep->assertInvar(); // Check that the pointer is valid. + delete fRep; + } + fRep = 0; +} + +template +QcNullableElement &QcNullableElement::operator=(const QcNullableElement &other) +{ + other.fRep->Increase(); + Decrease(); + fRep = other.fRep; + return *this; +} + +#if 0 +template +QcNullableElement &QcNullableElement::operator=(const ElementRef &other) +{ + other.Rep()->Increase(); + Decrease(); + fRep = other.Rep(); + return *this; +} +#endif + +#ifndef qcNoStream +template +inline ostream &operator<<(ostream &os, QcNullableElement const &cf) +{ + reinterpret_cast(cf).Print(os); + return os; +} +#endif + +#endif /* !__QcNullableElementH */ diff --git a/src/kits/interface/qoca/QcNullableFloat.hh b/src/kits/interface/qoca/QcNullableFloat.hh new file mode 100644 index 0000000000..380ecda87b --- /dev/null +++ b/src/kits/interface/qoca/QcNullableFloat.hh @@ -0,0 +1,10 @@ +#ifndef __QcNullableFloatH +#define __QcNullableFloatH + +#include "qoca/QcFloat.hh" +#include "qoca/QcFloatRep.hh" +#include "qoca/QcNullableElement.hh" + +typedef QcNullableElement QcNullableFloat; + +#endif /* !__QcNullableFloatH */ diff --git a/src/kits/interface/qoca/QcOrigRowState.hh b/src/kits/interface/qoca/QcOrigRowState.hh new file mode 100644 index 0000000000..d54fa14797 --- /dev/null +++ b/src/kits/interface/qoca/QcOrigRowState.hh @@ -0,0 +1,68 @@ +// $Id: QcOrigRowState.hh,v 1.4 2000/12/06 05:32:56 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// The class QcBiMap provides a bi-directional mapping from // +// identifier class to index class. // +//============================================================================// + +#ifndef __QcOrigRowStateH +#define __QcOrigRowStateH + +#include "qoca/QcState.hh" + +class QcOrigRowState : public QcState +{ +public: + numT fRHS; // The rhs coeff corres to row of fA. + int fMRowIndex; + bool fARowDeleted; + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcOrigRowState(int ci); + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os); +}; + +inline QcOrigRowState::QcOrigRowState(int ci) + : QcState(), + fRHS( 0), + fMRowIndex( ci), + fARowDeleted( false) +{ +} + +inline void QcOrigRowState::Print(ostream &os) +{ + os << "[RHS(" << fRHS << ")," + << "[MRowIndex(" << fMRowIndex << ")," + << "[ARowDeleted(" << fARowDeleted << ")]"; +} + +#endif /* !__QcOrigRowStateH */ diff --git a/src/kits/interface/qoca/QcOrigRowStateVector.H b/src/kits/interface/qoca/QcOrigRowStateVector.H new file mode 100644 index 0000000000..7a7e411c34 --- /dev/null +++ b/src/kits/interface/qoca/QcOrigRowStateVector.H @@ -0,0 +1,118 @@ +// Generated automatically from QcOrigRowStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcOrigRowStateVectorDCL +#define QcOrigRowStateVectorDCL +#line 1 "QcOrigRowStateVector.ch" +// $Id: QcOrigRowStateVector.ch,v 1.2 2000/12/06 05:32:56 pmoulder Exp $ +// Originally written by Alan Finlay and Sitt Sen Chok + +//%BeginLegal ================================================================ +// +// The QOCA implementation is free software, but it is Copyright (C) +// 1994-1999 Monash University. It is distributed under the terms of the GNU +// General Public License. See the file COPYING for copying permission. +// +// The QOCA toolkit and runtime are distributed under the terms of the GNU +// Library General Public License. See the file COPYING.LIB for copying +// permissions for those files. +// +// If those licencing arrangements are not satisfactory, please contact us! +// We are willing to offer alternative arrangements, if the need should arise. +// +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR +// IMPLIED. ANY USE IS AT YOUR OWN RISK. +// +// Permission is hereby granted to use or copy this program for any purpose, +// provided the above notices are retained on all copies. Permission to +// modify the code and to distribute modified code is granted, provided the +// above notices are retained, and a notice that the code was modified is +// included with the above copyright notice. +// +//%EndLegal ================================================================== + +#include +#include "qoca/QcStateVector.hh" +#include "qoca/QcOrigRowState.hh" + +class QcOrigRowStateVector + : public QcStateVector +{ +public: + + +inline +QcOrigRowStateVector(); +#line 44 "QcOrigRowStateVector.ch" +//-----------------------------------------------------------------------// +// Query functions. // +//-----------------------------------------------------------------------// + +inline bool +GetARowDeleted(unsigned i) const; +#line 55 "QcOrigRowStateVector.ch" +inline int +GetMRowIndex(unsigned i) const; +#line 63 "QcOrigRowStateVector.ch" +inline numT +GetRHS(unsigned i) const; +#line 71 "QcOrigRowStateVector.ch" +//-----------------------------------------------------------------------// +// Set* functions. +//-----------------------------------------------------------------------// +inline void +SetARowDeleted(unsigned i, bool d); +#line 81 "QcOrigRowStateVector.ch" +inline void +SetMRowIndex(unsigned i, int ri); +#line 88 "QcOrigRowStateVector.ch" +inline void +SetRHS(unsigned i, numT rhs); +#line 95 "QcOrigRowStateVector.ch" +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + +virtual void +FixLinkage(); +#line 104 "QcOrigRowStateVector.ch" +protected: + + +virtual void +Alloc(QcState **start, QcState **finish); +#line 122 "QcOrigRowStateVector.ch" +virtual void +AddToList(QcState **start, QcState **finish); +#line 135 "QcOrigRowStateVector.ch" +virtual void +RemoveFromList(QcState **start, QcState **finish); +#line 152 "QcOrigRowStateVector.ch" +#ifndef NDEBUG + +virtual void +virtualAssertLinkageInvar() const; +#line 165 "QcOrigRowStateVector.ch" +#endif + +public: + + +virtual inline void +Print(ostream &os) const; +#line 178 "QcOrigRowStateVector.ch" +private: +inline QcOrigRowState * +getState( unsigned i) const; +#line 188 "QcOrigRowStateVector.ch" +}; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcOrigRowStateVectorDCL */ diff --git a/src/kits/interface/qoca/QcOrigRowStateVector.cc b/src/kits/interface/qoca/QcOrigRowStateVector.cc new file mode 100644 index 0000000000..fa358d518a --- /dev/null +++ b/src/kits/interface/qoca/QcOrigRowStateVector.cc @@ -0,0 +1,132 @@ +// Generated automatically from QcOrigRowStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcOrigRowStateVector.hh" +#line 1 "QcOrigRowStateVector.ch" +// $Id: QcOrigRowStateVector.ch,v 1.2 2000/12/06 05:32:56 pmoulder Exp $ +// Originally written by Alan Finlay and Sitt Sen Chok + +//%BeginLegal ================================================================ +// +// The QOCA implementation is free software, but it is Copyright (C) +// 1994-1999 Monash University. It is distributed under the terms of the GNU +// General Public License. See the file COPYING for copying permission. +// +// The QOCA toolkit and runtime are distributed under the terms of the GNU +// Library General Public License. See the file COPYING.LIB for copying +// permissions for those files. +// +// If those licencing arrangements are not satisfactory, please contact us! +// We are willing to offer alternative arrangements, if the need should arise. +// +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR +// IMPLIED. ANY USE IS AT YOUR OWN RISK. +// +// Permission is hereby granted to use or copy this program for any purpose, +// provided the above notices are retained on all copies. Permission to +// modify the code and to distribute modified code is granted, provided the +// above notices are retained, and a notice that the code was modified is +// included with the above copyright notice. +// +//%EndLegal ================================================================== + +#include +#include "qoca/QcStateVector.hh" +#include "qoca/QcOrigRowState.hh" + + + + + + +#line 44 "QcOrigRowStateVector.ch" +//-----------------------------------------------------------------------// +// Query functions. // +//-----------------------------------------------------------------------// + +#line 71 "QcOrigRowStateVector.ch" +//-----------------------------------------------------------------------// +// Set* functions. +//-----------------------------------------------------------------------// +#line 95 "QcOrigRowStateVector.ch" +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + +void +QcOrigRowStateVector::FixLinkage() +{ +} + + + + +void +QcOrigRowStateVector::Alloc(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fCapacity); + + for (unsigned i = start - fStates; + start != finish; + start++, i++) + *start = new QcOrigRowState( i); +} + + + +void +QcOrigRowStateVector::AddToList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= getAllocEnd()); + + UNUSED(start); + UNUSED(finish); +} + + + +void +QcOrigRowStateVector::RemoveFromList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fSize); + + while(start != finish) + { + QcOrigRowState *state = CAST(QcOrigRowState *, *start); + state->fRHS = 0.0; + state->fMRowIndex = start - fStates; + state->fARowDeleted = false; + start++; + } +} + +#ifndef NDEBUG + +void +QcOrigRowStateVector::virtualAssertLinkageInvar() const +{ + for (QcState const * const *i = fStates + fSize; i < getAllocEnd(); i++) + { + QcOrigRowState const *state = CAST(QcOrigRowState const *, *i); + assert( state->fRHS == 0.0); + assert( state->fMRowIndex == i - fStates); + assert( !state->fARowDeleted); + } +} +#endif + + + +#line 191 "QcOrigRowStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcOrigRowStateVector.ch b/src/kits/interface/qoca/QcOrigRowStateVector.ch new file mode 100644 index 0000000000..f4db7283e6 --- /dev/null +++ b/src/kits/interface/qoca/QcOrigRowStateVector.ch @@ -0,0 +1,198 @@ +// $Id: QcOrigRowStateVector.ch,v 1.2 2000/12/06 05:32:56 pmoulder Exp $ +// Originally written by Alan Finlay and Sitt Sen Chok + +//%BeginLegal ================================================================ +// +// The QOCA implementation is free software, but it is Copyright (C) +// 1994-1999 Monash University. It is distributed under the terms of the GNU +// General Public License. See the file COPYING for copying permission. +// +// The QOCA toolkit and runtime are distributed under the terms of the GNU +// Library General Public License. See the file COPYING.LIB for copying +// permissions for those files. +// +// If those licencing arrangements are not satisfactory, please contact us! +// We are willing to offer alternative arrangements, if the need should arise. +// +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR +// IMPLIED. ANY USE IS AT YOUR OWN RISK. +// +// Permission is hereby granted to use or copy this program for any purpose, +// provided the above notices are retained on all copies. Permission to +// modify the code and to distribute modified code is granted, provided the +// above notices are retained, and a notice that the code was modified is +// included with the above copyright notice. +// +//%EndLegal ================================================================== + +#include +#include "qoca/QcStateVector.hh" +#include "qoca/QcOrigRowState.hh" + +//o[d] class QcOrigRowStateVector +//o[d] : public QcStateVector +//o[d] { +//o[d] public: + +//hf +inline +QcOrigRowStateVector() + : QcStateVector() +{ +} + +//-----------------------------------------------------------------------// +// Query functions. // +//-----------------------------------------------------------------------// + +inline bool +GetARowDeleted(unsigned i) const +{ + qcAssertPre (i < fSize); + return getState( i)->fARowDeleted; +} + +inline int +GetMRowIndex(unsigned i) const +{ + qcAssertPre (i < fSize); + return getState( i)->fMRowIndex; +} + + +inline numT +GetRHS(unsigned i) const +{ + qcAssertPre (i < fSize); + return getState( i)->fRHS; +} + + +//-----------------------------------------------------------------------// +// Set* functions. +//-----------------------------------------------------------------------// +inline void +SetARowDeleted(unsigned i, bool d) +{ + qcAssertPre (i < fSize); + getState( i)->fARowDeleted = d; +} + +inline void +SetMRowIndex(unsigned i, int ri) +{ + qcAssertPre (i < fSize); + getState( i)->fMRowIndex = ri; +} + +inline void +SetRHS(unsigned i, numT rhs) +{ + qcAssertPre (i < fSize); + getState( i)->fRHS = rhs; +} + +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// +//cf +virtual void +FixLinkage() +{ +} + +//o[d] protected: + +//cf +virtual void +Alloc(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fCapacity); + + for (unsigned i = start - fStates; + start != finish; + start++, i++) + *start = new QcOrigRowState( i); +} + + +//cf +virtual void +AddToList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= getAllocEnd()); + + UNUSED(start); + UNUSED(finish); +} + + +//cf +virtual void +RemoveFromList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start <= finish); + qcAssertPre( finish <= fStates + fSize); + + while(start != finish) + { + QcOrigRowState *state = CAST(QcOrigRowState *, *start); + state->fRHS = 0.0; + state->fMRowIndex = start - fStates; + state->fARowDeleted = false; + start++; + } +} + +#ifndef NDEBUG +//cf +virtual void +virtualAssertLinkageInvar() const +{ + for (QcState const * const *i = fStates + fSize; i < getAllocEnd(); i++) + { + QcOrigRowState const *state = CAST(QcOrigRowState const *, *i); + assert( state->fRHS == 0.0); + assert( state->fMRowIndex == i - fStates); + assert( !state->fARowDeleted); + } +} +#endif + +//o[d] public: + +//hf +virtual inline void +Print(ostream &os) const +{ + os << endl << "Original Row State Vector:"; + QcStateVector::Print( os); +} + + +//o[d] private: +inline QcOrigRowState * +getState( unsigned i) const +{ + qcAssertPre( i < fSize); + QcOrigRowState *ret = CAST(QcOrigRowState *, fStates[i]); + qcAssertPost( ret != 0); + return ret; +} + +//o[d] }; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcOrigRowStateVector.hh b/src/kits/interface/qoca/QcOrigRowStateVector.hh new file mode 100644 index 0000000000..9cac7eaacd --- /dev/null +++ b/src/kits/interface/qoca/QcOrigRowStateVector.hh @@ -0,0 +1,143 @@ +// Generated automatically from QcOrigRowStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcOrigRowStateVector.H" +#ifndef QcOrigRowStateVectorIFN +#define QcOrigRowStateVectorIFN +#line 1 "QcOrigRowStateVector.ch" +// $Id: QcOrigRowStateVector.ch,v 1.2 2000/12/06 05:32:56 pmoulder Exp $ +// Originally written by Alan Finlay and Sitt Sen Chok + +//%BeginLegal ================================================================ +// +// The QOCA implementation is free software, but it is Copyright (C) +// 1994-1999 Monash University. It is distributed under the terms of the GNU +// General Public License. See the file COPYING for copying permission. +// +// The QOCA toolkit and runtime are distributed under the terms of the GNU +// Library General Public License. See the file COPYING.LIB for copying +// permissions for those files. +// +// If those licencing arrangements are not satisfactory, please contact us! +// We are willing to offer alternative arrangements, if the need should arise. +// +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR +// IMPLIED. ANY USE IS AT YOUR OWN RISK. +// +// Permission is hereby granted to use or copy this program for any purpose, +// provided the above notices are retained on all copies. Permission to +// modify the code and to distribute modified code is granted, provided the +// above notices are retained, and a notice that the code was modified is +// included with the above copyright notice. +// +//%EndLegal ================================================================== + +#include +#include "qoca/QcStateVector.hh" +#include "qoca/QcOrigRowState.hh" + + + + + + + +inline +QcOrigRowStateVector::QcOrigRowStateVector() + : QcStateVector() +{ +} + +//-----------------------------------------------------------------------// +// Query functions. // +//-----------------------------------------------------------------------// + +inline bool +QcOrigRowStateVector::GetARowDeleted(unsigned i) const +{ + qcAssertPre (i < fSize); + return getState( i)->fARowDeleted; +} + +inline int +QcOrigRowStateVector::GetMRowIndex(unsigned i) const +{ + qcAssertPre (i < fSize); + return getState( i)->fMRowIndex; +} + + +inline numT +QcOrigRowStateVector::GetRHS(unsigned i) const +{ + qcAssertPre (i < fSize); + return getState( i)->fRHS; +} + + +//-----------------------------------------------------------------------// +// Set* functions. +//-----------------------------------------------------------------------// +inline void +QcOrigRowStateVector::SetARowDeleted(unsigned i, bool d) +{ + qcAssertPre (i < fSize); + getState( i)->fARowDeleted = d; +} + +inline void +QcOrigRowStateVector::SetMRowIndex(unsigned i, int ri) +{ + qcAssertPre (i < fSize); + getState( i)->fMRowIndex = ri; +} + +inline void +QcOrigRowStateVector::SetRHS(unsigned i, numT rhs) +{ + qcAssertPre (i < fSize); + getState( i)->fRHS = rhs; +} + +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + +#line 152 "QcOrigRowStateVector.ch" +#ifndef NDEBUG + +#line 165 "QcOrigRowStateVector.ch" +#endif + + + + +inline void +QcOrigRowStateVector::Print(ostream &os) const +{ + os << endl << "Original Row State Vector:"; + QcStateVector::Print( os); +} + + + +inline QcOrigRowState * +QcOrigRowStateVector::getState( unsigned i) const +{ + qcAssertPre( i < fSize); + QcOrigRowState *ret = CAST(QcOrigRowState *, fStates[i]); + qcAssertPost( ret != 0); + return ret; +} + + + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcOrigRowStateVectorIFN */ diff --git a/src/kits/interface/qoca/QcParamVarIndexIterator.hh b/src/kits/interface/qoca/QcParamVarIndexIterator.hh new file mode 100644 index 0000000000..b78bc80440 --- /dev/null +++ b/src/kits/interface/qoca/QcParamVarIndexIterator.hh @@ -0,0 +1,57 @@ +// $Id: QcParamVarIndexIterator.hh,v 1.5 2000/11/29 01:58:42 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcParamVarIndexIteratorH +#define __QcParamVarIndexIteratorH + +#include + +class QcParamVarIndexIterator + : public QcBasicnessVarIndexIterator +{ +public: + QcParamVarIndexIterator (const QcLinEqTableau &tab); + + void Reset() + { + QcBasicnessVarIndexIterator::Reset(); + qcAssertPost( !fCurrent->isBasic()); + } + + void Increment() + { + QcBasicnessVarIndexIterator::Increment(); + qcAssertPost( !fCurrent->isBasic()); + } +}; + +inline QcParamVarIndexIterator::QcParamVarIndexIterator( + const QcLinEqTableau &tab) + : QcBasicnessVarIndexIterator( &tab.GetColState().fParamHead) +{ +} + +#endif diff --git a/src/kits/interface/qoca/QcQuasiColState.hh b/src/kits/interface/qoca/QcQuasiColState.hh new file mode 100644 index 0000000000..4feb3db87e --- /dev/null +++ b/src/kits/interface/qoca/QcQuasiColState.hh @@ -0,0 +1,65 @@ +// $Id: QcQuasiColState.hh,v 1.4 2000/11/29 01:58:42 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// The class QcBiMap provides a bi-directional mapping from // +// identifier class to index class. // +//============================================================================// + +#ifndef __QcQuasiColStateH +#define __QcQuasiColStateH + +#include "qoca/QcState.hh" + +class QcQuasiColState : public QcState +{ +public: + unsigned getIndex() const + { + assert ((int) fIndex >= 0); + return fIndex; + } + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcQuasiColState(int vi); + + //-----------------------------------------------------------------------// + // Utililty functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) + { os << "Index(" << fIndex << ")"; } + +public: + int fIndex; // The property vector index of this record. +}; + +inline QcQuasiColState::QcQuasiColState(int vi) + : QcState() +{ + fIndex = vi; +} + +#endif diff --git a/src/kits/interface/qoca/QcQuasiColStateVector.hh b/src/kits/interface/qoca/QcQuasiColStateVector.hh new file mode 100644 index 0000000000..bff59b528e --- /dev/null +++ b/src/kits/interface/qoca/QcQuasiColStateVector.hh @@ -0,0 +1,62 @@ +// $Id: QcQuasiColStateVector.hh,v 1.4 2000/11/29 01:58:42 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcQuasiColStateVectorH +#define __QcQuasiColStateVectorH + +#include "qoca/QcStateVector.hh" + +class QcQuasiColStateVector : public QcStateVector +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcQuasiColStateVector(); + + unsigned getNColumns() const + { + return fSize; + } + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; +}; + +inline QcQuasiColStateVector::QcQuasiColStateVector() + : QcStateVector() +{ +} + +inline void QcQuasiColStateVector::Print(ostream &os) const +{ + os << endl << "Column State Vector:"; + QcStateVector::Print(os); +} + +#endif diff --git a/src/kits/interface/qoca/QcQuasiRowColStateVector.H b/src/kits/interface/qoca/QcQuasiRowColStateVector.H new file mode 100644 index 0000000000..e496d38091 --- /dev/null +++ b/src/kits/interface/qoca/QcQuasiRowColStateVector.H @@ -0,0 +1,102 @@ +// Generated automatically from QcQuasiRowColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcQuasiRowColStateVectorDCL +#define QcQuasiRowColStateVectorDCL +#line 1 "QcQuasiRowColStateVector.ch" +// $Id: QcQuasiRowColStateVector.ch,v 1.4 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include + +#include + +class QcQuasiRowColStateVector +{ +public: + +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// +inline +QcQuasiRowColStateVector(QcQuasiRowStateVector *rs, + QcQuasiColStateVector *cs); +#line 47 "QcQuasiRowColStateVector.ch" +protected: +/** This constructor should only be used by derived classes. The derived + class should initialize all the member data in this class. */ +QcQuasiRowColStateVector() +{ +} + +public: +virtual ~QcQuasiRowColStateVector() +{ + delete fRowState; + delete fColState; +} + + + +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// +inline void +Restart(); +#line 73 "QcQuasiRowColStateVector.ch" +inline void +Reserve(unsigned rows, unsigned cols); +#line 80 "QcQuasiRowColStateVector.ch" +#if 0 /* unused */ + +virtual void +SwapRows(unsigned c1, unsigned c2); +#line 135 "QcQuasiRowColStateVector.ch" +#endif /* unused */ + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// +inline void +Print(ostream &os); +#line 148 "QcQuasiRowColStateVector.ch" +public: + QcQuasiRowStateVector *fRowState; + QcQuasiColStateVector *fColState; + + +}; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + + +#endif /* !QcQuasiRowColStateVectorDCL */ diff --git a/src/kits/interface/qoca/QcQuasiRowColStateVector.cc b/src/kits/interface/qoca/QcQuasiRowColStateVector.cc new file mode 100644 index 0000000000..7777196772 --- /dev/null +++ b/src/kits/interface/qoca/QcQuasiRowColStateVector.cc @@ -0,0 +1,116 @@ +// Generated automatically from QcQuasiRowColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcQuasiRowColStateVector.hh" +#line 1 "QcQuasiRowColStateVector.ch" +// $Id: QcQuasiRowColStateVector.ch,v 1.4 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + + + + + + + + + + +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// +#line 63 "QcQuasiRowColStateVector.ch" +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// +#line 80 "QcQuasiRowColStateVector.ch" +#if 0 /* unused */ + +void +QcQuasiRowColStateVector::SwapRows(unsigned c1, unsigned c2) +{ + qcAssertPre( c1 < fRowState->getNRows()); + qcAssertPre( c2 < fRowState->getNRows()); + + if (c1 == c2) + return; + + QcQuasiRowState *r1 = (QcQuasiRowState *)fRowState->GetState(c1); + QcQuasiRowState *r2 = (QcQuasiRowState *)fRowState->GetState(c2); + + // Exchange the data contents (excluding the fIndex field). + { + int tmp = r1->fARowIndex; + r1->fARowIndex = r2->fARowIndex; + r2->fARowIndex = tmp; + } + + // Now fix up the linkage + if (r1->fMRowDeleted != r2->fMRowDeleted) + { + if (r2->fMRowDeleted) + { // Make r1-> original deleted + QcQuasiRowState *tmp = r2; + r2 = r1; + r1 = tmp; + } + assert( !r2->fMRowDeleted); + + if (r2->fPrevRow == 0) + { + assert( fRowState->fRowList == r2); + fRowState->fRowList = r1; + } + else + r2->fPrevRow->fNextRow = r1; + + r1->fNextRow = r2->fNextRow; + r1->fPrevRow = r2->fPrevRow; + + if (r2->fNextRow != 0) + r2->fNextRow->fPrevRow = r1; + + r2->fNextRow = 0; + r2->fPrevRow = 0; + r1->fMRowDeleted = false; + r2->fMRowDeleted = true; + } + + // effic: don't do this all the time + dbg(fRowState->assertLinkageInvar()); +} +#endif /* unused */ + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// +#line 155 "QcQuasiRowColStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + diff --git a/src/kits/interface/qoca/QcQuasiRowColStateVector.ch b/src/kits/interface/qoca/QcQuasiRowColStateVector.ch new file mode 100644 index 0000000000..0fccfae1b9 --- /dev/null +++ b/src/kits/interface/qoca/QcQuasiRowColStateVector.ch @@ -0,0 +1,163 @@ +// $Id: QcQuasiRowColStateVector.ch,v 1.4 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +//o[d] #include +//o[d] #include +//o[i] #include +//o[d] #include + +//o[d] class QcQuasiRowColStateVector +//o[d] { +public: + +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// +inline +QcQuasiRowColStateVector(QcQuasiRowStateVector *rs, + QcQuasiColStateVector *cs) + : fRowState(rs), fColState(cs) +{ +} + +//begin o[d] +protected: +/** This constructor should only be used by derived classes. The derived + class should initialize all the member data in this class. */ +QcQuasiRowColStateVector() +{ +} + +public: +virtual ~QcQuasiRowColStateVector() +{ + delete fRowState; + delete fColState; +} +//end o[d] + + +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// +inline void +Restart() +{ + fRowState->Resize(0); + fColState->Resize(0); +} + +inline void +Reserve(unsigned rows, unsigned cols) +{ + fRowState->Reserve(rows); + fColState->Reserve(cols); +} + +#if 0 /* unused */ +//cf +virtual void +SwapRows(unsigned c1, unsigned c2) +{ + qcAssertPre( c1 < fRowState->getNRows()); + qcAssertPre( c2 < fRowState->getNRows()); + + if (c1 == c2) + return; + + QcQuasiRowState *r1 = (QcQuasiRowState *)fRowState->GetState(c1); + QcQuasiRowState *r2 = (QcQuasiRowState *)fRowState->GetState(c2); + + // Exchange the data contents (excluding the fIndex field). + { + int tmp = r1->fARowIndex; + r1->fARowIndex = r2->fARowIndex; + r2->fARowIndex = tmp; + } + + // Now fix up the linkage + if (r1->fMRowDeleted != r2->fMRowDeleted) + { + if (r2->fMRowDeleted) + { // Make r1-> original deleted + QcQuasiRowState *tmp = r2; + r2 = r1; + r1 = tmp; + } + assert( !r2->fMRowDeleted); + + if (r2->fPrevRow == 0) + { + assert( fRowState->fRowList == r2); + fRowState->fRowList = r1; + } + else + r2->fPrevRow->fNextRow = r1; + + r1->fNextRow = r2->fNextRow; + r1->fPrevRow = r2->fPrevRow; + + if (r2->fNextRow != 0) + r2->fNextRow->fPrevRow = r1; + + r2->fNextRow = 0; + r2->fPrevRow = 0; + r1->fMRowDeleted = false; + r2->fMRowDeleted = true; + } + + // effic: don't do this all the time + dbg(fRowState->assertLinkageInvar()); +} +#endif /* unused */ + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// +inline void +Print(ostream &os) +{ + fRowState->Print(os); + fColState->Print(os); +} + +//begin o[d] +public: + QcQuasiRowStateVector *fRowState; + QcQuasiColStateVector *fColState; +//end o[d] + +//o[d] }; + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + diff --git a/src/kits/interface/qoca/QcQuasiRowColStateVector.hh b/src/kits/interface/qoca/QcQuasiRowColStateVector.hh new file mode 100644 index 0000000000..0f7db1892b --- /dev/null +++ b/src/kits/interface/qoca/QcQuasiRowColStateVector.hh @@ -0,0 +1,97 @@ +// Generated automatically from QcQuasiRowColStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcQuasiRowColStateVector.H" +#ifndef QcQuasiRowColStateVectorIFN +#define QcQuasiRowColStateVectorIFN +#line 1 "QcQuasiRowColStateVector.ch" +// $Id: QcQuasiRowColStateVector.ch,v 1.4 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + + + +#include + + + + + + +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// +inline +QcQuasiRowColStateVector::QcQuasiRowColStateVector(QcQuasiRowStateVector *rs, + QcQuasiColStateVector *cs) + : fRowState(rs), fColState(cs) +{ +} + + +#line 63 "QcQuasiRowColStateVector.ch" +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// +inline void +QcQuasiRowColStateVector::Restart() +{ + fRowState->Resize(0); + fColState->Resize(0); +} + +inline void +QcQuasiRowColStateVector::Reserve(unsigned rows, unsigned cols) +{ + fRowState->Reserve(rows); + fColState->Reserve(cols); +} + +#if 0 /* unused */ + +#line 135 "QcQuasiRowColStateVector.ch" +#endif /* unused */ + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// +inline void +QcQuasiRowColStateVector::Print(ostream &os) +{ + fRowState->Print(os); + fColState->Print(os); +} + + +#line 155 "QcQuasiRowColStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + + +#endif /* !QcQuasiRowColStateVectorIFN */ diff --git a/src/kits/interface/qoca/QcQuasiRowState.hh b/src/kits/interface/qoca/QcQuasiRowState.hh new file mode 100644 index 0000000000..7f50106b0f --- /dev/null +++ b/src/kits/interface/qoca/QcQuasiRowState.hh @@ -0,0 +1,95 @@ +// $Id: QcQuasiRowState.hh,v 1.6 2000/12/12 09:59:27 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// +// The class QcBiMap provides a bi-directional mapping from // +// identifier class to index class. // +//============================================================================// + +#ifndef __QcQuasiRowStateH +#define __QcQuasiRowStateH + +#include "qoca/QcState.hh" + +class QcQuasiRowState : public QcState +{ + friend class QcQuasiRowStateVector; + friend class QcQuasiRowColStateVector; + +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcQuasiRowState(int ci); + + //----------------------------------------------------------------------- + // Query functions + //----------------------------------------------------------------------- + bool isMRowDeleted() const + { + return fMRowDeleted; + } + + QcQuasiRowState const *getNextUndeletedRow() const + { + return fNextRow; + } + + //-----------------------------------------------------------------------// + // Utililty functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os); + +public: + int fIndex; // The property vector index of this record. + int fARowIndex; + +private: + bool fMRowDeleted; + /** fNextRow and fPrevRow are used for an unsorted, doubly-linked list of + undeleted (i.e. !fMRowDeleted) rows kept by QcQuasiRowStateVector. */ + QcQuasiRowState *fNextRow; + QcQuasiRowState *fPrevRow; + +}; + +inline QcQuasiRowState::QcQuasiRowState(int ci) +{ + fIndex = ci; + fARowIndex = ci; + fMRowDeleted = false; + fNextRow = 0; + fPrevRow = 0; +} + +inline void QcQuasiRowState::Print(ostream &os) +{ + os << "Index(" << fIndex << ")," + << "ARowIndex(" << fARowIndex << ")," + << "MRowDeleted(" << fMRowDeleted << ")," + << "NextRow(" << fNextRow << ")," + << "PrevRow(" << fPrevRow << ")"; +} + +#endif diff --git a/src/kits/interface/qoca/QcQuasiRowStateVector.H b/src/kits/interface/qoca/QcQuasiRowStateVector.H new file mode 100644 index 0000000000..a3980dc307 --- /dev/null +++ b/src/kits/interface/qoca/QcQuasiRowStateVector.H @@ -0,0 +1,160 @@ +// Generated automatically from QcQuasiRowStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcQuasiRowStateVectorDCL +#define QcQuasiRowStateVectorDCL +#line 1 "QcQuasiRowStateVector.ch" +// $Id: QcQuasiRowStateVector.ch,v 1.1 2000/11/29 01:49:41 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcStateVector.hh" +#include "qoca/QcQuasiRowState.hh" + +class QcQuasiRowStateVector + : public QcStateVector +{ +public: + + + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcQuasiRowStateVector() + : QcStateVector(), + fRowList( 0) + { + } + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + + unsigned getNRows() const + { + return fSize; + } + + int GetARowIndex(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcQuasiRowState *)fStates[i])->fARowIndex; + } + + bool GetMRowDeleted(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcQuasiRowState *)fStates[i])->fMRowDeleted; + } + + //-----------------------------------------------------------------------// + // Set functions. // + //-----------------------------------------------------------------------// + void SetARowIndex(unsigned i, int ri) + { + qcAssertPre (i < fSize); + ((QcQuasiRowState *)fStates[i])->fARowIndex = ri; + } + + + +void +SetMRowDeleted(unsigned i, bool d); +#line 94 "QcQuasiRowStateVector.ch" +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + +protected: + +virtual void +AddToList(QcState **start, QcState **finish); +#line 120 "QcQuasiRowStateVector.ch" +#ifndef NDEBUG +public: + + +void +assertLinkageInvar() const; +#line 155 "QcQuasiRowStateVector.ch" +protected: + + +virtual void +virtualAssertLinkageInvar() const; +#line 163 "QcQuasiRowStateVector.ch" +#endif + +public: + + +virtual void +FixLinkage(); +#line 189 "QcQuasiRowStateVector.ch" +private: + +inline void +LinkRow(unsigned index); +#line 199 "QcQuasiRowStateVector.ch" +inline void +LinkRow(QcQuasiRowState *me); +#line 216 "QcQuasiRowStateVector.ch" +inline void +UnlinkRow(unsigned index); +#line 225 "QcQuasiRowStateVector.ch" +inline void +UnlinkRow(QcQuasiRowState *me); +#line 244 "QcQuasiRowStateVector.ch" +protected: +inline void +Restart(unsigned i); +#line 260 "QcQuasiRowStateVector.ch" +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// +public: + +virtual void +Print(ostream &os) const; +#line 281 "QcQuasiRowStateVector.ch" +private: +inline QcQuasiRowState * +getState( unsigned i) const; +#line 293 "QcQuasiRowStateVector.ch" +public: + QcQuasiRowState *fRowList; // head of undeleted fM rows linked list + +}; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcQuasiRowStateVectorDCL */ diff --git a/src/kits/interface/qoca/QcQuasiRowStateVector.cc b/src/kits/interface/qoca/QcQuasiRowStateVector.cc new file mode 100644 index 0000000000..818100f319 --- /dev/null +++ b/src/kits/interface/qoca/QcQuasiRowStateVector.cc @@ -0,0 +1,184 @@ +// Generated automatically from QcQuasiRowStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcQuasiRowStateVector.hh" +#line 1 "QcQuasiRowStateVector.ch" +// $Id: QcQuasiRowStateVector.ch,v 1.1 2000/11/29 01:49:41 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcStateVector.hh" +#include "qoca/QcQuasiRowState.hh" + + + + + + + +#line 78 "QcQuasiRowStateVector.ch" +void +QcQuasiRowStateVector::SetMRowDeleted(unsigned i, bool d) +{ + qcAssertPre( i < fSize); + QcQuasiRowState *state = getState( i); + if (state->fMRowDeleted != d) + { + if (d) + UnlinkRow( state); + else + LinkRow( state); + } + state->fMRowDeleted = d; +} + + +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + + + +void +QcQuasiRowStateVector::AddToList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start < finish); + qcAssertPre( finish <= getAllocEnd()); + + for(; start != finish; start++) + { + QcQuasiRowState *state = CAST(QcQuasiRowState *, *start); + + assert( (state->fNextRow == 0) + && (state->fPrevRow == 0) + && (state->fARowIndex == start - fStates) + && (!state->fMRowDeleted)); + + LinkRow( state); + } +} + +#ifndef NDEBUG + + + +void +QcQuasiRowStateVector::assertLinkageInvar() const +{ + unsigned nLive = 0; + for (QcState const * const *i = fStates + fSize; i-- != fStates;) + { + QcQuasiRowState const *state = CAST(QcQuasiRowState const *, *i); + if (state->fMRowDeleted) + { + assert( state->fPrevRow == 0); + assert( state->fNextRow == 0); + } + else + nLive++; + } + + assert( (fRowList == 0) + || (fRowList->fPrevRow == 0)); + for (QcQuasiRowState const *curr = fRowList; + curr != 0; + curr = curr->fNextRow) + { + assert( !curr->fMRowDeleted); + assert( (curr->fNextRow == 0) + || (curr->fNextRow->fPrevRow == curr)); + assert( nLive != 0); + nLive--; + } + assert( nLive == 0); +} + + + + +void +QcQuasiRowStateVector::virtualAssertLinkageInvar() const +{ + assertLinkageInvar(); +} +#endif + + + + +void +QcQuasiRowStateVector::FixLinkage() +{ + dbg(assertLinkageInvar()); + +#if 0 /* should not be necessary */ + fRowList = 0; + + for (unsigned i = 0; i < fSize; i++) + { + QcQuasiRowState *state = (QcQuasiRowState *)fStates[i]; + state->fNextRow = 0; + state->fPrevRow = 0; + + if (!state->fMRowDeleted) + LinkRow( state); + } +#endif +} + + + + +#line 260 "QcQuasiRowStateVector.ch" +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// + + +void +QcQuasiRowStateVector::Print(ostream &os) const +{ + os << endl << "Row State Vector:"; + QcStateVector::Print(os); + os << endl << "Row List:"; + QcQuasiRowState *curr = fRowList; + + while (curr != 0) + { + curr->Print(os); + os << endl; + curr = curr->fNextRow; + } +} + + +#line 299 "QcQuasiRowStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcQuasiRowStateVector.ch b/src/kits/interface/qoca/QcQuasiRowStateVector.ch new file mode 100644 index 0000000000..e26d442f97 --- /dev/null +++ b/src/kits/interface/qoca/QcQuasiRowStateVector.ch @@ -0,0 +1,306 @@ +// $Id: QcQuasiRowStateVector.ch,v 1.1 2000/11/29 01:49:41 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcStateVector.hh" +#include "qoca/QcQuasiRowState.hh" + +//o[d] class QcQuasiRowStateVector +//o[d] : public QcStateVector +//o[d] { +//o[d] public: + +//begin o[d] + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcQuasiRowStateVector() + : QcStateVector(), + fRowList( 0) + { + } + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + + unsigned getNRows() const + { + return fSize; + } + + int GetARowIndex(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcQuasiRowState *)fStates[i])->fARowIndex; + } + + bool GetMRowDeleted(unsigned i) const + { + qcAssertPre (i < fSize); + return ((QcQuasiRowState *)fStates[i])->fMRowDeleted; + } + + //-----------------------------------------------------------------------// + // Set functions. // + //-----------------------------------------------------------------------// + void SetARowIndex(unsigned i, int ri) + { + qcAssertPre (i < fSize); + ((QcQuasiRowState *)fStates[i])->fARowIndex = ri; + } +//end o[d] + +//cf +void +SetMRowDeleted(unsigned i, bool d) +{ + qcAssertPre( i < fSize); + QcQuasiRowState *state = getState( i); + if (state->fMRowDeleted != d) + { + if (d) + UnlinkRow( state); + else + LinkRow( state); + } + state->fMRowDeleted = d; +} + + +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + +//o[d] protected: +//cf +virtual void +AddToList(QcState **start, QcState **finish) +{ + qcAssertPre( fStates <= start); + qcAssertPre( start < finish); + qcAssertPre( finish <= getAllocEnd()); + + for(; start != finish; start++) + { + QcQuasiRowState *state = CAST(QcQuasiRowState *, *start); + + assert( (state->fNextRow == 0) + && (state->fPrevRow == 0) + && (state->fARowIndex == start - fStates) + && (!state->fMRowDeleted)); + + LinkRow( state); + } +} + +#ifndef NDEBUG +//o[d] public: + +//cf +void +assertLinkageInvar() const +{ + unsigned nLive = 0; + for (QcState const * const *i = fStates + fSize; i-- != fStates;) + { + QcQuasiRowState const *state = CAST(QcQuasiRowState const *, *i); + if (state->fMRowDeleted) + { + assert( state->fPrevRow == 0); + assert( state->fNextRow == 0); + } + else + nLive++; + } + + assert( (fRowList == 0) + || (fRowList->fPrevRow == 0)); + for (QcQuasiRowState const *curr = fRowList; + curr != 0; + curr = curr->fNextRow) + { + assert( !curr->fMRowDeleted); + assert( (curr->fNextRow == 0) + || (curr->fNextRow->fPrevRow == curr)); + assert( nLive != 0); + nLive--; + } + assert( nLive == 0); +} + +//o[d] protected: + +//cf +virtual void +virtualAssertLinkageInvar() const +{ + assertLinkageInvar(); +} +#endif + +//o[d] public: + +//cf +virtual void +FixLinkage() +{ + dbg(assertLinkageInvar()); + +#if 0 /* should not be necessary */ + fRowList = 0; + + for (unsigned i = 0; i < fSize; i++) + { + QcQuasiRowState *state = (QcQuasiRowState *)fStates[i]; + state->fNextRow = 0; + state->fPrevRow = 0; + + if (!state->fMRowDeleted) + LinkRow( state); + } +#endif +} + + +//o[d] private: + +inline void +LinkRow(unsigned index) +{ + qcAssertPre (index < fSize); + QcQuasiRowState *me = (QcQuasiRowState *)fStates[index]; + LinkRow( me); +} + +inline void +LinkRow(QcQuasiRowState *me) +{ + qcAssertPre( me->fPrevRow == 0); + qcAssertPre( me->fNextRow == 0); + qcAssertPre( me != fRowList); + + if (fRowList != 0) + { + me->fNextRow = fRowList; + fRowList->fPrevRow = me; + } + + fRowList = me; +} + + +inline void +UnlinkRow(unsigned index) +{ + qcAssertPre (index < fSize); + + QcQuasiRowState *me = (QcQuasiRowState *)fStates[index]; + UnlinkRow( me); +} + +inline void +UnlinkRow(QcQuasiRowState *me) +{ + qcAssertPre( (me->fPrevRow == 0) + == (fRowList == me)); + + if (me->fPrevRow == 0) + fRowList = me->fNextRow; + else + me->fPrevRow->fNextRow = me->fNextRow; + + if (me->fNextRow != 0) + me->fNextRow->fPrevRow = me->fPrevRow; + + me->fPrevRow = 0; + me->fNextRow = 0; +} + + +//o[d] protected: +inline void +Restart(unsigned i) +{ + qcAssertPre (i < fSize); + + QcQuasiRowState *state = (QcQuasiRowState *)fStates[i]; + + if (!state->fMRowDeleted) + UnlinkRow(i); + + state->fARowIndex = (int) i; + state->fMRowDeleted = false; +} + + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// +//o[d] public: +//cf +virtual void +Print(ostream &os) const +{ + os << endl << "Row State Vector:"; + QcStateVector::Print(os); + os << endl << "Row List:"; + QcQuasiRowState *curr = fRowList; + + while (curr != 0) + { + curr->Print(os); + os << endl; + curr = curr->fNextRow; + } +} + +//o[d] private: +inline QcQuasiRowState * +getState( unsigned i) const +{ + qcAssertPre( i < fSize); + QcQuasiRowState *ret = CAST(QcQuasiRowState *, fStates[i]); + qcAssertPost( ret != 0); + return ret; +} + + +//begin o[d] +public: + QcQuasiRowState *fRowList; // head of undeleted fM rows linked list +//end o[d] +//o[d] }; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcQuasiRowStateVector.hh b/src/kits/interface/qoca/QcQuasiRowStateVector.hh new file mode 100644 index 0000000000..567c13dd67 --- /dev/null +++ b/src/kits/interface/qoca/QcQuasiRowStateVector.hh @@ -0,0 +1,156 @@ +// Generated automatically from QcQuasiRowStateVector.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcQuasiRowStateVector.H" +#ifndef QcQuasiRowStateVectorIFN +#define QcQuasiRowStateVectorIFN +#line 1 "QcQuasiRowStateVector.ch" +// $Id: QcQuasiRowStateVector.ch,v 1.1 2000/11/29 01:49:41 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include "qoca/QcStateVector.hh" +#include "qoca/QcQuasiRowState.hh" + + + + + + + +#line 94 "QcQuasiRowStateVector.ch" +//-----------------------------------------------------------------------// +// Manipulation functions. // +//-----------------------------------------------------------------------// + + + +#line 120 "QcQuasiRowStateVector.ch" +#ifndef NDEBUG + + + +#line 163 "QcQuasiRowStateVector.ch" +#endif + + + + +#line 191 "QcQuasiRowStateVector.ch" +inline void +QcQuasiRowStateVector::LinkRow(unsigned index) +{ + qcAssertPre (index < fSize); + QcQuasiRowState *me = (QcQuasiRowState *)fStates[index]; + LinkRow( me); +} + +inline void +QcQuasiRowStateVector::LinkRow(QcQuasiRowState *me) +{ + qcAssertPre( me->fPrevRow == 0); + qcAssertPre( me->fNextRow == 0); + qcAssertPre( me != fRowList); + + if (fRowList != 0) + { + me->fNextRow = fRowList; + fRowList->fPrevRow = me; + } + + fRowList = me; +} + + +inline void +QcQuasiRowStateVector::UnlinkRow(unsigned index) +{ + qcAssertPre (index < fSize); + + QcQuasiRowState *me = (QcQuasiRowState *)fStates[index]; + UnlinkRow( me); +} + +inline void +QcQuasiRowStateVector::UnlinkRow(QcQuasiRowState *me) +{ + qcAssertPre( (me->fPrevRow == 0) + == (fRowList == me)); + + if (me->fPrevRow == 0) + fRowList = me->fNextRow; + else + me->fPrevRow->fNextRow = me->fNextRow; + + if (me->fNextRow != 0) + me->fNextRow->fPrevRow = me->fPrevRow; + + me->fPrevRow = 0; + me->fNextRow = 0; +} + + + +inline void +QcQuasiRowStateVector::Restart(unsigned i) +{ + qcAssertPre (i < fSize); + + QcQuasiRowState *state = (QcQuasiRowState *)fStates[i]; + + if (!state->fMRowDeleted) + UnlinkRow(i); + + state->fARowIndex = (int) i; + state->fMRowDeleted = false; +} + + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// + + +#line 282 "QcQuasiRowStateVector.ch" +inline QcQuasiRowState * +QcQuasiRowStateVector::getState( unsigned i) const +{ + qcAssertPre( i < fSize); + QcQuasiRowState *ret = CAST(QcQuasiRowState *, fStates[i]); + qcAssertPost( ret != 0); + return ret; +} + + + +#line 299 "QcQuasiRowStateVector.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcQuasiRowStateVectorIFN */ diff --git a/src/kits/interface/qoca/QcRowAdaptor.hh b/src/kits/interface/qoca/QcRowAdaptor.hh new file mode 100644 index 0000000000..43b50729de --- /dev/null +++ b/src/kits/interface/qoca/QcRowAdaptor.hh @@ -0,0 +1,172 @@ +// $Id: QcRowAdaptor.hh,v 1.10 2001/01/04 05:20:11 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcRowAdaptorH +#define __QcRowAdaptorH + +#include "qoca/QcDefines.hh" +#include "qoca/QcFloat.hh" +#include "qoca/QcBiMapNotifier.hh" +#include "qoca/QcTableau.hh" +#include "qoca/QcConstraint.hh" +#include "qoca/QcLinPoly.hh" + +/** Extracts the coefficients from a QcLinPoly (typically in a + QcLinConstraint). It is assumed the QcVariableBiMap + supplied has all the variables registered and will continue to so have while + the iterator is incremented. +**/ +class QcRowAdaptor +{ +public: + //-----------------------------------------------------------------------// + // Constructor // + //-----------------------------------------------------------------------// + QcRowAdaptor(const QcLinPoly &lp, QcVariableBiMap &vb, QcTableau &tab); + + //-----------------------------------------------------------------------// + // Query functions // + //-----------------------------------------------------------------------// + bool AtEnd() const + { return (fCurrent == fLinPoly.GetSize()); } + + int GetIndex() const + { + qcAssertPre (!AtEnd()); + return (int) fIndex; + } + + unsigned getIndex() const + { + qcAssertPre (!AtEnd()); + return fIndex; + } + + numT GetValue() const + { + qcAssertPre (!AtEnd()); + return fValue; + } + + numT getValue() const + { + qcAssertPre (!AtEnd()); + return fValue; + } + + //-----------------------------------------------------------------------// + // Iteration functions. // + //-----------------------------------------------------------------------// + void Increment(); + void Reset(); + +private: + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + void Advance(); + + void Refresh(); + // Refresh fIndex according to the current value of fIt. + // As a side effect, get the variable for this polyterm and + // register it in the variable bimap if not already present. + +private: + QcVariableBiMap &fVariableBiMap; + QcTableau &fTableau; + const QcLinPoly &fLinPoly; + unsigned fCurrent; // Current position on the linpoly. + + /** fVariableBiMap.index(fLinPoly.getVariable(fCurrent)). */ + unsigned fIndex; + + /** fLinPoly.getCoeff(fCurrent). */ + numT fValue; +}; + +inline QcRowAdaptor::QcRowAdaptor(const QcLinPoly &lp, QcVariableBiMap &vb, + QcTableau &tab) + : fVariableBiMap(vb), + fTableau(tab), + fLinPoly(lp), + fValue() +{ + if (fLinPoly.GetSize() > 0) { + fCurrent = 0; + fValue = fLinPoly.GetTerm(0).GetCoeff(); + Refresh(); + } +} + +inline void QcRowAdaptor::Advance() +{ + qcAssertPre( !AtEnd()); + + fCurrent++; + fValue = fLinPoly.GetTerm(fCurrent).GetCoeff(); + Refresh(); +} + +inline void QcRowAdaptor::Increment() +{ + qcAssertPre (!AtEnd()); + + fCurrent++; + + while (fCurrent < fLinPoly.GetSize()) { + fValue = fLinPoly.GetTerm(fCurrent).GetCoeff(); + + if (!QcUtility::IsZero(fValue)) { + Refresh(); + break; + } + } +} + +inline void QcRowAdaptor::Refresh() + // Refresh fIndex according to the current value of fIt. + // As a side effect, get the variable for this polyterm and + // register it in the variable bimap if not already present. +{ + qcAssertPre( !AtEnd()); + + QcFloatRep *ident = fLinPoly.GetTerm( fCurrent).getVariable(); + + if (!fVariableBiMap.IdentifierPtrPresent( ident)) { + fIndex = fTableau.NewVariable(); + fVariableBiMap.Update(ident, fIndex); + } else + fIndex = fVariableBiMap.Index(ident); +} + +inline void QcRowAdaptor::Reset() +{ + fCurrent = 0; + fValue = fLinPoly.GetTerm(0).GetCoeff(); + Refresh(); +} + +#endif diff --git a/src/kits/interface/qoca/QcSolvedFormMatrix.hh b/src/kits/interface/qoca/QcSolvedFormMatrix.hh new file mode 100644 index 0000000000..8b55ce1eb4 --- /dev/null +++ b/src/kits/interface/qoca/QcSolvedFormMatrix.hh @@ -0,0 +1,386 @@ +// $Id: QcSolvedFormMatrix.hh,v 1.8 2001/01/30 01:32:08 pmoulder Exp $ +// Originally written by Alan Finlay and Sitt Sen Chok + +//%BeginLegal =============================================================== +// +// The QOCA implementation is free software, but it is Copyright (C) +// 1994-1999 Monash University. It is distributed under the terms of the GNU +// General Public License. See the file COPYING for copying permission. +// +// The QOCA toolkit and runtime are distributed under the terms of the GNU +// Library General Public License. See the file COPYING.LIB for copying +// permissions for those files. +// +// If those licencing arrangements are not satisfactory, please contact us! +// We are willing to offer alternative arrangements, if the need should arise. +// +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR +// IMPLIED. ANY USE IS AT YOUR OWN RISK. +// +// Permission is hereby granted to use or copy this program for any purpose, +// provided the above notices are retained on all copies. Permission to +// modify the code and to distribute modified code is granted, provided the +// above notices are retained, and a notice that the code was modified is +// included with the above copyright notice. +// +//%EndLegal ================================================================= + + +#ifndef __QcSolvedFormMatrixH +#define __QcSolvedFormMatrixH + +#include +#include "qoca/QcUtility.hh" +#include "qoca/QcSparseMatrix.hh" + +/** A matrix of coefficients, and a RHS vector. Except that if + qcRealTableauCoeff is not defined, then the matrix is considered + to be all zeroes; similarly, if qcRealTableauRHS is undefined then + the RHS vector is considered to be all zeroes. +**/ +class QcSolvedFormMatrix +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcSolvedFormMatrix(); + +#ifndef NDEBUG + void assertInvar() const + { +# if defined(qcRealTableauCoeff) && defined(RealTableauRHS) + assert( fCoeffs.getNRows() == fRHS.size()); +# endif + } + + void assertDeepInvar() const + { + assertInvar(); +# ifdef qcRealTableauCoeff + fCoeffs.assertDeepInvar(); +# endif + } +#endif + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + + numT GetValue( unsigned row, unsigned col) const; + + numT GetRHS( unsigned row) const; + +#ifdef qcRealTableauCoeff + QcSparseMatrix const &getCoeffs() const + { return fCoeffs; } +#endif + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + bool AddScaledRow( unsigned destRow, unsigned srcRow, numT factor); + + /** @precondition destRow < getNRows() + @precondition srcRow < srcMatrix.getNRows() + **/ + void CopyCoeffRow( unsigned destRow, QcSparseMatrix const &srcMatrix, unsigned srcRow); + + void Reserve( unsigned r, unsigned c); + void Resize( unsigned rows, unsigned cols); + void Restart(); + + /** Equivalent to ScaleRow(row, -1), but faster (especially if numT is a compound type). */ + void NegateRow( unsigned row); + + bool ScaleRow( unsigned row, numT factor); + void SetValue( unsigned row, unsigned col, numT val); + void CopyColumn( unsigned destCol, unsigned srcCol); + void ZeroRow( unsigned row); + void ZeroColumn( unsigned row); + void IncreaseRHS( unsigned row, numT inc); + void SetRHS( unsigned row, numT rhs); + +#if 0 /* unused */ + void Print(ostream &os) const; +#endif + +#if qcCheckInternalPre +private: + unsigned getNRows() const; + unsigned getNColumns() const; +#endif + +private: +#ifdef qcRealTableauCoeff + QcSparseMatrix fCoeffs; +#elif qcCheckInternalPre + unsigned fColumns; +#endif +#ifdef qcRealTableauRHS + vector fRHS; +#elif !defined(qcRealTableauCoeff) && qcCheckInternalPre + unsigned fRows; +#endif +}; + + +inline QcSolvedFormMatrix::QcSolvedFormMatrix() +#define SEPARATOR : +#ifdef qcRealTableauCoeff + SEPARATOR fCoeffs() +# undef SEPARATOR +# define SEPARATOR , +#elif qcCheckInternalPre + SEPARATOR fColumns(0) +# undef SEPARATOR +# define SEPARATOR , +#endif +#ifdef qcRealTableauRHS + SEPARATOR fRHS() +#elif !defined(qcRealTableauCoeff) && qcCheckInternalPre + SEPARATOR fRows(0) +#endif +#undef SEPARATOR +{ + dbg(assertInvar()); +} + + +#if qcCheckInternalPre +inline unsigned +QcSolvedFormMatrix::getNRows() const +{ +# ifdef qcRealTableauRHS + return fRHS.size(); +# elif defined(qcRealTableauCoeff) + return fCoeffs.getNRows(); +# else + return fRows; +# endif +} + +inline unsigned +QcSolvedFormMatrix::getNColumns() const +{ +# ifdef qcRealTableauCoeff + return fCoeffs.getNColumns(); +# else + return fColumns; +# endif +} +#endif + + +inline bool QcSolvedFormMatrix::AddScaledRow( unsigned destRow, unsigned srcRow, + numT factor) +{ + qcAssertPre( srcRow < getNRows()); + qcAssertPre( destRow < getNRows()); + +#ifdef qcRealTableauCoeff + bool ret = fCoeffs.AddScaledRow( destRow, srcRow, factor); +#else + bool ret = !qcIsZero( factor); +#endif + +#ifdef qcRealTableauRHS + if (ret) + fRHS[destRow] += fRHS[srcRow] * factor; +#endif + + return ret; +} + + +inline numT QcSolvedFormMatrix::GetRHS( unsigned row) const +{ + qcAssertPre( row < getNRows()); + +#ifdef qcRealTableauRHS + return fRHS[row]; +#else + return 0.0; +#endif +} + + +inline numT +QcSolvedFormMatrix::GetValue( unsigned row, unsigned col) const +{ + qcAssertPre( row < getNRows()); + qcAssertPre( col < getNColumns()); + +#ifdef qcRealTableauCoeff + return fCoeffs.GetValue( row, col); +#else + return 0.0; +#endif +} + + +inline void +QcSolvedFormMatrix::CopyCoeffRow( unsigned destRow, QcSparseMatrix const &srcMatrix, unsigned srcRow) +{ + qcAssertPre( destRow < getNRows()); + qcAssertPre( srcRow < srcMatrix.getNRows()); + +#ifdef qcRealTableauCoeff + fCoeffs.CopyRow( destRow, srcMatrix, srcRow); +#else + UNUSED(destRow); + UNUSED(srcMatrix); + UNUSED(srcRow); +#endif +} + + +inline void QcSolvedFormMatrix::IncreaseRHS( unsigned row, numT inc) +{ + qcAssertPre( row < getNRows()); + +#ifdef qcRealTableauRHS + fRHS[row] += inc; +#endif +} + + +#if 0 /* unused */ +inline void QcSolvedFormMatrix::Print(ostream &os) const +{ +# ifdef qcRealTableauCoeff + os << "Solved Form Matrix:" << endl; + os << "===================" << endl; + QcMatrix::Print(os); + os << endl << endl; +# endif +# ifdef qcRealTableauRHS + os << "rhs:" << endl; + os << "====" << endl; + for (unsigned i = 0; i < fRows; i++) + os << "[" << i << "] " << GetRHS(i) << endl; +# endif +} +#endif + + +inline void QcSolvedFormMatrix::Resize( unsigned rows, unsigned cols) +{ +#ifdef qcRealTableauRHS + fRHS.resize( rows); +#endif +#ifdef qcRealTableauCoeff + fCoeffs.Resize( rows, cols); + dbg(assertInvar()); +#endif +} + + +inline void QcSolvedFormMatrix::Restart() +{ +#ifdef qcRealTableauRHS + fRHS.resize(0); +#endif +#ifdef qcRealTableauCoeff + fCoeffs.Resize(0, 0); +#endif +} + + +inline void QcSolvedFormMatrix::Reserve(unsigned row, unsigned col) +{ +#ifdef qcRealTableauRHS + fRHS.reserve( row); +#endif +#ifdef qcRealTableauCoeff + fCoeffs.Reserve( row, col); +#endif +} + + +inline bool QcSolvedFormMatrix::ScaleRow(unsigned row, numT factor) +{ + qcAssertPre( row < getNRows()); + qcAssertPre( QcUtility::isFinite( factor)); + +#ifdef qcRealTableauCoeff + bool ret = fCoeffs.ScaleRow( row, factor); +#else + bool ret = !qcIsZero( factor - 1.0); +#endif + +#ifdef qcRealTableauRHS + if (ret) + fRHS[row] *= factor; +#endif + + return ret; +} + + +inline void QcSolvedFormMatrix::NegateRow(unsigned row) +{ + qcAssertPre( row < getNRows()); + +#ifdef qcRealTableauCoeff + fCoeffs.NegateRow( row); +#endif + +#ifdef qcRealTableauRHS + make_neg( fRHS[row]); +#endif +} + + +inline void QcSolvedFormMatrix::SetRHS(unsigned row, numT rhs) +{ + qcAssertPre( row < getNRows()); + +#ifdef qcRealTableauRHS + fRHS[row] = rhs; +#endif +} + +inline void QcSolvedFormMatrix::SetValue(unsigned row, unsigned col, numT val) +{ + qcAssertPre( row < getNRows()); + qcAssertPre( col < getNColumns()); + +#ifdef qcRealTableauCoeff + fCoeffs.SetValue(row, col, val); +#endif +} + +inline void QcSolvedFormMatrix::CopyColumn(unsigned destCol, unsigned srcCol) +{ + qcAssertPre( destCol < getNColumns()); + qcAssertPre( srcCol < getNColumns()); + +#ifdef qcRealTableauCoeff + fCoeffs.CopyColumn( destCol, srcCol); +#endif +} + +inline void QcSolvedFormMatrix::ZeroColumn( unsigned col) +{ + qcAssertPre( col < getNColumns()); + +#ifdef qcRealTableauCoeff + fCoeffs.ZeroColumn( col); +#endif +} + +inline void QcSolvedFormMatrix::ZeroRow(unsigned row) +{ + qcAssertPre( row < getNRows()); + +#ifdef qcRealTableauRHS + fRHS[row] = 0.0; +#endif +#ifdef qcRealTableauCoeff + fCoeffs.ZeroRow( row); +#endif +} + + +#endif /* !__QcSolvedFormMatrixH */ diff --git a/src/kits/interface/qoca/QcSolver.H b/src/kits/interface/qoca/QcSolver.H new file mode 100644 index 0000000000..2528d34a72 --- /dev/null +++ b/src/kits/interface/qoca/QcSolver.H @@ -0,0 +1,489 @@ +// Generated automatically from QcSolver.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcSolverDCL +#define QcSolverDCL +#line 1 "QcSolver.ch" +// $Id: QcSolver.ch,v 1.21 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Initial version by by Alan Finlay and Sitt Sen Chok +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include +#include "qoca/QcConstraint.hh" + + +class QcSolver +{ + +public: + +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// +inline QcSolver(); +#line 46 "QcSolver.ch" +virtual ~QcSolver() +{ +} + + + +#if qcCheckInternalInvar +inline void +assertInvar() const; +#line 59 "QcSolver.ch" +void +assertDeepInvar() const; +#line 74 "QcSolver.ch" +virtual void +vAssertDeepInvar() const; +#line 79 "QcSolver.ch" +#endif + + +//-----------------------------------------------------------------------// +// Variable management methods // +//-----------------------------------------------------------------------// + +/** Registers a variable with a solver. It is usually not necessary to + do this, as variables are registered automatically when they are + first encountered during an AddConstraint operation. + AddVar is useful to indicate variables which are to be + included in Solve and RestSolver operations when + not referred to in any of the constraints added to the solver. +**/ +virtual void AddVar(QcFloat &v) = 0; + + +void +addVar (QcFloatRep *v); +#line 109 "QcSolver.ch" +static void bad_call (char const *method) __attribute__ ((__noreturn__)); + +#line 118 "QcSolver.ch" +/** Removes variable from solver and returns true provided v is + free. Does nothing and returns false if v is not free. + +

If !IsRegistered(v) then the current behavior is to return + false; maybe presence should be precondition. + +**/ +virtual bool +RemoveVar (QcFloat &v); +#line 133 "QcSolver.ch" +bool +removeVar (QcFloatRep *v) +{ + QcFloat v1 (v); + return RemoveVar (v1); +} + + +/** Sets the desired value of v to desval. This is + the same doing v.SuggestValue(desval), except it checks + that v is registered in the solver. +**/ +virtual inline void +SuggestValue(QcFloat &v, numT desval); +#line 152 "QcSolver.ch" +/** Sets the desired value of all registered variables to their current + value. Useful in some situations after a solve. */ +virtual void RestSolver() = 0; + +//-----------------------------------------------------------------------// +// Enquiry functions for variables // +//-----------------------------------------------------------------------// +/** Indicates whether a variable has been introduced to the solver + either by virtue of a constraint being added, or via AddVar + (or AddEditVar). */ +virtual bool IsRegistered (QcFloat const &v) const = 0; + +/** Indicates a parametric variable which does not depend on any basic + variables (i.e. has zero coefficients in all added constraints). It + is an error to call IsFree for a variable not used by the + the solver, a warning is issued if safety checks are enabled. +**/ +virtual bool IsFree (QcFloat const &v) const; +#line 176 "QcSolver.ch" +/** Indicates if a variable used by the tableau is basic. It is an + error to call IsBasic for a variable not used by the the + solver; a warning is issued in this case if safety checks are + enabled. + +

For some solvers (QcNlpSolver) this is not meaningful. +**/ +virtual bool IsBasic(QcFloat const &v) const = 0; + +/** Returns true iff v is an edit var. Currently does linear search + through list of edit vars. + +

(Fixing this performance bug requires limiting how many solvers a given + var can be in, e.g. to 1. Currently variables can be in more than one + QcSolver due to the way the solvers work (e.g. Qc*System inheriting from + QcSolver). But maybe it's enough to guarantee that ∀[QcFloat v] v in + no more than N solvers, where N ≤ 32.) +**/ +bool +IsEditVar(QcFloat const &v) const; +#line 207 "QcSolver.ch" +bool isEditVar (QcFloatRep const *v) const +{ + QcFloat v1(v); + return IsEditVar (v1); +} + + +/* ---------------------------------------------------------------------- + High Level Edit Variable Interface for use by solver clients. Edit + variables are set and unset with the following interface. The + semantics is that of a set. Edit variables have their weight + multiplied by the a factor which may be specified when the solver is + constructed (else a default factor is used). EndEdit calls RestSolver + for the respective edit variables. It is not necessary for edit + variables to be registered with the solver in advance, AddEditVar + registers them automatically. + --------------------------------------------------------------------- */ + +/** Add v to edit vars. */ + +virtual void +AddEditVar(QcFloat &v); +#line 235 "QcSolver.ch" +void addEditVar (QcFloatRep *v) +{ + QcFloat v1 (v); + AddEditVar (v1); +} + + +/** Prepare for resolve call. The first call to + Resolve after changing the edit vars or the constraints + will call BeginEdit and incur a slight delay. An explicit + BeginEdit call avoids that delay by allowing the + preprocessing to be done at a more convenient time. */ +virtual void BeginEdit() = 0; + + +/** Synonym of BeginEdit. */ +void beginEdit() +{ + BeginEdit(); +} + + +/** For every variable: make it non-edit (i.e. undoes + addEditVar), set it to stay weight, and (if not a + QcFixedFloat) set its desired value to the current value. + +

If both fixed and nomadic variables are in this solver, and not + (each fixed variable weight is well outside of each nomadic edit + variable's stay--edit weight range), then endEdit may cause + the solution to be no longer optimal (i.e. with respect to the stay + weights). +**/ + +virtual void +EndEdit(); +#line 280 "QcSolver.ch" +/** Synonym of EndEdit. */ +void endEdit() +{ EndEdit(); } + + +//-----------------------------------------------------------------------// +// Constraint management methods // +//-----------------------------------------------------------------------// + +/** Returns constraint handles for all constraints rejected as + inconsistant since the last call to ClearInconsistant. + The handles are stored in the order in which they were encountered. +**/ +inline vector const &Inconsistant() const; +#line 299 "QcSolver.ch" +virtual void ClearInconsistant() +{ fInconsistant.resize(0); } + + +/** Add to this solver all the constraints of other. If each + of the addConstraint operations is successful, then return + true; otherwise, false is returned, and this + solver is left in an undefined state. + + @precondition other != null + @precondition other != this +**/ +bool swallow (QcSolver *other); + +#line 333 "QcSolver.ch" +/** If c is consistent with the other constraints in this + solver, then add c to this solver and return + true; otherwise simply return false. The + inconsistant constraint can be identified by calling + Inconsistant after AddConstraint. + + @precondition c (i.e. something returning the same + Id() as c; values of LHS and RHS are irrelevant) is not + already present. + +**/ +virtual bool AddConstraint(QcConstraint &c) = 0; + + +bool addConstraint (QcConstraintRep *c) +{ + QcConstraint c1 (c); + return AddConstraint (c1); +} + + + +/** Identical to AddConstraint(c) except gives hint of which variable + to make basic. + +

One would usually choose a variable that is never an edit variable (or at + least not an edit variable for the first few edit sessions), and is not the + hint for any other constraint in this solver. +**/ +virtual bool AddConstraint(QcConstraint &c, QcFloat &hint) = 0; + + +/** Add weighted "constraint", implemented with an error variable. Equivalent + to adding a QcFixedFloat e to the left-hand side of c, + where e has goal value zero and weight weight. + +

Bug: The error variable doesn't get cleaned up when c is removed. + (Fix: use special marker, and have removeConstraint etc. remove the + error variable from the solver and delete it.) + +

N.B. The interface for weighted constraints will change. It might make + more sense for weightedness to be a property of the constraint object rather + than added on during addConstraint. + +

And/or use an explicit cookie object that is returned from + AddConstraint,AddWeightedConstraint that is used for + removeConstraint,changeConstraint. + +**/ + +void +AddWeightedConstraint(QcConstraint &c, numT weight); +#line 443 "QcSolver.ch" +/** Marks the beginning of a batch of AddConstraint operation. + + @precondition !inBatch() +**/ +inline virtual void +BeginAddConstraint(); +#line 457 "QcSolver.ch" +/** Returns true iff batch constraint mode is active, i.e. there + has been a call to BeginAddConstraint not followed by an + EndAddConstraint call. +**/ +inline bool +inBatch(); +#line 467 "QcSolver.ch" +inline bool +ChangeRHS (QcConstraint &c, numT rhs); +#line 473 "QcSolver.ch" +inline bool +changeRHS (QcConstraintRep *c, numT rhs); +#line 479 "QcSolver.ch" +/** Change the rhs of a constraint. */ +virtual bool ChangeConstraint(QcConstraint &c, numT rhs) = 0; + + +bool +changeConstraint(QcConstraintRep *c, numT rhs) +{ + QcConstraint c1 (c); + return ChangeConstraint (c1, rhs); +} + + + +/** Marks the end of a batch of AddConstraint operations. + + @precondition inBatch() +**/ + +virtual bool +EndAddConstraint(); +#line 517 "QcSolver.ch" +/** If c is in this solver, then remove it and return + true. Does not modify the value of any variable in + c. Returns false if the constraint is not present and + also issues a warning if safety checks are enabled. +**/ +virtual bool RemoveConstraint(QcConstraint &c); +#line 530 "QcSolver.ch" +bool removeConstraint (QcConstraintRep *c) +{ + QcConstraint c1 (c); + return RemoveConstraint (c1); +} + + + +/** Solve all the original constraints again from scratch. Returns + false if any of the original constraints are found to be + inconsistant. The inconsistant constraints can be identified by + calling Inconsistant after Reset. +**/ +virtual bool Reset() = 0; + + +//-----------------------------------------------------------------------// +// Constraint Solving methods // +//-----------------------------------------------------------------------// + +bool GetAutoSolve() const +{ + return fAutoSolve; +} + +void SetAutoSolve (bool a) +{ + fAutoSolve = a; +} + + +/** Solve uses the desired values of the parametric variables to + calculate values for all the variables. */ +virtual void Solve() = 0; + + +/** Synonym of Solve. */ +void solve() +{ Solve(); } + + +/** Similar to Solve, but for "interactive" use. Unlike + Solve, does not call RestDesVal on anything; that is done + by EndEdit. Only values for the variables of interest and + dependent (basic) variables are recalculated, so the solution may not be as + exact as with Solve. +**/ +virtual void Resolve() = 0; + +//-----------------------------------------------------------------------// +// Low Level Edit Variable Interface for use by solvers. These functions // +// manipulate the set of edit variables without any adjustment of the // +// variable weights or automatic registration on addition or RestSolver()// +// on removal. +//-----------------------------------------------------------------------// + +/** Add v to fEditVars. */ +inline void +RegisterEditVar(QcFloat &v); +#line 597 "QcSolver.ch" +/** Remove v from fEditVars. */ + +virtual void RemoveEditVar (QcFloat &v); +#line 617 "QcSolver.ch" +virtual void ClearEditVars() // make fEditVars empty. +{ + fEditVars.resize(0); + fEditVarsSetup = false; +} + + + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// + + +virtual void Print (ostream &os) const; +#line 642 "QcSolver.ch" +/** Erase everything ready to start afresh. */ + +virtual void +Restart(); +#line 653 "QcSolver.ch" +#if qcCheckPost +public: +inline bool +hasConstraint(QcConstraintRep const *c) const; +#line 664 "QcSolver.ch" +inline bool +hasConstraint(QcConstraint const &c) const; +#line 671 "QcSolver.ch" +void checkSatisfied() const; +#line 680 "QcSolver.ch" +protected: +inline void +addCheckedConstraint(QcConstraintRep *c); +#line 689 "QcSolver.ch" +void +removeCheckedConstraint(QcConstraintRep *c); +#line 723 "QcSolver.ch" +inline void +changeCheckedConstraint(QcConstraintRep *oldc, numT rhs); +#line 729 "QcSolver.ch" +inline vector::const_iterator +checkedConstraints_abegin() const; +#line 735 "QcSolver.ch" +inline vector::const_iterator +checkedConstraints_aend() const; +#line 741 "QcSolver.ch" +inline vector::size_type +checkedConstraints_size() const; +#line 747 "QcSolver.ch" +#endif + + +protected: + vector fInconsistant; // Records inconsistant constraints + vector fEditVars; // Used for Edit/Resolve + bool fEditVarsSetup; // Used for Edit/Resolve + bool fAutoSolve; + bool fBatchAddConst; + bool fBatchAddConstFail; + vector fBatchConstraints; + +#if qcCheckPost +private: + vector checkedConstraints; +#endif + + +}; + + + +#ifndef qcNoStream +inline ostream &operator<< (ostream &os, const QcSolver &s); +#line 775 "QcSolver.ch" +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcSolverDCL */ diff --git a/src/kits/interface/qoca/QcSolver.cc b/src/kits/interface/qoca/QcSolver.cc new file mode 100644 index 0000000000..08410f02f9 --- /dev/null +++ b/src/kits/interface/qoca/QcSolver.cc @@ -0,0 +1,417 @@ +// Generated automatically from QcSolver.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcSolver.hh" +#line 1 "QcSolver.ch" +// $Id: QcSolver.ch,v 1.21 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Initial version by by Alan Finlay and Sitt Sen Chok +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include +#include "qoca/QcConstraint.hh" +#include + + + + + + +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// +#line 52 "QcSolver.ch" +#if qcCheckInternalInvar +#line 59 "QcSolver.ch" +void +QcSolver::assertDeepInvar() const +{ + assertInvar(); + for (int i = fInconsistant.size(); --i >= 0;) + fInconsistant[i].assertInvar(); + for (int i = fEditVars.size(); --i >= 0;) + fEditVars[i].assertInvar(); + for (int i = fBatchConstraints.size(); --i >= 0;) + fBatchConstraints[i].assertInvar(); + for (int i = checkedConstraints.size(); --i >= 0;) + checkedConstraints[i]->assertInvar(); +} + + +void +QcSolver::vAssertDeepInvar() const +{ + assertDeepInvar(); +} +#endif + + +//-----------------------------------------------------------------------// +// Variable management methods // +//-----------------------------------------------------------------------// + + +#line 96 "QcSolver.ch" +void +QcSolver::addVar (QcFloatRep *v) +{ + QcFloat v1 (v); + AddVar (v1); + qcAssertPost (IsRegistered (v1)); + QcFloat v2 (v); + assert (v2.Id() == v1.Id()); + assert (!(v2 < v1)); + assert (!(v1 < v2)); + qcAssertPost (IsRegistered (v2)); +} + + + +void QcSolver::bad_call (char const *method) +{ + cerr << "should not call " << method << endl; + abort(); +} + + + +#line 125 "QcSolver.ch" +bool +QcSolver::RemoveVar (QcFloat &v) +{ + UNUSED(v); + bad_call ("QcSolver::RemoveVar"); +} + + +#line 156 "QcSolver.ch" +//-----------------------------------------------------------------------// +// Enquiry functions for variables // +//-----------------------------------------------------------------------// + +#line 169 "QcSolver.ch" +bool QcSolver::IsFree (QcFloat const &v) const +{ + UNUSED(v); + bad_call ("QcSolver::IsFree"); +} + + + +#line 194 "QcSolver.ch" +bool +QcSolver::IsEditVar(QcFloat const &v) const +{ + vector::const_iterator it; + + for (it = fEditVars.begin(); it != fEditVars.end(); ++it) + if ((*it) == v) + return true; + + return false; +} + + +#line 214 "QcSolver.ch" +/* ---------------------------------------------------------------------- + High Level Edit Variable Interface for use by solver clients. Edit + variables are set and unset with the following interface. The + semantics is that of a set. Edit variables have their weight + multiplied by the a factor which may be specified when the solver is + constructed (else a default factor is used). EndEdit calls RestSolver + for the respective edit variables. It is not necessary for edit + variables to be registered with the solver in advance, AddEditVar + registers them automatically. + --------------------------------------------------------------------- */ + + + +void +QcSolver::AddEditVar(QcFloat &v) +{ + v.SetToEditWeight(); + RegisterEditVar (v); +} + + +#line 268 "QcSolver.ch" +void +QcSolver::EndEdit() +{ + for (vector::iterator evi = fEditVars.begin(), eviEnd = fEditVars.end(); + evi != eviEnd; + ++evi) + evi->SetToStayWeight(); + + ClearEditVars(); +} + + +#line 285 "QcSolver.ch" +//-----------------------------------------------------------------------// +// Constraint management methods // +//-----------------------------------------------------------------------// + + +#line 313 "QcSolver.ch" +#ifdef qcCheckPost /* swallow nyi unless compiled with qcCheckPost defined */ +bool QcSolver::swallow (QcSolver *other) +{ + assert (other != NULL); + assert (other != this); + + /* TODO: Consider transferring the variables too. E.g. for v in + other.getVariables; do addVar(v); done. (Except that + getVariables currently returns "internal" variables.) */ + for (vector::iterator ci = other->checkedConstraints.begin(), + ciEnd = other->checkedConstraints.end(); + ci != ciEnd; ci++) + if (!addConstraint (*ci)) + return false; + return true; +} +#endif + + + + +#line 383 "QcSolver.ch" +void +QcSolver::AddWeightedConstraint(QcConstraint &c, numT weight) +{ + /* The reason that we create a new constraint object instead of adding the + variable to the existing constraint is so that adding then removing then + adding a given constraint won't create more and more variables, and so that + user operations on c (such as printing it) don't show the error variable. + + OTOH, removeConstraint could get rid of the extra term from the constraint. */ + + QcLinPoly &wp = const_cast( c.LinPoly()); + QcFloatRep *v; + switch (c.getRelation()) + { + case QcConstraintRep::coEQ: + v = new QcFixedFloatRep( "cnWeight", 0, weight, false); + wp.push( 1, v); + goto ok; + + //case QcConstraintRep::coLT: + case QcConstraintRep::coLE: + v = new QcFixedFloatRep( "cnWeight", 0, weight, true); + wp.push( -1, v); + goto ok; + + //case QcConstraintRep::coGT: + case QcConstraintRep::coGE: + v = new QcFixedFloatRep( "cnWeight", 0, weight, true); + wp.push( 1, v); + goto ok; + } + qcDurchfall( "relation"); + + ok: +#if 0 /* For the moment we'll use the same object, to keep the hash tables happy. */ + QcConstraintRep *wc = new QcConstraintRep( *c.pointer()); + long refcnt = wc->Counter(); + wc->SetLinPoly( wp); + addConstraint( wc); +#else + AddConstraint( c); +#endif + v->Decrease(); + assert( v->Counter() > 0); + /* proof: v->Counter is 1 at creation, it increases by 1 in addConstraint + and/or when added to the end of wc, and the Decrease cancels out the creation + value. + + relevance: Decrease() doesn't call delete. And if it did, then presumably + we'd have a garbage variable in the solver. */ + +#if 0 + assert( refcnt); + while (--refcnt) + wc->Decrease(); + wc->Drop(); +#endif +} + + + +#line 497 "QcSolver.ch" +bool +QcSolver::EndAddConstraint() +{ + qcAssertExternalPre( inBatch()); + fBatchAddConst = false; + + if (fBatchAddConstFail) + { + vector::iterator it; + + for (it = fBatchConstraints.begin(); it != fBatchConstraints.end(); it++) + RemoveConstraint (*it); + } + + fBatchConstraints.clear(); + + return !fBatchAddConstFail; +} + + + +#line 522 "QcSolver.ch" +bool QcSolver::RemoveConstraint(QcConstraint &c) +{ + UNUSED(c); + bad_call ("QcSolver::RemoveConstraint"); +} + + + +#line 546 "QcSolver.ch" +//-----------------------------------------------------------------------// +// Constraint Solving methods // +//-----------------------------------------------------------------------// + +#line 579 "QcSolver.ch" +//-----------------------------------------------------------------------// +// Low Level Edit Variable Interface for use by solvers. These functions // +// manipulate the set of edit variables without any adjustment of the // +// variable weights or automatic registration on addition or RestSolver()// +// on removal. +//-----------------------------------------------------------------------// + + +#line 599 "QcSolver.ch" +void QcSolver::RemoveEditVar (QcFloat &v) +{ + vector::iterator it; + int last = fEditVars.size() - 1; + + for (it = fEditVars.begin(); it != fEditVars.end(); ++it) + { + if ((*it) == v) + { + *it = fEditVars[last]; + fEditVars.resize(last); + fEditVarsSetup = false; + break; + } + } +} + + +#line 625 "QcSolver.ch" +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// + + +void QcSolver::Print (ostream &os) const +{ + if (fEditVarsSetup) + { + os << "Edit Variables"; + unsigned size = fEditVars.size(); + + for (unsigned i = 0; i < size; i++) + fEditVars[i].Print(os); + } +} + + + +void +QcSolver::Restart() +{ + ClearEditVars(); + ClearInconsistant(); + fEditVarsSetup = false; +} + + +#if qcCheckPost + +#line 671 "QcSolver.ch" +void QcSolver::checkSatisfied() const +{ + for (int i = checkedConstraints.size(); --i >= 0;) + { + QcConstraintRep *c = checkedConstraints[i]; + qcAssertExternalPost (c->isSatisfied()); + } +} + + +#line 689 "QcSolver.ch" +void +QcSolver::removeCheckedConstraint(QcConstraintRep *c) +{ + int n1 = checkedConstraints.size() - 1; + int i = n1; + + if (n1 < 0) + goto notHere; + + if (checkedConstraints[n1] == c) + goto trim; + + while (i--) + { + if (checkedConstraints[i] == c) + goto swap; + } + + notHere: + qcAssertExternalPre( 0 && "removing non-present constraint"); + + swap: + { + QcConstraintRep *last; + last = checkedConstraints[n1]; + checkedConstraints[i] = last; + } + + trim: + checkedConstraints.pop_back(); + c->Drop(); +} + + +#line 747 "QcSolver.ch" +#endif + + +#line 769 "QcSolver.ch" +#ifndef qcNoStream +#line 775 "QcSolver.ch" +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcSolver.ch b/src/kits/interface/qoca/QcSolver.ch new file mode 100644 index 0000000000..11080db4ef --- /dev/null +++ b/src/kits/interface/qoca/QcSolver.ch @@ -0,0 +1,784 @@ +// $Id: QcSolver.ch,v 1.21 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Initial version by by Alan Finlay and Sitt Sen Chok +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include +#include "qoca/QcConstraint.hh" +//o[c] #include + +//ho class QcSolver +//ho { + +//ho public: + +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// +inline QcSolver() + : fEditVarsSetup(false), fAutoSolve(false), fBatchAddConst(false) +{ +} + +//begin ho +virtual ~QcSolver() +{ +} +//end ho + + +#if qcCheckInternalInvar +inline void +assertInvar() const +{ +} + +//cf +void +assertDeepInvar() const +{ + assertInvar(); + for (int i = fInconsistant.size(); --i >= 0;) + fInconsistant[i].assertInvar(); + for (int i = fEditVars.size(); --i >= 0;) + fEditVars[i].assertInvar(); + for (int i = fBatchConstraints.size(); --i >= 0;) + fBatchConstraints[i].assertInvar(); + for (int i = checkedConstraints.size(); --i >= 0;) + checkedConstraints[i]->assertInvar(); +} + +//cf +virtual void +vAssertDeepInvar() const +{ + assertDeepInvar(); +} +#endif + + +//-----------------------------------------------------------------------// +// Variable management methods // +//-----------------------------------------------------------------------// + +/** Registers a variable with a solver. It is usually not necessary to + do this, as variables are registered automatically when they are + first encountered during an AddConstraint operation. + AddVar is useful to indicate variables which are to be + included in Solve and RestSolver operations when + not referred to in any of the constraints added to the solver. +**/ +virtual void AddVar(QcFloat &v) = 0; + +//cf +void +addVar (QcFloatRep *v) +{ + QcFloat v1 (v); + AddVar (v1); + qcAssertPost (IsRegistered (v1)); + QcFloat v2 (v); + assert (v2.Id() == v1.Id()); + assert (!(v2 < v1)); + assert (!(v1 < v2)); + qcAssertPost (IsRegistered (v2)); +} + +//ho static void bad_call (char const *method) __attribute__ ((__noreturn__)); +//begin o[c] +void QcSolver::bad_call (char const *method) +{ + cerr << "should not call " << method << endl; + abort(); +} +//end o[c] + +/** Removes variable from solver and returns true provided v is + free. Does nothing and returns false if v is not free. + +

If !IsRegistered(v) then the current behavior is to return + false; maybe presence should be precondition. + +**/ //cf +virtual bool +RemoveVar (QcFloat &v) +{ + UNUSED(v); + bad_call ("QcSolver::RemoveVar"); +} + +//begin ho +bool +removeVar (QcFloatRep *v) +{ + QcFloat v1 (v); + return RemoveVar (v1); +} +//end ho + +/** Sets the desired value of v to desval. This is + the same doing v.SuggestValue(desval), except it checks + that v is registered in the solver. +**/ //hf +virtual inline void +SuggestValue(QcFloat &v, numT desval) +{ + v.SuggestValue (desval); +} + + +/** Sets the desired value of all registered variables to their current + value. Useful in some situations after a solve. */ +virtual void RestSolver() = 0; + +//-----------------------------------------------------------------------// +// Enquiry functions for variables // +//-----------------------------------------------------------------------// +/** Indicates whether a variable has been introduced to the solver + either by virtue of a constraint being added, or via AddVar + (or AddEditVar). */ +virtual bool IsRegistered (QcFloat const &v) const = 0; + +/** Indicates a parametric variable which does not depend on any basic + variables (i.e. has zero coefficients in all added constraints). It + is an error to call IsFree for a variable not used by the + the solver, a warning is issued if safety checks are enabled. +**/ //cf +virtual bool IsFree (QcFloat const &v) const +{ + UNUSED(v); + bad_call ("QcSolver::IsFree"); +} + + +/** Indicates if a variable used by the tableau is basic. It is an + error to call IsBasic for a variable not used by the the + solver; a warning is issued in this case if safety checks are + enabled. + +

For some solvers (QcNlpSolver) this is not meaningful. +**/ +virtual bool IsBasic(QcFloat const &v) const = 0; + +/** Returns true iff v is an edit var. Currently does linear search + through list of edit vars. + +

(Fixing this performance bug requires limiting how many solvers a given + var can be in, e.g. to 1. Currently variables can be in more than one + QcSolver due to the way the solvers work (e.g. Qc*System inheriting from + QcSolver). But maybe it's enough to guarantee that ∀[QcFloat v] v in + no more than N solvers, where N ≤ 32.) +**/ //cf +bool +IsEditVar(QcFloat const &v) const +{ + vector::const_iterator it; + + for (it = fEditVars.begin(); it != fEditVars.end(); ++it) + if ((*it) == v) + return true; + + return false; +} + +//begin ho +bool isEditVar (QcFloatRep const *v) const +{ + QcFloat v1(v); + return IsEditVar (v1); +} +//end ho + +/* ---------------------------------------------------------------------- + High Level Edit Variable Interface for use by solver clients. Edit + variables are set and unset with the following interface. The + semantics is that of a set. Edit variables have their weight + multiplied by the a factor which may be specified when the solver is + constructed (else a default factor is used). EndEdit calls RestSolver + for the respective edit variables. It is not necessary for edit + variables to be registered with the solver in advance, AddEditVar + registers them automatically. + --------------------------------------------------------------------- */ + +/** Add v to edit vars. */ +//cf +virtual void +AddEditVar(QcFloat &v) +{ + v.SetToEditWeight(); + RegisterEditVar (v); +} + +//begin ho +void addEditVar (QcFloatRep *v) +{ + QcFloat v1 (v); + AddEditVar (v1); +} +//end ho + +/** Prepare for resolve call. The first call to + Resolve after changing the edit vars or the constraints + will call BeginEdit and incur a slight delay. An explicit + BeginEdit call avoids that delay by allowing the + preprocessing to be done at a more convenient time. */ +virtual void BeginEdit() = 0; + +//begin ho +/** Synonym of BeginEdit. */ +void beginEdit() +{ + BeginEdit(); +} +//end ho + +/** For every variable: make it non-edit (i.e. undoes + addEditVar), set it to stay weight, and (if not a + QcFixedFloat) set its desired value to the current value. + +

If both fixed and nomadic variables are in this solver, and not + (each fixed variable weight is well outside of each nomadic edit + variable's stay--edit weight range), then endEdit may cause + the solution to be no longer optimal (i.e. with respect to the stay + weights). +**/ +//cf +virtual void +EndEdit() +{ + for (vector::iterator evi = fEditVars.begin(), eviEnd = fEditVars.end(); + evi != eviEnd; + ++evi) + evi->SetToStayWeight(); + + ClearEditVars(); +} + +//begin ho +/** Synonym of EndEdit. */ +void endEdit() +{ EndEdit(); } +//end ho + +//-----------------------------------------------------------------------// +// Constraint management methods // +//-----------------------------------------------------------------------// + +/** Returns constraint handles for all constraints rejected as + inconsistant since the last call to ClearInconsistant. + The handles are stored in the order in which they were encountered. +**/ +inline vector const &Inconsistant() const +{ + return fInconsistant; +} + +//begin ho +virtual void ClearInconsistant() +{ fInconsistant.resize(0); } +//end ho + +/** Add to this solver all the constraints of other. If each + of the addConstraint operations is successful, then return + true; otherwise, false is returned, and this + solver is left in an undefined state. + + @precondition other != null + @precondition other != this +**/ +//ho bool swallow (QcSolver *other); +//begin o[c] +#ifdef qcCheckPost /* swallow nyi unless compiled with qcCheckPost defined */ +bool QcSolver::swallow (QcSolver *other) +{ + assert (other != NULL); + assert (other != this); + + /* TODO: Consider transferring the variables too. E.g. for v in + other.getVariables; do addVar(v); done. (Except that + getVariables currently returns "internal" variables.) */ + for (vector::iterator ci = other->checkedConstraints.begin(), + ciEnd = other->checkedConstraints.end(); + ci != ciEnd; ci++) + if (!addConstraint (*ci)) + return false; + return true; +} +#endif +//end o[c] + + +/** If c is consistent with the other constraints in this + solver, then add c to this solver and return + true; otherwise simply return false. The + inconsistant constraint can be identified by calling + Inconsistant after AddConstraint. + + @precondition c (i.e. something returning the same + Id() as c; values of LHS and RHS are irrelevant) is not + already present. + +**/ +virtual bool AddConstraint(QcConstraint &c) = 0; + +//begin ho +bool addConstraint (QcConstraintRep *c) +{ + QcConstraint c1 (c); + return AddConstraint (c1); +} +//end ho + + +/** Identical to AddConstraint(c) except gives hint of which variable + to make basic. + +

One would usually choose a variable that is never an edit variable (or at + least not an edit variable for the first few edit sessions), and is not the + hint for any other constraint in this solver. +**/ +virtual bool AddConstraint(QcConstraint &c, QcFloat &hint) = 0; + + +/** Add weighted "constraint", implemented with an error variable. Equivalent + to adding a QcFixedFloat e to the left-hand side of c, + where e has goal value zero and weight weight. + +

Bug: The error variable doesn't get cleaned up when c is removed. + (Fix: use special marker, and have removeConstraint etc. remove the + error variable from the solver and delete it.) + +

N.B. The interface for weighted constraints will change. It might make + more sense for weightedness to be a property of the constraint object rather + than added on during addConstraint. + +

And/or use an explicit cookie object that is returned from + AddConstraint,AddWeightedConstraint that is used for + removeConstraint,changeConstraint. + +**/ +//cf +void +AddWeightedConstraint(QcConstraint &c, numT weight) +{ + /* The reason that we create a new constraint object instead of adding the + variable to the existing constraint is so that adding then removing then + adding a given constraint won't create more and more variables, and so that + user operations on c (such as printing it) don't show the error variable. + + OTOH, removeConstraint could get rid of the extra term from the constraint. */ + + QcLinPoly &wp = const_cast( c.LinPoly()); + QcFloatRep *v; + switch (c.getRelation()) + { + case QcConstraintRep::coEQ: + v = new QcFixedFloatRep( "cnWeight", 0, weight, false); + wp.push( 1, v); + goto ok; + + //case QcConstraintRep::coLT: + case QcConstraintRep::coLE: + v = new QcFixedFloatRep( "cnWeight", 0, weight, true); + wp.push( -1, v); + goto ok; + + //case QcConstraintRep::coGT: + case QcConstraintRep::coGE: + v = new QcFixedFloatRep( "cnWeight", 0, weight, true); + wp.push( 1, v); + goto ok; + } + qcDurchfall( "relation"); + + ok: +#if 0 /* For the moment we'll use the same object, to keep the hash tables happy. */ + QcConstraintRep *wc = new QcConstraintRep( *c.pointer()); + long refcnt = wc->Counter(); + wc->SetLinPoly( wp); + addConstraint( wc); +#else + AddConstraint( c); +#endif + v->Decrease(); + assert( v->Counter() > 0); + /* proof: v->Counter is 1 at creation, it increases by 1 in addConstraint + and/or when added to the end of wc, and the Decrease cancels out the creation + value. + + relevance: Decrease() doesn't call delete. And if it did, then presumably + we'd have a garbage variable in the solver. */ + +#if 0 + assert( refcnt); + while (--refcnt) + wc->Decrease(); + wc->Drop(); +#endif +} + + +/** Marks the beginning of a batch of AddConstraint operation. + + @precondition !inBatch() +**/ +inline virtual void +BeginAddConstraint() +{ + qcAssertExternalPre( !fBatchAddConst); + + fBatchConstraints.clear(); + fBatchAddConst = true; + fBatchAddConstFail = false; +} + +/** Returns true iff batch constraint mode is active, i.e. there + has been a call to BeginAddConstraint not followed by an + EndAddConstraint call. +**/ +inline bool +inBatch() +{ + return fBatchAddConst; +} + +inline bool +ChangeRHS (QcConstraint &c, numT rhs) +{ + return ChangeConstraint (c, rhs); +} + +inline bool +changeRHS (QcConstraintRep *c, numT rhs) +{ + return changeConstraint (c, rhs); +} + +/** Change the rhs of a constraint. */ +virtual bool ChangeConstraint(QcConstraint &c, numT rhs) = 0; + +//begin ho +bool +changeConstraint(QcConstraintRep *c, numT rhs) +{ + QcConstraint c1 (c); + return ChangeConstraint (c1, rhs); +} +//end ho + + +/** Marks the end of a batch of AddConstraint operations. + + @precondition inBatch() +**/ +//cf +virtual bool +EndAddConstraint() +{ + qcAssertExternalPre( inBatch()); + fBatchAddConst = false; + + if (fBatchAddConstFail) + { + vector::iterator it; + + for (it = fBatchConstraints.begin(); it != fBatchConstraints.end(); it++) + RemoveConstraint (*it); + } + + fBatchConstraints.clear(); + + return !fBatchAddConstFail; +} + + +/** If c is in this solver, then remove it and return + true. Does not modify the value of any variable in + c. Returns false if the constraint is not present and + also issues a warning if safety checks are enabled. +**/ //cf +virtual bool RemoveConstraint(QcConstraint &c) +{ + UNUSED(c); + bad_call ("QcSolver::RemoveConstraint"); +} + + +//begin ho +bool removeConstraint (QcConstraintRep *c) +{ + QcConstraint c1 (c); + return RemoveConstraint (c1); +} +//end ho + + +/** Solve all the original constraints again from scratch. Returns + false if any of the original constraints are found to be + inconsistant. The inconsistant constraints can be identified by + calling Inconsistant after Reset. +**/ +virtual bool Reset() = 0; + + +//-----------------------------------------------------------------------// +// Constraint Solving methods // +//-----------------------------------------------------------------------// +//begin ho +bool GetAutoSolve() const +{ + return fAutoSolve; +} + +void SetAutoSolve (bool a) +{ + fAutoSolve = a; +} +//end ho + +/** Solve uses the desired values of the parametric variables to + calculate values for all the variables. */ +virtual void Solve() = 0; + +//begin ho +/** Synonym of Solve. */ +void solve() +{ Solve(); } +//end ho + +/** Similar to Solve, but for "interactive" use. Unlike + Solve, does not call RestDesVal on anything; that is done + by EndEdit. Only values for the variables of interest and + dependent (basic) variables are recalculated, so the solution may not be as + exact as with Solve. +**/ +virtual void Resolve() = 0; + +//-----------------------------------------------------------------------// +// Low Level Edit Variable Interface for use by solvers. These functions // +// manipulate the set of edit variables without any adjustment of the // +// variable weights or automatic registration on addition or RestSolver()// +// on removal. +//-----------------------------------------------------------------------// + +/** Add v to fEditVars. */ +inline void +RegisterEditVar(QcFloat &v) +{ + if (IsEditVar( v)) + return; + + fEditVars.push_back( v); + fEditVarsSetup = false; +} + +/** Remove v from fEditVars. */ +//cf +virtual void RemoveEditVar (QcFloat &v) +{ + vector::iterator it; + int last = fEditVars.size() - 1; + + for (it = fEditVars.begin(); it != fEditVars.end(); ++it) + { + if ((*it) == v) + { + *it = fEditVars[last]; + fEditVars.resize(last); + fEditVarsSetup = false; + break; + } + } +} + +//begin ho +virtual void ClearEditVars() // make fEditVars empty. +{ + fEditVars.resize(0); + fEditVarsSetup = false; +} +//end ho + + +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// + +//cf +virtual void Print (ostream &os) const +{ + if (fEditVarsSetup) + { + os << "Edit Variables"; + unsigned size = fEditVars.size(); + + for (unsigned i = 0; i < size; i++) + fEditVars[i].Print(os); + } +} + +/** Erase everything ready to start afresh. */ +//cf +virtual void +Restart() +{ + ClearEditVars(); + ClearInconsistant(); + fEditVarsSetup = false; +} + + +#if qcCheckPost +//ho public: +inline bool +hasConstraint(QcConstraintRep const *c) const +{ + return (find (checkedConstraints.begin(), + checkedConstraints.end(), + c) + != checkedConstraints.end()); +} + +inline bool +hasConstraint(QcConstraint const &c) const +{ + return hasConstraint (c.pointer()); +} + +//cf +void checkSatisfied() const +{ + for (int i = checkedConstraints.size(); --i >= 0;) + { + QcConstraintRep *c = checkedConstraints[i]; + qcAssertExternalPost (c->isSatisfied()); + } +} + +//ho protected: +inline void +addCheckedConstraint(QcConstraintRep *c) +{ + checkedConstraints.push_back( c); + c->Increase(); +} + +//cf +void +removeCheckedConstraint(QcConstraintRep *c) +{ + int n1 = checkedConstraints.size() - 1; + int i = n1; + + if (n1 < 0) + goto notHere; + + if (checkedConstraints[n1] == c) + goto trim; + + while (i--) + { + if (checkedConstraints[i] == c) + goto swap; + } + + notHere: + qcAssertExternalPre( 0 && "removing non-present constraint"); + + swap: + { + QcConstraintRep *last; + last = checkedConstraints[n1]; + checkedConstraints[i] = last; + } + + trim: + checkedConstraints.pop_back(); + c->Drop(); +} + + +inline void +changeCheckedConstraint(QcConstraintRep *oldc, numT rhs) +{ + oldc->SetRHS( rhs); +} + +inline vector::const_iterator +checkedConstraints_abegin() const +{ + return checkedConstraints.begin(); +} + +inline vector::const_iterator +checkedConstraints_aend() const +{ + return checkedConstraints.end(); +} + +inline vector::size_type +checkedConstraints_size() const +{ + return checkedConstraints.size(); +} + +#endif + +//begin ho +protected: + vector fInconsistant; // Records inconsistant constraints + vector fEditVars; // Used for Edit/Resolve + bool fEditVarsSetup; // Used for Edit/Resolve + bool fAutoSolve; + bool fBatchAddConst; + bool fBatchAddConstFail; + vector fBatchConstraints; + +#if qcCheckPost +private: + vector checkedConstraints; +#endif +//end ho + +//ho }; + +//$class_prefix = + +#ifndef qcNoStream +inline ostream &operator<< (ostream &os, const QcSolver &s) +{ + s.Print (os); + return os; +} +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcSolver.hh b/src/kits/interface/qoca/QcSolver.hh new file mode 100644 index 0000000000..0d540f2657 --- /dev/null +++ b/src/kits/interface/qoca/QcSolver.hh @@ -0,0 +1,252 @@ +// Generated automatically from QcSolver.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcSolver.H" +#ifndef QcSolverIFN +#define QcSolverIFN +#line 1 "QcSolver.ch" +// $Id: QcSolver.ch,v 1.21 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Initial version by by Alan Finlay and Sitt Sen Chok +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include +#include "qoca/QcConstraint.hh" + + + + + + + +//-----------------------------------------------------------------------// +// Constructor. // +//-----------------------------------------------------------------------// +inline QcSolver::QcSolver() + : fEditVarsSetup(false), fAutoSolve(false), fBatchAddConst(false) +{ +} + + +#line 52 "QcSolver.ch" +#if qcCheckInternalInvar +inline void +QcSolver::assertInvar() const +{ +} + + +#line 79 "QcSolver.ch" +#endif + + +//-----------------------------------------------------------------------// +// Variable management methods // +//-----------------------------------------------------------------------// + + +#line 145 "QcSolver.ch" +inline void +QcSolver::SuggestValue(QcFloat &v, numT desval) +{ + v.SuggestValue (desval); +} + + + + + + +//-----------------------------------------------------------------------// +// Enquiry functions for variables // +//-----------------------------------------------------------------------// + +#line 214 "QcSolver.ch" +/* ---------------------------------------------------------------------- + High Level Edit Variable Interface for use by solver clients. Edit + variables are set and unset with the following interface. The + semantics is that of a set. Edit variables have their weight + multiplied by the a factor which may be specified when the solver is + constructed (else a default factor is used). EndEdit calls RestSolver + for the respective edit variables. It is not necessary for edit + variables to be registered with the solver in advance, AddEditVar + registers them automatically. + --------------------------------------------------------------------- */ + + + +#line 285 "QcSolver.ch" +//-----------------------------------------------------------------------// +// Constraint management methods // +//-----------------------------------------------------------------------// + + +#line 293 "QcSolver.ch" +inline vector const &QcSolver::Inconsistant() const +{ + return fInconsistant; +} + + +#line 447 "QcSolver.ch" +inline void +QcSolver::BeginAddConstraint() +{ + qcAssertExternalPre( !fBatchAddConst); + + fBatchConstraints.clear(); + fBatchAddConst = true; + fBatchAddConstFail = false; +} + + +#line 461 "QcSolver.ch" +inline bool +QcSolver::inBatch() +{ + return fBatchAddConst; +} + +inline bool +QcSolver::ChangeRHS (QcConstraint &c, numT rhs) +{ + return ChangeConstraint (c, rhs); +} + +inline bool +QcSolver::changeRHS (QcConstraintRep *c, numT rhs) +{ + return changeConstraint (c, rhs); +} + + + + + +#line 546 "QcSolver.ch" +//-----------------------------------------------------------------------// +// Constraint Solving methods // +//-----------------------------------------------------------------------// + +#line 579 "QcSolver.ch" +//-----------------------------------------------------------------------// +// Low Level Edit Variable Interface for use by solvers. These functions // +// manipulate the set of edit variables without any adjustment of the // +// variable weights or automatic registration on addition or RestSolver()// +// on removal. +//-----------------------------------------------------------------------// + + +inline void +QcSolver::RegisterEditVar(QcFloat &v) +{ + if (IsEditVar( v)) + return; + + fEditVars.push_back( v); + fEditVarsSetup = false; +} + + + +#line 625 "QcSolver.ch" +//-----------------------------------------------------------------------// +// Utility functions. // +//-----------------------------------------------------------------------// + + +#line 653 "QcSolver.ch" +#if qcCheckPost + +inline bool +QcSolver::hasConstraint(QcConstraintRep const *c) const +{ + return (find (checkedConstraints.begin(), + checkedConstraints.end(), + c) + != checkedConstraints.end()); +} + +inline bool +QcSolver::hasConstraint(QcConstraint const &c) const +{ + return hasConstraint (c.pointer()); +} + + +#line 681 "QcSolver.ch" +inline void +QcSolver::addCheckedConstraint(QcConstraintRep *c) +{ + checkedConstraints.push_back( c); + c->Increase(); +} + + +#line 723 "QcSolver.ch" +inline void +QcSolver::changeCheckedConstraint(QcConstraintRep *oldc, numT rhs) +{ + oldc->SetRHS( rhs); +} + +inline vector::const_iterator +QcSolver::checkedConstraints_abegin() const +{ + return checkedConstraints.begin(); +} + +inline vector::const_iterator +QcSolver::checkedConstraints_aend() const +{ + return checkedConstraints.end(); +} + +inline vector::size_type +QcSolver::checkedConstraints_size() const +{ + return checkedConstraints.size(); +} + +#endif + + +#line 769 "QcSolver.ch" +#ifndef qcNoStream +inline ostream &operator<< (ostream &os, const QcSolver &s) +{ + s.Print (os); + return os; +} +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcSolverIFN */ diff --git a/src/kits/interface/qoca/QcSparseCoeff.hh b/src/kits/interface/qoca/QcSparseCoeff.hh new file mode 100644 index 0000000000..d3ef26192f --- /dev/null +++ b/src/kits/interface/qoca/QcSparseCoeff.hh @@ -0,0 +1,74 @@ +// $Id: QcSparseCoeff.hh,v 1.5 2001/01/31 07:37:13 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcSparseCoeffH +#define __QcSparseCoeffH + +#include + +class QcSparseCoeff +{ +public: + //-----------------------------------------------------------------------// + // Constructor // + //-----------------------------------------------------------------------// + QcSparseCoeff() + : fValue() + { + dbg(fIndex = -1); + } + + QcSparseCoeff(numT v, int i) + : fValue(v), fIndex(i) + { + qcAssertPre( i >= 0); + } + + numT getValue() const + { + assert( fIndex >= 0); + return fValue; + } + + unsigned getIndex() const + { + assert( fIndex >= 0); + return (unsigned) fIndex; + } + + //-----------------------------------------------------------------------// + // Utility function // + //-----------------------------------------------------------------------// + void Print(ostream &os) const + { os << "[" << fIndex << "," << fValue << "]"; } + + +private: + numT fValue; + int fIndex; +}; + +#endif diff --git a/src/kits/interface/qoca/QcSparseMatrix.cc b/src/kits/interface/qoca/QcSparseMatrix.cc new file mode 100644 index 0000000000..9a5d66f418 --- /dev/null +++ b/src/kits/interface/qoca/QcSparseMatrix.cc @@ -0,0 +1,595 @@ +// $Id: QcSparseMatrix.cc,v 1.23 2001/01/31 11:06:14 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#include +#include +#include +#include +#include + +#ifndef MAX +# define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b)) +#endif + +QcSparseMatrix::~QcSparseMatrix() +{ + TrimRows( 0); + + if(fAllocRows) + { + for(QcSparseMatrixElement **ri = fRowHeads, **riEnd = ri + fAllocRows; + ri < riEnd; ri++) + delete *ri; + delete [] fRowHeads; + } + + if(fAllocColumns) + { + for(QcSparseMatrixElement **ci = fColHeads, **ciEnd = ci + fAllocColumns; + ci < ciEnd; ci++) + delete *ci; + + delete [] fColHeads; + } +} + +#ifndef NDEBUG +void +QcSparseMatrix::assertInvar() const +{ + assert( (fAllocColumns == 0) == (fColHeads == 0)); + assert( (fAllocRows == 0) == (fRowHeads == 0)); + QcMatrix::assertInvar(); + /* ∀[i ∈ [fColumns, fAllocColumns)] fColHeads[i] points to an + allocated element (though that element's pointers are allowed to be + garbage). */ +} + +void +QcSparseMatrix::vAssertDeepInvar() const +{ + assertDeepInvar(); +} +#endif + +/* Note: On the only largish example we've tried, AddScaledRow takes up 46% of + the CPU time. Any speed improvements (other than removing things that + disappear with -DNDEBUG, such as qcAssertPre, assert, dbg(...)) are likely to + have a noticeable effect on overall program speed. */ +bool QcSparseMatrix::AddScaledRow(unsigned destRow, unsigned srcRow, numT factor) +{ + qcAssertPre( QcUtility::isFinite( factor)); + qcAssertPre( srcRow < fRows); + qcAssertPre( destRow < fRows); + + if(QcUtility::IsZero( factor)) + return false; + + qcAssertPre( destRow != srcRow); + /* If we are called with destRow == srcRow then should call ScaleRow. */ + + QcSparseMatrixElement *de = fRowHeads[ destRow]; + QcSparseMatrixElement *prevCol = de; // Link from previous column + de = de->fNextColumn; + unsigned col; + for(QcSparseMatrixElement const *se = fRowHeads[ srcRow]->fNextColumn; + (col = se->fColumn) != ~0u; se = se->fNextColumn) + { + numT increment = se->fValue * factor; + if(QcUtility::IsZero( increment)) + continue; + + // Find existing element or insertion point + while(de->fColumn < col) + { + prevCol = de; + de = de->fNextColumn; + } + + assert( de->fColumn >= col); + + if(de->fColumn == col) + { // found existing + de->fValue += increment; + + if(QcUtility::IsZero( de->fValue)) + { + // Row linkage. + de->fPrevColumn->fNextColumn = de->fNextColumn; + de->fNextColumn->fPrevColumn = de->fPrevColumn; + + // Column linkage. + de->fPrevRow->fNextRow = de->fNextRow; + de->fNextRow->fPrevRow = de->fPrevRow; + + QcSparseMatrixElement *de_nxt = de->fNextColumn; + delete de; // Free memory. + de = de_nxt; + } + else + { + prevCol = de; + de = de->fNextColumn; + } + } + else + { // Allocate a new element + QcSparseMatrixElement *ne = new QcSparseMatrixElement( increment, destRow, col); + + // Insert new element into destRow. + ne->fNextColumn = de; + de->fPrevColumn = ne; + + prevCol->fNextColumn = ne; + ne->fPrevColumn = prevCol; + + // Insert new element into column. + { + QcSparseMatrixElement *head = fColHeads[ col]; + + ne->fPrevRow = head; + ne->fNextRow = head->fNextRow; + head->fNextRow = ne; + ne->fNextRow->fPrevRow = ne; + } + + prevCol = ne; + assert( de == prevCol->fNextColumn); + } + + assert( (de->fColumn > se->fColumn) + && (de->fPrevColumn == prevCol)); + /* Note that prevCol can still be the sentinel (if we added to make zero), + in which case prevCol->fColumn == ~0u. */ + assert( (prevCol->fColumn + 1 <= se->fColumn + 1) + && (prevCol->fNextColumn == de)); + } + + return true; +} + +void QcSparseMatrix::CopyRow(unsigned destRow, QcSparseMatrix const &srcMatrix, unsigned srcRow) +{ + ZeroRow (destRow); + + /* effic: Construct the row in place instead of using SetValue. */ + for (QcSparseMatrixRowIterator i( srcMatrix, srcRow); + !i.AtEnd(); + i.Increment()) + SetValue (destRow, i.getIndex(), i.getValue()); +} + +void QcSparseMatrix::FractionRow(unsigned row, numT factor) +{ + /* The reason we don't do simply `ScaleRow( row, recip( factor))' + is to reduce round-off error. */ + + qcAssertPre( row < fRows); + + if(QcUtility::IsOne( factor)) + return; + + QcSparseMatrixElement *e = fRowHeads[ row]->fNextColumn; + while(!e->isRowHead()) + { + e->fValue /= factor; + e = e->fNextColumn; + } +} + +numT QcSparseMatrix::GetValue(unsigned row, unsigned col) const +{ + qcAssertPre( row < fRows); + qcAssertPre( col < fColumns); + + unsigned eCol; + QcSparseMatrixElement *e = fRowHeads[ row]; + do + e = e->fNextColumn; + while((eCol = e->fColumn) < col); + + return (eCol == col + ? e->fValue + : numT( 0)); +} + + +void +QcSparseMatrix::Pivot(unsigned row, unsigned col) +{ + qcAssertPre( row < getNRows()); + qcAssertPre( col < getNColumns()); + + numT p = GetValue(row, col); + qcAssertPre( !QcUtility::IsZero( p)); + + ScaleRow( row, recip( p)); + + // Cache column coefficients because it is problematic due to the possible + // change of column coefficients. + { + vector coeffCache; + + for (QcSparseMatrixColIterator varCoeffs(*this, col); + !varCoeffs.AtEnd(); + varCoeffs.Increment()) + { + if(varCoeffs.getIndex() != row) + coeffCache.push_back( QcSparseCoeff( varCoeffs.getValue(), + varCoeffs.getIndex())); + } + + for (vector::iterator colIt = coeffCache.begin(); + colIt != coeffCache.end(); + colIt++) + AddScaledRow( colIt->getIndex(), row, -colIt->getValue()); + } + + +#ifdef qcCheckInternalPost + QcSparseMatrixColIterator i( *this, col); + qcAssertPost( i.getIndex() == row); + qcAssertPost( QcUtility::IsOne( i.getValue())); + i.Increment(); + qcAssertPost( i.AtEnd()); +#endif +} + + +void QcSparseMatrix::Reserve(unsigned rows, unsigned cols) + // This routing must cope with any of rows, cols, fRows, fColumns, + // fAllocRows, fAllocColumns being 0. + // Only this routine should change fAllocRows and fAllocColumns + // apart from them being initialised to 0 by the constructor. +{ + qcAssertPre ((int) rows >= 0); + qcAssertPre ((int) cols >= 0); + + QcSparseMatrixElement **e; + unsigned i; + + assert( fAllocRows >= fRows); + assert( fAllocColumns >= fColumns); + + // Copy existing column references and allocate new references + if (cols > fAllocColumns) { + e = new QcSparseMatrixElement*[cols]; // Allocate a new column vector + + // Copy old columns. + assert( (fAllocColumns == 0) == (fColHeads == 0)); + if (fAllocColumns != 0) { + memcpy( e, fColHeads, + fAllocColumns * sizeof(QcSparseMatrixElement *)); + delete [] fColHeads; // Free the old column vector + } + + fColHeads = e; // matrix now uses the new col vector + + for (i = fAllocColumns; i < cols; i++) + { + QcSparseMatrixElement *head = new QcSparseMatrixElement( numT( 1), ~0u, i); + fColHeads[ i] = head; + } + + fAllocColumns = cols; + } + + // Copy existing row references and allocate new references + if (rows > fAllocRows) { + e = new QcSparseMatrixElement*[rows]; // Allocate a new row vector + + // Copy old rows. + if (fAllocRows != 0) { + memcpy( e, fRowHeads, fAllocRows * sizeof( QcSparseMatrixElement *)); + delete [] fRowHeads; // Free the old row vector + } + + fRowHeads = e; // matrix now uses the new row vector + + for (i = fAllocRows; i < rows; i++) + fRowHeads[ i] = new QcSparseMatrixElement( numT( 1), i, ~0u); // Initialise new rows + + fAllocRows = rows; + } + + qcAssertPost (fAllocRows >= rows); + qcAssertPost (fAllocColumns >= cols); + dbg(assertInvar()); +} + +#ifndef MIN +# define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b)) +#endif + +void QcSparseMatrix::Resize(unsigned rows, unsigned cols) + // Note this routine is called by a constructor, be careful + // calling any virtual members. + // Only this routine should change fRows and fColumns. +{ + /* Dispose of surplus elements. Simplistic algorithm since QOCA does not + normally require resize downwards (except to zero, in which case the + current algorithm is almost optimal anyway), so it's not worth finding an + efficient algorithm -- especially as preliminary investigations indicate + that efficient implementation is complex due to the fNextRow and + fNextColumn pointers spanning the clipping region and that one can do + better than scanning all the elements. */ + + // Sweep rows. + if (cols < fColumns) + { + TrimRows( cols); + fColumns = cols; // Because fColHeads[i in [cols..fColumns)] now contain garbage pointers. + } + + // Sweep columns. + if (rows < fRows) + { + for (unsigned j = fColumns; j--;) + TrimColumn( j, rows); + fRows = rows; + } + + // To aid in correctness analysis, note that after each sweep the + // matrix is consistent: the sweeps simply produce empty rows or + // columns outside the clipping region. + + // Add new rows and columns + if ((rows > fAllocRows) + || (cols > fAllocColumns)) + Reserve( MAX( rows, 2 * fAllocRows), + MAX( cols, 2 * fAllocColumns)); + + // Initialise newly exposed columns + for (unsigned i = fColumns; i < cols; i++) + { + QcSparseMatrixElement *head = fColHeads[i]; + head->fNextRow = head->fPrevRow = head; + } + fColumns = cols; + + // Initialise newly exposed rows + for (unsigned i = fRows; i < rows; i++) + { + QcSparseMatrixElement *head = fRowHeads[ i]; + head->fNextColumn = head->fPrevColumn = head; + } + fRows = rows; + + dbg(assertInvar()); +} + +bool QcSparseMatrix::ScaleRow(unsigned row, numT factor) +{ + qcAssertPre( row < fRows); + + if(QcUtility::IsOne( factor)) + return false; + + QcSparseMatrixElement *e = fRowHeads[ row]->fNextColumn; + while(!e->isRowHead()) + { + e->fValue *= factor; + e = e->fNextColumn; + } + + return true; +} + +void QcSparseMatrix::NegateRow(unsigned row) +{ + qcAssertPre( row < fRows); + + QcSparseMatrixElement *e = fRowHeads[ row]->fNextColumn; + while(!e->isRowHead()) + { + make_neg( e->fValue); + e = e->fNextColumn; + } +} + +void QcSparseMatrix::SetValue(unsigned row, unsigned col, numT val) + // Note that SetValue currently search the row for the insertion point. + // They could just as easily be implemented to search the column. + // Which is best depends on the application and may not be matter. +{ + qcAssertPre( row < fRows); + qcAssertPre( col < fColumns); + + // Find existing element or insertion point. + QcSparseMatrixElement *e = fRowHeads[ row]; // element cursor + QcSparseMatrixElement *prevCol; // Link from previous column + + do + { + prevCol = e; + e = e->fNextColumn; + } + while(e->fColumn < col); + + assert( e->getColNr() >= col); + assert( prevCol->fNextColumn == e); + + if(e->fColumn == col) + { // found existing + if(QcUtility::IsZero( val)) + { + e->fPrevColumn->fNextColumn = e->fNextColumn; + e->fNextColumn->fPrevColumn = e->fPrevColumn; + + e->fPrevRow->fNextRow = e->fNextRow; + e->fNextRow->fPrevRow = e->fPrevRow; + + delete e; // Free memory. + } + else + e->fValue = val; // update existing + } + else if(!QcUtility::IsZero( val)) + { // Allocate a new element. + QcSparseMatrixElement *ne = new QcSparseMatrixElement( val, row, col); + + // Insert new element into row. + ne->fNextColumn = e; + e->fPrevColumn = ne; + + prevCol->fNextColumn = ne; + ne->fPrevColumn = prevCol; + + // Insert new element into column. + { + QcSparseMatrixElement *head = fColHeads[ col]; + + ne->fPrevRow = head; + ne->fNextRow = head->fNextRow; + head->fNextRow = ne; + ne->fNextRow->fPrevRow = ne; + } + } +} + +void QcSparseMatrix::CopyColumn(unsigned destCol, unsigned srcCol) +{ + ZeroColumn( destCol); + + for(QcSparseMatrixColIterator colIt( *this, srcCol); + !colIt.AtEnd(); + colIt.Increment()) + SetValue( colIt.getIndex(), destCol, colIt.getValue()); +} + +#if 0 /* unused */ +void QcSparseMatrix::SwapRows(unsigned r1, unsigned r2) +{ + numT temp; + + /* effic: Avoid use of SetValue,GetValue. */ + for (unsigned i = 0; i < fColumns; i++) { + temp = GetValue(r1, i); + SetValue(r1, i, GetValue(r2, i)); + SetValue(r2, i, temp); + } +} +#endif + +void QcSparseMatrix::TrimColumn(unsigned col, unsigned from) +{ + qcAssertPre(col < fColumns); + qcAssertPre(from < fAllocRows); + + QcSparseMatrixElement *e1 = fColHeads[ col]; + QcSparseMatrixElement *last = e1; + e1 = e1->fNextRow; + + while (!e1->isColHead()) { + QcSparseMatrixElement *e2 = e1->fNextRow; + + if (e1->fRow >= from) + delete e1; // Free memory. + else + last = e1; + + e1 = e2; + } + + assert( e1 == fColHeads[ col]); + last->fNextRow = e1; // fixup dangling pointer +} + +void QcSparseMatrix::Zero() +{ + if(fColumns != 0) + TrimRows( 0); + + // Fix up after TrimRows. + for(unsigned i = 0; i < fColumns; i++) + { + QcSparseMatrixElement *head = fColHeads[ i]; + head->fNextRow = head->fPrevRow = head; + } +} + +void QcSparseMatrix::TrimRows(unsigned from) +{ + qcAssertPre( from < fAllocColumns); + + for(QcSparseMatrixElement **ri = fRowHeads, **riEnd = ri + fRows; + ri < riEnd; ri++) + { + QcSparseMatrixElement *head = *ri; + + /* Go backwards: no need to iterate over elements we aren't deleting. */ + QcSparseMatrixElement *e1 = head->fPrevColumn; + while(e1->fColumn + 1 > from) // Note that e1->fColumn can be ~0u. + { + QcSparseMatrixElement *savedPrevCol = e1->fPrevColumn; + delete e1; // Free memory. + e1 = savedPrevCol; + } + + e1->fNextColumn = head; + head->fPrevColumn = e1; + } +} + +void QcSparseMatrix::ZeroColumn(unsigned col) +{ + qcAssertPre( col < fColumns); + + QcSparseMatrixElement *head = fColHeads[ col]; + QcSparseMatrixElement *ecol = head->fNextRow; // element cursor + + while(ecol != head) + { // Remove the column elements from rows + ecol->fPrevColumn->fNextColumn = ecol->fNextColumn; + ecol->fNextColumn->fPrevColumn = ecol->fPrevColumn; + + QcSparseMatrixElement *temp = ecol; + ecol = ecol->fNextRow; + delete temp; + } + + head->fPrevRow = head->fNextRow = head; +} + +void QcSparseMatrix::ZeroRow(unsigned row) +{ + qcAssertPre( row < fRows); + + QcSparseMatrixElement *head = fRowHeads[ row]; + QcSparseMatrixElement *erow = head->fNextColumn; + + while(erow != head) + { // Remove the column elements from rows + erow->fPrevRow->fNextRow = erow->fNextRow; + erow->fNextRow->fPrevRow = erow->fPrevRow; + + QcSparseMatrixElement *temp = erow; + erow = erow->fNextColumn; + delete temp; + } + + head->fPrevColumn = head->fNextColumn = head; +} diff --git a/src/kits/interface/qoca/QcSparseMatrix.hh b/src/kits/interface/qoca/QcSparseMatrix.hh new file mode 100644 index 0000000000..4f470e7335 --- /dev/null +++ b/src/kits/interface/qoca/QcSparseMatrix.hh @@ -0,0 +1,190 @@ +// $Id: QcSparseMatrix.hh,v 1.17 2001/01/31 10:47:44 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcSparseMatrixH +#define __QcSparseMatrixH + +#include +#include "qoca/QcDefines.hh" +#include "qoca/QcMatrix.hh" +#include "qoca/QcSparseMatrixElement.hh" +#include "qoca/QcSparseCoeff.hh" + +class QcSparseMatrixIterator; +class QcSparseMatrixRowIterator; +class QcSparseMatrixColIterator; + +/** A matrix of numTs whose representation is optimized for containing many zero elements. + +

["Optimized" is used a little loosely in the above statement, but that is + at least the intent.] + +

Representation: There are two arrays, fRowHeads and + fColHeads. + +

∀[j] fColHeads[j] points to a "sentinel" + element of a circular bidirectional unsorted linked list of the + non-zero elements of column j. The sentinel element is marked + with row number ~0u. + +

fRowHeads is similar, but the list is sorted by column number. + +

Proposal for better representation: +

    + +
  • Use hash tabling (see below) to allow lookups to be O(1) (approximately). + +
+ +

The reason for still having linked lists is for more efficient iteration + over non-zero elements of a specified row or column. The cost of iterating + over a hashtable in STL is O(size of table), which can be a relatively large + multiplier. Unsorted linked lists are cheap to maintain, the main cost + being memory usage (four words per stored element for doubly-linked lists). + +

Singly-linked lists are not worth the extra programming effort. [In + favor of singly-linked lists: (i) We save two words per stored element. + (ii) Deletions are relatively rare, the main cases being clear() + (which isn't a problem because we're iterating over everything anyway) and + pivoting. However, there may be some correctness issues due to the changing + of the address of the elements following the deleted item. Also + consider that the following item could be the sentinel.] + +

Regarding choice of backing for O(1) lookup: The choices are: +

    +
  1. Dense matrix. +
  2. Single hashtable mapping from pair(row number, column number) to element. +
  3. Array of fAllocRows hashtables mapping from column number to element. (Or the other way around.) +
+ +

Option one is best for relatively small problems, especially since STL + hashtables have a minimum size of 53 elements (see __stl_prime_list in + stl_hashtable.h). It's also the right choice if we don't care about memory + consumption. + +

Option 3 has a better-than-random hash function (namely the column number + itself): there will in many problems be no clashes at all, since regularity + in the column numbers works in our favour. + +

Option 2 is more memory efficient, though finding a good hash function is + harder. That said, an array of hash tables is conceptually equivalent to a + large single hash table, which suggests that a single hash table should be + at least almost as good as an array of hash tables. +**/ +class QcSparseMatrix : public QcMatrix +{ +public: + friend class QcSparseMatrixRowIterator; + friend class QcSparseMatrixColIterator; + + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcSparseMatrix() + : QcMatrix(), fRowHeads( 0), fColHeads( 0) + { } + + virtual ~QcSparseMatrix(); + +#ifndef NDEBUG + void assertInvar() const; + void assertDeepInvar() const { assertInvar(); } + virtual void vAssertDeepInvar() const; +#endif + + //-----------------------------------------------------------------------// + // Enquiry functions. // + //-----------------------------------------------------------------------// + virtual numT GetValue(unsigned row, unsigned col) const; + + inline QcSparseMatrixElement const * + getFirstInRow( unsigned row) const + { + qcAssertPre( row < fRows); + return fRowHeads[ row]->getNextInRow(); + } + + inline QcSparseMatrixElement const * + getFirstInCol( unsigned col) const + { + qcAssertPre( col < fColumns); + return fColHeads[ col]->getNextInCol(); + } + + //-----------------------------------------------------------------------// + // Matrix size management functions. // + //-----------------------------------------------------------------------// + virtual void Reserve(unsigned rows, unsigned cols); + virtual void Resize(unsigned rows, unsigned cols); + // Change the size of the used part of the array up or down. + // Increases may take time up to O(rows * cols). + + //-----------------------------------------------------------------------// + // Basic matrix data management functions. // + //-----------------------------------------------------------------------// + void CopyRow(unsigned destRow, QcSparseMatrix const &srcMatrix, unsigned srcRow); + + virtual void CopyColumn(unsigned d, unsigned s); + //virtual void SwapRows(unsigned r1, unsigned r2); + virtual void SetValue(unsigned row, unsigned col, numT val); + virtual void Zero(); + virtual void ZeroColumn(unsigned col); + virtual void ZeroRow(unsigned row); + + //-----------------------------------------------------------------------// + // Numerical computation functions. // + //-----------------------------------------------------------------------// + //virtual void AddRow(unsigned destRow, unsigned srcRow); + virtual bool AddScaledRow(unsigned destRow, unsigned srcRow, numT factor); + virtual void FractionRow(unsigned row, numT factor); + virtual void Pivot(unsigned row, unsigned col); + virtual bool ScaleRow(unsigned row, numT factor); + /** Equivalent to ScaleRow(row, -1), but faster. */ + void NegateRow( unsigned row); + +private: + //-----------------------------------------------------------------------// + // Sparse matrix specific functions. // + //-----------------------------------------------------------------------// + + /** Disposes each row's sparse elements with column index greater than or + equal to from. Doesn't touch fColHeads, i.e. the + pointers are left dangling. + **/ + void TrimRows(unsigned from); + + + /** Exactly analagous to TrimRow. I.e. same explanation applies + except swapping the word `row' with the word `column' throughout. */ + void TrimColumn(unsigned col, unsigned from); + + +private: + QcSparseMatrixElement **fRowHeads; + QcSparseMatrixElement **fColHeads; +}; + +#endif diff --git a/src/kits/interface/qoca/QcSparseMatrixColIterator.hh b/src/kits/interface/qoca/QcSparseMatrixColIterator.hh new file mode 100644 index 0000000000..f5f5b37b0e --- /dev/null +++ b/src/kits/interface/qoca/QcSparseMatrixColIterator.hh @@ -0,0 +1,85 @@ +// $Id: QcSparseMatrixColIterator.hh,v 1.9 2001/01/31 10:04:51 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcSparseMatrixColIteratorH +#define __QcSparseMatrixColIteratorH + +#include +#include + +/** Iterator over the non-zero elements of a column of a + QcSparseMatrix. + +

Note: there is no order guarantee. + +

Also note that it's best not to write to the matrix while iterating over + it. +**/ +class QcSparseMatrixColIterator : public QcSparseMatrixIterator +{ + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// +public: + QcSparseMatrixColIterator(const QcSparseMatrix &m, unsigned col); + + //-----------------------------------------------------------------------// + // Iteration functions. // + //-----------------------------------------------------------------------// +public: + bool AtEnd() const + // Returns true iff the iterator is past the end of its column. + { return fIndex == ~0u; } + virtual void Increment(); + virtual void Reset(); +}; + +inline QcSparseMatrixColIterator::QcSparseMatrixColIterator( + const QcSparseMatrix &m, unsigned col) + : QcSparseMatrixIterator(m, col) +{ + qcAssertPre (col < m.getNColumns()); + + Reset(); +} + +inline void QcSparseMatrixColIterator::Increment() +{ + qcAssertPre (!AtEnd()); + + fCurrent = fCurrent->getNextInCol(); + fValue = fCurrent->getValue(); + fIndex = fCurrent->getRowNr(); +} + +inline void QcSparseMatrixColIterator::Reset() +{ + fCurrent = fMatrix->getFirstInCol( fVector); + fValue = fCurrent->getValue(); + fIndex = fCurrent->getRowNr(); +} + +#endif diff --git a/src/kits/interface/qoca/QcSparseMatrixElement.hh b/src/kits/interface/qoca/QcSparseMatrixElement.hh new file mode 100644 index 0000000000..b4fa56f43c --- /dev/null +++ b/src/kits/interface/qoca/QcSparseMatrixElement.hh @@ -0,0 +1,107 @@ +// $Id: QcSparseMatrixElement.hh,v 1.7 2001/01/31 10:04:51 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcSparseMatrixElementH +#define __QcSparseMatrixElementH + +#include "qoca/QcDefines.hh" + +class QcSparseMatrixElement +{ +public: + friend class QcSparseMatrix; + + QcSparseMatrixElement( numT val, unsigned row, unsigned col) + : fValue( val), + fRow( row), + fColumn( col) + { + qcAssertPre( int( row + 1) >= 0); + qcAssertPre( int( col + 1) >= 0); + } + +private: + // Dummy constructors so that usage is caught at compile-time. + QcSparseMatrixElement(); + QcSparseMatrixElement(QcSparseMatrixElement const &); + +public: + + inline numT + getValue() const + { + return fValue; + } + + inline unsigned + getRowNr() const + { + qcAssertPost( int( fRow + 1) >= 0); + return fRow; + } + + inline bool + isColHead() const + { + return fRow == ~0u; + } + + inline bool + isRowHead() const + { + return fColumn == ~0u; + } + + inline unsigned + getColNr() const + { + qcAssertPost( int( fColumn + 1) >= 0); + return fColumn; + } + + inline QcSparseMatrixElement const * + getNextInCol() const + { + return fNextRow; + } + + inline QcSparseMatrixElement const * + getNextInRow() const + { + return fNextColumn; + } + +private: + numT fValue; + unsigned fRow; // Row index of element. + unsigned fColumn; // Column index of element. + QcSparseMatrixElement *fNextRow; // Next elements in this row. + QcSparseMatrixElement *fNextColumn; // Next elements in this col. + QcSparseMatrixElement *fPrevRow; // Previous elements in this row. + QcSparseMatrixElement *fPrevColumn; // Previous elements in this col. +}; + +#endif diff --git a/src/kits/interface/qoca/QcSparseMatrixIterator.hh b/src/kits/interface/qoca/QcSparseMatrixIterator.hh new file mode 100644 index 0000000000..474fc492c2 --- /dev/null +++ b/src/kits/interface/qoca/QcSparseMatrixIterator.hh @@ -0,0 +1,64 @@ +// $Id: QcSparseMatrixIterator.hh,v 1.8 2001/01/31 04:53:11 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcSparseMatrixIteratorH +#define __QcSparseMatrixIteratorH + +#include "qoca/QcMatrixIterator.hh" +#include "qoca/QcSparseMatrix.hh" + +class QcSparseMatrix; +class QcSparseMatrixElement; + +/** Iterator over the non-zero elements of a row or column of a + QcSparseMatrix. + +

Note: there is no order guarantee. + +

Also note that it's best not to write to the matrix while iterating over + it. +**/ +class QcSparseMatrixIterator : public QcMatrixIterator +{ + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// +public: + QcSparseMatrixIterator(const QcSparseMatrix &m, unsigned vec); + +protected: + const QcSparseMatrix *fMatrix; + QcSparseMatrixElement const *fCurrent; +}; + +inline QcSparseMatrixIterator::QcSparseMatrixIterator(const QcSparseMatrix &m, + unsigned vec) + : QcMatrixIterator(vec), + fMatrix(&m) +{ +} + +#endif /* !__QcSparseMatrixIteratorH */ diff --git a/src/kits/interface/qoca/QcSparseMatrixRowIterator.hh b/src/kits/interface/qoca/QcSparseMatrixRowIterator.hh new file mode 100644 index 0000000000..38d3250478 --- /dev/null +++ b/src/kits/interface/qoca/QcSparseMatrixRowIterator.hh @@ -0,0 +1,80 @@ +// $Id: QcSparseMatrixRowIterator.hh,v 1.7 2001/01/31 10:04:51 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcSparseMatrixRowIteratorH +#define __QcSparseMatrixRowIteratorH + +#include +#include + +/** An iterator over the non-zero elements of a row of a QcSparseMatrix. */ +class QcSparseMatrixRowIterator : public QcSparseMatrixIterator +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcSparseMatrixRowIterator(const QcSparseMatrix &m, unsigned col); + + //-----------------------------------------------------------------------// + // Iteration functions. // + //-----------------------------------------------------------------------// + + /** Returns true iff the iterator is past the end of its row. */ + bool AtEnd() const + { return fIndex == ~0u; } + + virtual void Increment(); + virtual void Reset(); + +}; + +inline QcSparseMatrixRowIterator::QcSparseMatrixRowIterator( + const QcSparseMatrix &m, unsigned row) + : QcSparseMatrixIterator(m, row) +{ + qcAssertPre (row < m.getNRows()); + + Reset(); +} + +inline void QcSparseMatrixRowIterator::Increment() +{ + qcAssertPre (!AtEnd()); + + fCurrent = fCurrent->getNextInRow(); + fValue = fCurrent->getValue(); + fIndex = fCurrent->getColNr(); +} + +inline void QcSparseMatrixRowIterator::Reset() +{ + fCurrent = fMatrix->getFirstInRow( fVector); + fValue = fCurrent->getValue(); + fIndex = fCurrent->getColNr(); +} + +#endif diff --git a/src/kits/interface/qoca/QcState.hh b/src/kits/interface/qoca/QcState.hh new file mode 100644 index 0000000000..3d41d75166 --- /dev/null +++ b/src/kits/interface/qoca/QcState.hh @@ -0,0 +1,43 @@ +// $Id: QcState.hh,v 1.4 2000/12/06 05:32:56 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcStateH +#define __QcStateH + +#include + +class QcState +{ +public: + virtual ~QcState() { } + + //-----------------------------------------------------------------------// + // Utililty functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) = 0; +}; + +#endif diff --git a/src/kits/interface/qoca/QcStateVector.hh b/src/kits/interface/qoca/QcStateVector.hh new file mode 100644 index 0000000000..fd93cb8e77 --- /dev/null +++ b/src/kits/interface/qoca/QcStateVector.hh @@ -0,0 +1,175 @@ +// $Id: QcStateVector.hh,v 1.6 2000/11/29 01:58:42 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcStateVectorH +#define __QcStateVectorH + +#include +#include "qoca/QcDefines.hh" +#include "qoca/QcState.hh" + +/** Much like an STL vector, but with infrastructure for proper + initialization & cleanup of elements. */ +class QcStateVector +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcStateVector(); + virtual ~QcStateVector(); + +#ifndef NDEBUG + void assertInvar() + { + assert (fSize <= fAllocCount); + assert (fAllocCount <= fCapacity); + } + + virtual void virtualAssertLinkageInvar() const = 0; +#endif + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + unsigned GetSize() const + { return fSize; } + + /** @precondition i < GetSize(). + @postcondition ret != NULL + **/ + QcState *GetState(unsigned i) + { + qcAssertPre (i < fSize); + QcState *ret = fStates[i]; + qcAssertPost (ret != 0); + return ret; + } + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + virtual void FixLinkage() = 0; + + void Reserve(unsigned size); + + void Resize(unsigned size); + + virtual void Alloc(QcState **start, QcState **finish) = 0; + virtual void AddToList(QcState **start, QcState **finish) = 0; + virtual void RemoveFromList(QcState **start, QcState **finish) = 0; + + virtual void Print(ostream &os) const; + +protected: + QcState * const * const getAllocEnd() const + { + return fStates + fAllocCount; + } + +protected: + unsigned fSize; + unsigned fCapacity; + QcState **fStates; + +private: + unsigned fAllocCount; +}; + +inline QcStateVector::QcStateVector() + : fSize(0), fCapacity(0), fStates(0), fAllocCount(0) +{ +} + +inline QcStateVector::~QcStateVector() +{ + for (unsigned i = 0; i < fAllocCount; i++) + delete fStates[i]; + delete [] fStates; +} + +inline void QcStateVector::Print(ostream &os) const +{ + for (unsigned i = 0; i < fSize; i++) { + fStates[i]->Print(os); + os << endl; + } +} + +inline void QcStateVector::Reserve(unsigned cap) +{ + if (cap <= fCapacity) + return; + + QcState **oldStates = fStates; + fStates = new QcState*[cap]; + + memcpy(fStates, oldStates, fAllocCount * sizeof(QcState *)); + + fCapacity = cap; + + dbg(assertInvar()); +} + +#ifndef MAX +# define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b)) +#endif + +inline void QcStateVector::Resize(unsigned s) +{ + qcAssertPre( s <= fCapacity); + /* TODO: Remove either the above or the handling of + the fCapacity < s case below. */ + + if (s == fSize) + return; + + if (s < fSize) + { + RemoveFromList( fStates + s, + fStates + fSize); + } + else + { + if (fAllocCount < s) + { + if (fCapacity < s) + Reserve( MAX( s, fCapacity * 2)); + Alloc( fStates + fAllocCount, + fStates + s); + fAllocCount = s; + } + AddToList( fStates + fSize, + fStates + s); + } + + fSize = s; + + dbg(assertInvar()); + dbg(virtualAssertLinkageInvar()); +} + +#endif diff --git a/src/kits/interface/qoca/QcStructVarIndexIterator.hh b/src/kits/interface/qoca/QcStructVarIndexIterator.hh new file mode 100644 index 0000000000..9c82563c3f --- /dev/null +++ b/src/kits/interface/qoca/QcStructVarIndexIterator.hh @@ -0,0 +1,86 @@ +// $Id: QcStructVarIndexIterator.hh,v 1.5 2000/11/29 01:58:42 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcStructVarIndexIteratorH +#define __QcStructVarIndexIteratorH + +class QcStructVarIndexIterator +{ +public: + QcStructVarIndexIterator(const QcLinInEqTableau &tab); + +#if 0 + QcStructVarIndexIterator(const QcLinInEqColStateVector &csv) + : fColState( csv) + { + Reset(); + } +#endif + + bool AtEnd() const + { return (fCurrent == 0); } + + unsigned getIndex() const + { + qcAssertPre (!AtEnd()); + unsigned ret = fCurrent->fIndex; + qcAssertPost ((int) ret >= 0); + return ret; + } + + void Increment(); + void Reset(); + +private: + QcLinInEqColStateVector const &fColState; + QcLinInEqColState const *fCurrent; +}; + +inline QcStructVarIndexIterator::QcStructVarIndexIterator( + const QcLinInEqTableau &tab) + : fColState((QcLinInEqColStateVector const &)tab.GetColState()) +{ + Reset(); +} + +inline void QcStructVarIndexIterator::Increment() +{ + qcAssertPre (!AtEnd()); + fCurrent = fCurrent->getNextStructuralCol(); + qcAssertPost( AtEnd() + || (fCurrent->getCondition() + & QcLinInEqColState::fStructural)); +} + +inline void QcStructVarIndexIterator::Reset() +{ + fCurrent = fColState.fStructVarList; + qcAssertPost( AtEnd() + || (fCurrent->getCondition() + & QcLinInEqColState::fStructural)); +} + +#endif /* !__QcStructVarIndexIteratorH */ diff --git a/src/kits/interface/qoca/QcTableau.hh b/src/kits/interface/qoca/QcTableau.hh new file mode 100644 index 0000000000..bd734632f9 --- /dev/null +++ b/src/kits/interface/qoca/QcTableau.hh @@ -0,0 +1,222 @@ +// $Id: QcTableau.hh,v 1.11 2001/01/30 01:32:08 pmoulder Exp $ + +//============================================================================// +// Written by Alan Finlay and Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//----------------------------------------------------------------------------// + +#ifndef __QcTableauH +#define __QcTableauH + +#include "qoca/QcDefines.hh" +#include "qoca/QcBiMapNotifier.hh" + +// Forward declaration. +class QcRowAdaptor; + +/** Constraint tableau. Tableau rows correspond to contraints. Tableau columns + correspond to variables. RHS is a separately stored column. The tableau is + at a level of abstraction that does not access QcFloats, hence the + constraints represented in the tableau cannot be evaluated at this level. + The client maintains the mapping from variable index to QcFloat and + can evaluate a constraint using this information and a + QcSparseRowIterator. +**/ + +class QcTableau +{ +public: + enum {fInvalidVariableIndex = -1, fInvalidConstraintIndex = -1}; + +protected: + QcBiMapNotifier &fNotifier; // Must be initialised by constructors + QcConstraintBiMap &fOCBiMap; + QcVariableBiMap &fVBiMap; + +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcTableau(QcBiMapNotifier &n); + + virtual ~QcTableau() + { } + +#ifndef NDEBUG + void assertInvar() const { } + + void + assertDeepInvar() const + { + fNotifier.vAssertDeepInvar(); + fVBiMap.vAssertDeepInvar(); + fOCBiMap.vAssertDeepInvar(); + } + + virtual void + vAssertDeepInvar() const + { + assertDeepInvar(); + } +#endif + + //-----------------------------------------------------------------------// + // Data structure access functions. // + //-----------------------------------------------------------------------// + QcBiMapNotifier &getNotifier() + // GetNotifier is not particularly useful since the notifier + // base class interface is not intended for clients to use. + // The client oriented interface is in the derived class only. + { return fNotifier; } + + //-----------------------------------------------------------------------// + // Query functions. // + //-----------------------------------------------------------------------// + // The GetRows() and GetColumns() bounds are useful in determining the // + // size of the domain should a map from constraint index or variable // + // index be needed. It should not be assumed that all the values in the // + // stated range are utilised. For example when rows are removed from the// + // derived class QcLinEqTableau the constraint index for that row becomes// + // unused. GetValue() can be called for unused indices and will return // + // zero. // + //-----------------------------------------------------------------------// + virtual int GetColumns() const = 0; + virtual unsigned getNColumns() const = 0; + virtual int GetBasicVar(unsigned ci) const = 0; + // Indicates the basic variable for solved form constraint ci. + virtual numT GetRHS(unsigned ci) const = 0; + virtual int GetRows() const = 0; + virtual numT GetValue(unsigned ci, unsigned vi) const = 0; + virtual bool IsBasic(unsigned vi) const = 0; + virtual int IsBasicIn(unsigned vi) const = 0; + virtual bool IsRedundant(unsigned ci) const = 0; + // Indicates if the original constraint ci is redundant. + + virtual bool IsFree(unsigned vi) const; + // Indicates if a particular variable is in use (i.e. has a + // non-zero coefficient in any solved form (or original) constraint. + + //-----------------------------------------------------------------------// + // Manipulation functions. // + //-----------------------------------------------------------------------// + virtual int AddEq(QcRowAdaptor &varCoeffs, numT rhs) = 0; + // Returns the solved form constraint index of the new constraint. + virtual void ChangeRHS(unsigned ci, numT rhs) = 0; + // Change the RHS of the constraint ci. + + + /** Eliminate the basic variables from new original constraint ci + creating a new solved form constraint and returning this new index. + +

Call this method after addEq. + +

If the new constraint is consistant, Eliminate moves the row + condition from invalid to normalised or redundant. + +

The new solved form constraint still needs a Pivot to put it into + solved form. If the new solved form is inconsistant, the original + constraint is removed and InvalidCIndex is returned. If Eliminate + returns a valid index, the new solved form constraint may be + redundant. Check with IsRedundant before attempting a Pivot. + +

Eliminate updates the current PivotHints. + + @precondition ci < getNRows() + @precondition !fCoreTableau->GetARowDeleted(ci) + **/ + virtual int Eliminate(unsigned ci) = 0; + + /** Allocate a new variable column. */ + virtual unsigned NewVariable() = 0; + + virtual bool Pivot(unsigned ci, unsigned vi) = 0; + // Pivot returns true if successful, some derived classes may + // indicate failure, in which case the tableau is unchanged. + virtual void Restart() = 0; // Erase everything ready to start afresh. + + virtual int RemoveEq(unsigned ci); + // Removes an equation from the tableau given its original constraint + // index. Returns the corresponding solved form constraint index. + // After an equation is removed the CIndex values for the remaining + // equations are unchanged. CIndex values are not shifted up to + // remove the "hole" left by the removed equation. + + virtual bool RemoveVarix(unsigned vi); + // Remove the variable vi from the tableau. + + //-----------------------------------------------------------------------// + // Utility functions. // + //-----------------------------------------------------------------------// + virtual void Print(ostream &os) const; + virtual void TransitiveClosure(vector &vars); +}; + +inline QcTableau::QcTableau(QcBiMapNotifier &n) + : fNotifier(n), fOCBiMap(n.GetOCMap()), fVBiMap(n.GetVMap()) +{ +} + + +/* Note: the reason that IsFree, RemoveEq, RemoveVarix, + TransitiveClosure are here is that QcLinEqSystem has a var of type + QcLinEqTableau&, and QcDelLinEqSystem puts a QcDelLinEqTableau in + that var. Maybe we should separate QcLinEqSystem into the bits + that are and aren't shared with QcDelLinEqSystem, with the fTableau + var not being shared. The common base can define some abstract + methods to access the fTableau var. Advantage of splitting: type + safety and possible inlining/specialization advantages because the + compiler knows what type fTableau is. */ +inline bool QcTableau::IsFree(unsigned vi) const +{ + UNUSED(vi); + throw QcWarning("Error: Should not call QcTableau::IsFree"); + return false; +} + +inline void QcTableau::Print(ostream &os) const +{ + os << "Begin[Tableau]" << endl; + fNotifier.Print(os); + os << "End[Tableau]" << endl; +} + +inline int QcTableau::RemoveEq(unsigned ci) +{ + UNUSED(ci); + throw QcWarning("Error: Should not call QcTableau::RemoveEq"); + return fInvalidConstraintIndex; +} + +inline bool QcTableau::RemoveVarix(unsigned vi) +{ + UNUSED(vi); + throw QcWarning("Error: Should not call QcTableau::RemoveVar"); + return false; +} + +inline void QcTableau::TransitiveClosure(vector &vars) +{ + UNUSED(vars); + throw QcWarning("Error: Should not call QcTableau::TransitiveClosure"); +} + +#endif diff --git a/src/kits/interface/qoca/QcTableauColIterator.hh b/src/kits/interface/qoca/QcTableauColIterator.hh new file mode 100644 index 0000000000..0c6c8303b7 --- /dev/null +++ b/src/kits/interface/qoca/QcTableauColIterator.hh @@ -0,0 +1,58 @@ +// $Id: QcTableauColIterator.hh,v 1.7 2000/11/29 01:58:42 pmoulder Exp $ + +//============================================================================// +// Originally written by Sitt Sen Chok +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcTableauColIteratorH +#define __QcTableauColIteratorH + +#ifdef qcRealTableauCoeff +# include "qoca/QcSparseMatrixColIterator.hh" +#else +# include "qoca/QcNullIterator.H" +#endif + +class QcTableauColIterator +#ifdef qcRealTableauCoeff + : public QcSparseMatrixColIterator +#else + : public QcNullIterator +#endif +{ +public: + QcTableauColIterator (const QcLinEqTableau &tab, unsigned col); +}; + + +inline QcTableauColIterator::QcTableauColIterator(const QcLinEqTableau &tab, + unsigned col) +#ifdef qcRealTableauCoeff + : QcSparseMatrixColIterator (tab.GetCoreTableau().fSF.getCoeffs(), col) +#endif +{ + qcAssertPre (col < tab.getNColumns()); +} + + +#endif /* !__QcTableauColIteratorH */ diff --git a/src/kits/interface/qoca/QcTableauRowIterator.hh b/src/kits/interface/qoca/QcTableauRowIterator.hh new file mode 100644 index 0000000000..adc1daba8f --- /dev/null +++ b/src/kits/interface/qoca/QcTableauRowIterator.hh @@ -0,0 +1,59 @@ +// $Id: QcTableauRowIterator.hh,v 1.6 2000/11/29 01:58:42 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcTableauRowIteratorH +#define __QcTableauRowIteratorH + +#include "qoca/QcLinEqTableau.hh" +#ifdef qcRealTableauCoeff +# include "qoca/QcSparseMatrixRowIterator.hh" +#else +# include "qoca/QcNullIterator.H" +#endif + +class QcTableauRowIterator +#ifdef qcRealTableauCoeff + : public QcSparseMatrixRowIterator +#else + : public QcNullIterator +#endif +{ +public: + QcTableauRowIterator(const QcLinEqTableau &tab, unsigned row); +}; + + +inline QcTableauRowIterator::QcTableauRowIterator (const QcLinEqTableau &tab, + unsigned row) +#ifdef qcRealTableauCoeff + : QcSparseMatrixRowIterator (tab.GetCoreTableau().fSF.getCoeffs(), row) +#endif +{ + qcAssertPre (row < tab.getNRows()); +} + + +#endif /* !__QcTableauRowIteratorH */ diff --git a/src/kits/interface/qoca/QcUnsortedListSet.hh b/src/kits/interface/qoca/QcUnsortedListSet.hh new file mode 100644 index 0000000000..6514ac5eeb --- /dev/null +++ b/src/kits/interface/qoca/QcUnsortedListSet.hh @@ -0,0 +1,84 @@ +#ifndef __QcUnsortedListSetH +#define __QcUnsortedListSetH + +#include + +template +class QcUnsortedListSet +{ +public: + typedef T value_type; + typedef value_type* iterator; + typedef value_type const * const_iterator; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + +public: + QcUnsortedListSet() + : elements() + { + } + + QcUnsortedListSet(int initCapacity) + : elements(initCapacity) + { + } + + QcUnsortedListSet(int initCapacity, int increment) + : elements(initCapacity, increment) + { + } + + iterator begin() { return elements.begin(); } + iterator end() { return elements.end(); } + + iterator abegin() { return elements.begin(); } + iterator aend() { return elements.end(); } + + const_iterator abegin() const { return elements.begin(); } + const_iterator aend() const { return elements.end(); } + + void clear() + { + elements.clear(); + } + + iterator erase(iterator position) + { + if (position + 1 < elements.end()) + *position = elements.back(); + elements.pop_back(); + return position; + } + + void push_back(const T& x) + { + elements.push_back(x); + } + + reference operator[](size_type n) + { return elements[n]; } + + const_reference operator[](size_type n) const + { return elements[n]; } + + void resize(size_type new_size) + { + elements.resize(new_size); + } + + size_type size() const + { + return elements.size(); + } + +private: + /* effic: We should allow a version implemented as a subclass instead of + using the extra indirection of an instance variable. + + (The reason for using an instance variable is so that we can control + the interface.) */ + vector elements; +}; +#endif /* !__QcUnsortedListSetH */ diff --git a/src/kits/interface/qoca/QcUtility.hh b/src/kits/interface/qoca/QcUtility.hh new file mode 100644 index 0000000000..f0a71e6ff2 --- /dev/null +++ b/src/kits/interface/qoca/QcUtility.hh @@ -0,0 +1,135 @@ +// $Id: QcUtility.hh,v 1.10 2000/12/13 07:18:32 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcUtilityH +#define __QcUtilityH + +#include "qoca/QcDefines.hh" + +class QcUtility +{ +#if NUMT_IS_DOUBLE +private: + static double const qcEps = 2.273736754432321e-13; // 2 ** -42 + static double const qcNearEps = 9.313225746154785e-10; // 2 ** -30 + static double const qcVaguelyNearEps = 9.5367431640625e-7; // 2 ** -20 + +public: + /** Highest numT x s.t. IsZero(x). + This is a positive (non-zero) number iff numT is floating point. */ + static double const qcMaxZeroVal = qcEps * (1 - DBL_EPSILON / 2); + +public: + //-----------------------------------------------------------------------// + // We need some conventions about when small values are converted // + // to 0.0 or we will be performing unnecessary isZero tests. // + // Generally we don't want to test and "zeroise" values every time // + // a calculation is done (e.g. matrix row operations) since the values // + // may never need to be compared with zero anyway. Better to take // + // care where efficiency may be impacted to ensure the test is only // + // done once, and where there is no efficiency impact, be cautious // + // and do isZero tests which are not strictly necessary - with // + // a comment to this effect. Note that sparse iterators which by // + // definition do not return zero coefficients should do the isZero // + // test, clients do not need to repeat this test. // + //-----------------------------------------------------------------------// + + static bool IsVaguelyZero(numT val) + { return fabs( val) < qcVaguelyNearEps; } + + static bool IsNearZero(numT val) + { return fabs( val) < qcNearEps; } + + static bool IsZero(double val) + { return fabs( val) < qcEps; } + + static bool IsOne(double val) + { return IsZero( val - 1.0); } + + static bool IsNegative(numT val) + { return (val <= -qcEps); } + + static bool IsPositive(numT val) + { return (val >= qcEps); } + + static double Zeroise(double val) + { + return (IsZero( val) + ? 0.0 + : val); + } + +#ifndef NDEBUG + static bool IsZeroised(double val) + { + return (val == 0 || !IsZero( val)); + } +#endif + + /** Return true iff x is neither NaN nor +/- infinity. */ + static bool isFinite( double x) + { +#ifdef isfinite + return isfinite( x); +#else + return x * 0.0 == 0.0; +#endif + } +#elif NUMT_IS_PJM_MPQ +public: + static unsigned long const qcMaxZeroVal = 0ul; + + static bool IsNegative(numT val) + { return val < 0; } + static bool IsPositive(numT val) + { return val > 0; } + static bool IsZero(numT val) + { return val == 0; } + static bool IsNearZero(numT val) + { return val == 0; } + static bool IsVaguelyZero(numT val) + { return val == 0; } + static bool IsOne(numT val) + { return val == 1; } + static numT Zeroise(numT val) + { return val; } + static bool isFinite(numT val) + { return val.isFinite(); } + +# ifndef NDEBUG + static bool IsZeroised(numT val) + { + UNUSED(val); + return true; + } +# endif + +#else +# error "Unknown numT" +#endif +}; + +#endif diff --git a/src/kits/interface/qoca/QcVarStow.H b/src/kits/interface/qoca/QcVarStow.H new file mode 100644 index 0000000000..96757a454b --- /dev/null +++ b/src/kits/interface/qoca/QcVarStow.H @@ -0,0 +1,124 @@ +// Generated automatically from QcVarStow.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcVarStowDCL +#define QcVarStowDCL +#line 1 "QcVarStow.ch" +#include +#ifdef QC_USING_NLPSOLVER + + +#include +#include +#include + + +#line 13 "QcVarStow.ch" +class QcVarStow +{ +public: + + +QcVarStow(); +#line 27 "QcVarStow.ch" +#ifndef NDEBUG + +void +assertInvar() const; +#line 39 "QcVarStow.ch" +#endif + +inline unsigned +size() const; +#line 47 "QcVarStow.ch" +inline unsigned +getVarIx( QcFloatRep *v) const; +#line 56 "QcVarStow.ch" +void +ensurePresent(QcFloatRep *v); +#line 73 "QcVarStow.ch" +inline bool +constrCacheValid() const; +#line 79 "QcVarStow.ch" +/** Equivalent to ensurePresent(v); incUsage(v);. + @precondition v != 0 +**/ +void +addReference(QcFloatRep *v); +#line 102 "QcVarStow.ch" +/** If v is present and has usage count 0, then remove v and + return true; otherwise return false. + + @precondition v != 0 +**/ +bool +tryRemove(QcFloatRep *v); +#line 145 "QcVarStow.ch" +void +incUsage( QcFloatRep *v); +#line 157 "QcVarStow.ch" +void +decUsage( QcFloatRep *v); +#line 168 "QcVarStow.ch" +inline unsigned +getUsage(QcFloatRep *v) const; +#line 178 "QcVarStow.ch" +inline double * +getSolvedValArray(); +#line 186 "QcVarStow.ch" +inline double const * +getSolvedValArray() const; +#line 194 "QcVarStow.ch" +typedef vector::const_iterator var_const_iterator; +typedef vector::iterator var_iterator; + +inline QcVarStow::var_const_iterator +vars_begin() const; +#line 203 "QcVarStow.ch" +inline QcVarStow::var_const_iterator +vars_end() const; +#line 209 "QcVarStow.ch" +inline QcVarStow::var_iterator +vars_begin(); +#line 215 "QcVarStow.ch" +inline QcVarStow::var_iterator +vars_end(); +#line 222 "QcVarStow.ch" +bool +isPresent( QcFloatRep *v) const; +#line 229 "QcVarStow.ch" +private: + +bool +presentAndReferenced( QcFloatRep *v) const; +#line 243 "QcVarStow.ch" +public: +bool fConstrCacheValid; + +private: +vector fSolvedVals; +vector fVars; +vector fCounts; +typedef hash_map Var2Ix_T; +Var2Ix_T fVar2Ix; + +}; + +#else /* !QC_USING_NLPSOLVER */ +// Make the linker happy. + + +void +QcVarStow_dummy(); +#line 265 "QcVarStow.ch" +#endif /* !QC_USING_NLPSOLVER */ + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcVarStowDCL */ diff --git a/src/kits/interface/qoca/QcVarStow.cc b/src/kits/interface/qoca/QcVarStow.cc new file mode 100644 index 0000000000..0bdf3c38ed --- /dev/null +++ b/src/kits/interface/qoca/QcVarStow.cc @@ -0,0 +1,183 @@ +// Generated automatically from QcVarStow.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcVarStow.hh" +#line 1 "QcVarStow.ch" + +#ifdef QC_USING_NLPSOLVER + + +#line 10 "QcVarStow.ch" +#include + + + + + + + +QcVarStow::QcVarStow() + : fConstrCacheValid( false), + fSolvedVals(), + fVars(), + fVar2Ix() +{ +} + + +#ifndef NDEBUG + +void +QcVarStow::assertInvar() const +{ + unsigned n = size(); + assert( fSolvedVals.size() == n); + assert( fVars.size() == n); + assert( fVar2Ix.size() == n); + assert( fCounts.size() == n); + /* TODO: assert that fVars is consistent with fVar2Ix. */ +} +#endif + +#line 56 "QcVarStow.ch" +void +QcVarStow::ensurePresent(QcFloatRep *v) +{ + qcAssertPre( v != 0); + + pair ins( v, fVars.size()); + pair res = fVar2Ix.insert( ins); + if (!res.second) + return; // already present + + fVars.push_back( v); + fSolvedVals.push_back( dbl_val( v->Value())); + fCounts.push_back( 0); + + dbg(assertInvar()); +} + +#line 82 "QcVarStow.ch" +void +QcVarStow::addReference(QcFloatRep *v) +{ + qcAssertPre( v != 0); + + pair ins( v, fVars.size()); + pair res = fVar2Ix.insert( ins); + if (res.second) + { + fVars.push_back( v); + fSolvedVals.push_back( dbl_val( v->Value())); + fCounts.push_back( 1); + } + else + fCounts[res.first->second]++; + + dbg(assertInvar()); + qcAssertPost( presentAndReferenced( v)); +} + + +#line 107 "QcVarStow.ch" +bool +QcVarStow::tryRemove(QcFloatRep *v) +{ + qcAssertPre( v != 0); + + Var2Ix_T::iterator v_i = fVar2Ix.find( v); + if (v_i == fVar2Ix.end()) + return false; + unsigned v_ix = v_i->second; + assert( v_ix < fVars.size()); + if( fCounts[v_ix] != 0) + return false; + + unsigned e_ix = fVars.size() - 1; + if (v_ix != e_ix) + { + fVars[v_ix] = fVars[e_ix]; + { + Var2Ix_T::iterator e_i = fVar2Ix.find( fVars[e_ix]); + assert( e_i != fVar2Ix.end()); + assert( e_i->second == e_ix); + e_i->second = v_ix; + } + fSolvedVals[v_ix] = fSolvedVals[e_ix]; + fCounts[v_ix] = fCounts[e_ix]; + if (fCounts[e_ix] != 0) + fConstrCacheValid = false; + } + fVars.pop_back(); + fSolvedVals.pop_back(); + fCounts.pop_back(); + fVar2Ix.erase( v_i); + + dbg(assertInvar()); + return true; +} + + +void +QcVarStow::incUsage( QcFloatRep *v) +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + qcAssertPre( i != fVar2Ix.end()); + unsigned vi = i->second; + assert( vi < fCounts.size()); + fCounts[vi]++; + qcAssertPost( fCounts[vi] != 0); +} + + +void +QcVarStow::decUsage( QcFloatRep *v) +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + qcAssertPre( i != fVar2Ix.end()); + unsigned vi = i->second; + assert( vi < fCounts.size()); + qcAssertPre( fCounts[vi] != 0); + fCounts[vi]--; +} + +#line 222 "QcVarStow.ch" +bool +QcVarStow::isPresent( QcFloatRep *v) const +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + return (i != fVar2Ix.end()); +} + + + +bool +QcVarStow::presentAndReferenced( QcFloatRep *v) const +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + if (i == fVar2Ix.end()) + return false; + unsigned ix = i->second; + assert( ix < fCounts.size()); + return fCounts[ix] != 0; +} + + +#line 256 "QcVarStow.ch" +#else /* !QC_USING_NLPSOLVER */ +// Make the linker happy. + + +void +QcVarStow_dummy() +{ +} + +#endif /* !QC_USING_NLPSOLVER */ + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcVarStow.ch b/src/kits/interface/qoca/QcVarStow.ch new file mode 100644 index 0000000000..6421e85b96 --- /dev/null +++ b/src/kits/interface/qoca/QcVarStow.ch @@ -0,0 +1,274 @@ +//o[d] #include +#ifdef QC_USING_NLPSOLVER + +//begin o[d] +#include +#include +#include +//end o[d] +//begin o[c] +#include +//end o[c] + +//o[d] class QcVarStow +//o[d] { +//o[d] public: + +//cf +QcVarStow() + : fConstrCacheValid( false), + fSolvedVals(), + fVars(), + fVar2Ix() +{ +} + + +#ifndef NDEBUG +//cf +void +assertInvar() const +{ + unsigned n = size(); + assert( fSolvedVals.size() == n); + assert( fVars.size() == n); + assert( fVar2Ix.size() == n); + assert( fCounts.size() == n); + /* TODO: assert that fVars is consistent with fVar2Ix. */ +} +#endif + +inline unsigned +size() const +{ + return fVars.size(); +} + +inline unsigned +getVarIx( QcFloatRep *v) const +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + qcAssertPre( i != fVar2Ix.end()); + return i->second; +} + +//cf +void +ensurePresent(QcFloatRep *v) +{ + qcAssertPre( v != 0); + + pair ins( v, fVars.size()); + pair res = fVar2Ix.insert( ins); + if (!res.second) + return; // already present + + fVars.push_back( v); + fSolvedVals.push_back( dbl_val( v->Value())); + fCounts.push_back( 0); + + dbg(assertInvar()); +} + +inline bool +constrCacheValid() const +{ + return fConstrCacheValid; +} + +/** Equivalent to ensurePresent(v); incUsage(v);. + @precondition v != 0 +**/ //cf +void +addReference(QcFloatRep *v) +{ + qcAssertPre( v != 0); + + pair ins( v, fVars.size()); + pair res = fVar2Ix.insert( ins); + if (res.second) + { + fVars.push_back( v); + fSolvedVals.push_back( dbl_val( v->Value())); + fCounts.push_back( 1); + } + else + fCounts[res.first->second]++; + + dbg(assertInvar()); + qcAssertPost( presentAndReferenced( v)); +} + +/** If v is present and has usage count 0, then remove v and + return true; otherwise return false. + + @precondition v != 0 +**/ //cf +bool +tryRemove(QcFloatRep *v) +{ + qcAssertPre( v != 0); + + Var2Ix_T::iterator v_i = fVar2Ix.find( v); + if (v_i == fVar2Ix.end()) + return false; + unsigned v_ix = v_i->second; + assert( v_ix < fVars.size()); + if( fCounts[v_ix] != 0) + return false; + + unsigned e_ix = fVars.size() - 1; + if (v_ix != e_ix) + { + fVars[v_ix] = fVars[e_ix]; + { + Var2Ix_T::iterator e_i = fVar2Ix.find( fVars[e_ix]); + assert( e_i != fVar2Ix.end()); + assert( e_i->second == e_ix); + e_i->second = v_ix; + } + fSolvedVals[v_ix] = fSolvedVals[e_ix]; + fCounts[v_ix] = fCounts[e_ix]; + if (fCounts[e_ix] != 0) + fConstrCacheValid = false; + } + fVars.pop_back(); + fSolvedVals.pop_back(); + fCounts.pop_back(); + fVar2Ix.erase( v_i); + + dbg(assertInvar()); + return true; +} + +//cf +void +incUsage( QcFloatRep *v) +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + qcAssertPre( i != fVar2Ix.end()); + unsigned vi = i->second; + assert( vi < fCounts.size()); + fCounts[vi]++; + qcAssertPost( fCounts[vi] != 0); +} + +//cf +void +decUsage( QcFloatRep *v) +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + qcAssertPre( i != fVar2Ix.end()); + unsigned vi = i->second; + assert( vi < fCounts.size()); + qcAssertPre( fCounts[vi] != 0); + fCounts[vi]--; +} + +inline unsigned +getUsage(QcFloatRep *v) const +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + qcAssertPre( i != fVar2Ix.end()); + unsigned vi = i->second; + assert( vi < fCounts.size()); + return fCounts[vi]; +} + +inline double * +getSolvedValArray() +{ + qcAssertPost( fSolvedVals.size() == size()); + + return fSolvedVals.begin(); +} + +inline double const * +getSolvedValArray() const +{ + qcAssertPost( fSolvedVals.size() == size()); + + return fSolvedVals.begin(); +} + +typedef vector::const_iterator var_const_iterator; +typedef vector::iterator var_iterator; + +inline QcVarStow::var_const_iterator +vars_begin() const +{ + return fVars.begin(); +} + +inline QcVarStow::var_const_iterator +vars_end() const +{ + return fVars.end(); +} + +inline QcVarStow::var_iterator +vars_begin() +{ + return fVars.begin(); +} + +inline QcVarStow::var_iterator +vars_end() +{ + return fVars.end(); +} + +//cf +bool +isPresent( QcFloatRep *v) const +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + return (i != fVar2Ix.end()); +} + +//ho private: +//cf +bool +presentAndReferenced( QcFloatRep *v) const +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + if (i == fVar2Ix.end()) + return false; + unsigned ix = i->second; + assert( ix < fCounts.size()); + return fCounts[ix] != 0; +} + +//begin o[d] +public: +bool fConstrCacheValid; + +private: +vector fSolvedVals; +vector fVars; +vector fCounts; +typedef hash_map Var2Ix_T; +Var2Ix_T fVar2Ix; +//end o[d] +//o[d] }; + +#else /* !QC_USING_NLPSOLVER */ +// Make the linker happy. +//$class_prefix= +//cf +void +QcVarStow_dummy() +{ +} + +#endif /* !QC_USING_NLPSOLVER */ + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcVarStow.hh b/src/kits/interface/qoca/QcVarStow.hh new file mode 100644 index 0000000000..3eb5f985fc --- /dev/null +++ b/src/kits/interface/qoca/QcVarStow.hh @@ -0,0 +1,111 @@ +// Generated automatically from QcVarStow.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcVarStow.H" +#ifndef QcVarStowIFN +#define QcVarStowIFN +#line 1 "QcVarStow.ch" + +#ifdef QC_USING_NLPSOLVER + + +#line 27 "QcVarStow.ch" +#ifndef NDEBUG + +#line 39 "QcVarStow.ch" +#endif + +inline unsigned +QcVarStow::size() const +{ + return fVars.size(); +} + +inline unsigned +QcVarStow::getVarIx( QcFloatRep *v) const +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + qcAssertPre( i != fVar2Ix.end()); + return i->second; +} + + +#line 73 "QcVarStow.ch" +inline bool +QcVarStow::constrCacheValid() const +{ + return fConstrCacheValid; +} + + +#line 168 "QcVarStow.ch" +inline unsigned +QcVarStow::getUsage(QcFloatRep *v) const +{ + Var2Ix_T::const_iterator i = fVar2Ix.find( v); + qcAssertPre( i != fVar2Ix.end()); + unsigned vi = i->second; + assert( vi < fCounts.size()); + return fCounts[vi]; +} + +inline double * +QcVarStow::getSolvedValArray() +{ + qcAssertPost( fSolvedVals.size() == size()); + + return fSolvedVals.begin(); +} + +inline double const * +QcVarStow::getSolvedValArray() const +{ + qcAssertPost( fSolvedVals.size() == size()); + + return fSolvedVals.begin(); +} + + + + +inline QcVarStow::var_const_iterator +QcVarStow::vars_begin() const +{ + return fVars.begin(); +} + +inline QcVarStow::var_const_iterator +QcVarStow::vars_end() const +{ + return fVars.end(); +} + +inline QcVarStow::var_iterator +QcVarStow::vars_begin() +{ + return fVars.begin(); +} + +inline QcVarStow::var_iterator +QcVarStow::vars_end() +{ + return fVars.end(); +} + + +#line 256 "QcVarStow.ch" +#else /* !QC_USING_NLPSOLVER */ +// Make the linker happy. + + +#line 265 "QcVarStow.ch" +#endif /* !QC_USING_NLPSOLVER */ + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcVarStowIFN */ diff --git a/src/kits/interface/qoca/QcVariableBiMap.H b/src/kits/interface/qoca/QcVariableBiMap.H new file mode 100644 index 0000000000..0dc1db7b09 --- /dev/null +++ b/src/kits/interface/qoca/QcVariableBiMap.H @@ -0,0 +1,65 @@ +// Generated automatically from QcVariableBiMap.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef QcVariableBiMapDCL +#define QcVariableBiMapDCL +#line 1 "QcVariableBiMap.ch" + +#include +#include +#include + + +#line 14 "QcVariableBiMap.ch" +#define super QcAliasedBiMap + +class QcVariableBiMap + : public super +{ + + +public: + QcVariableBiMap() + : super() + { + } + + +#ifndef NDEBUG + +void +assertInvar() const; +#line 40 "QcVariableBiMap.ch" +void +assertDeepInvar() const; +#line 48 "QcVariableBiMap.ch" +virtual void +vAssertDeepInvar() const; +#line 53 "QcVariableBiMap.ch" +#endif + + +void +Update(QcFloat const &ident, int index); +#line 64 "QcVariableBiMap.ch" +void +Update(QcFloatRep *ident, int index); +#line 72 "QcVariableBiMap.ch" +//-----------------------------------------------------------------------// +// Query functions // +//-----------------------------------------------------------------------// + +void +GetVariableSet(vector &vars); +#line 100 "QcVariableBiMap.ch" +}; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcVariableBiMapDCL */ diff --git a/src/kits/interface/qoca/QcVariableBiMap.cc b/src/kits/interface/qoca/QcVariableBiMap.cc new file mode 100644 index 0000000000..eb39def46c --- /dev/null +++ b/src/kits/interface/qoca/QcVariableBiMap.cc @@ -0,0 +1,100 @@ +// Generated automatically from QcVariableBiMap.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcVariableBiMap.hh" +#line 1 "QcVariableBiMap.ch" + +#line 10 "QcVariableBiMap.ch" +#include + + + +#define super QcAliasedBiMap + + + + + + +#line 28 "QcVariableBiMap.ch" +#ifndef NDEBUG + +void +QcVariableBiMap::assertInvar() const +{ + for(TIdentifierMap::const_iterator + i = fIdentifierMap.begin(), iEnd = fIdentifierMap.end(); + i != iEnd; i++) + assert( i->first.pointer()->isQcFloatRep()); +} + + +void +QcVariableBiMap::assertDeepInvar() const +{ + super::assertDeepInvar(); + assertInvar(); +} + + +void +QcVariableBiMap::vAssertDeepInvar() const +{ + assertDeepInvar(); +} +#endif + + +void +QcVariableBiMap::Update(QcFloat const &ident, int index) +{ + super::Update( ident, index); + dbg( assertInvar()); +} + + +void +QcVariableBiMap::Update(QcFloatRep *ident, int index) +{ + super::Update( ident, index); + dbg( assertInvar()); +} + + +//-----------------------------------------------------------------------// +// Query functions // +//-----------------------------------------------------------------------// + +void +QcVariableBiMap::GetVariableSet(vector &vars) +{ + unsigned size = GetSize(); + + for(unsigned i = 0; i < size; i++) + { + QcNullableFloat &nf = fIndexMap[i]; + if(nf.isDead()) + continue; + + QcFloat &f = reinterpret_cast(nf); + + if (f.Name()[0] == '\0') + { + char name[20]; + sprintf(name, "$%ld", f.Id()); + f.SetName(name); + } + + vars.push_back(f); + } +} + + + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcVariableBiMap.ch b/src/kits/interface/qoca/QcVariableBiMap.ch new file mode 100644 index 0000000000..94bab001fa --- /dev/null +++ b/src/kits/interface/qoca/QcVariableBiMap.ch @@ -0,0 +1,110 @@ +//begin o[d] +#include +#include +#include +//end o[d] +//begin o[i] +#include +//end o[i] +//begin o[c] +#include +//end o[c] + + +#define super QcAliasedBiMap + +//o[d] class QcVariableBiMap +//o[d] : public super +//o[d] { + +//begin o[d] +public: + QcVariableBiMap() + : super() + { + } +//end o[d] + +#ifndef NDEBUG +//cf +void +assertInvar() const +{ + for(TIdentifierMap::const_iterator + i = fIdentifierMap.begin(), iEnd = fIdentifierMap.end(); + i != iEnd; i++) + assert( i->first.pointer()->isQcFloatRep()); +} + +//cf +void +assertDeepInvar() const +{ + super::assertDeepInvar(); + assertInvar(); +} + +//cf +virtual void +vAssertDeepInvar() const +{ + assertDeepInvar(); +} +#endif + +//cf +void +Update(QcFloat const &ident, int index) +{ + super::Update( ident, index); + dbg( assertInvar()); +} + +//cf +void +Update(QcFloatRep *ident, int index) +{ + super::Update( ident, index); + dbg( assertInvar()); +} + + +//-----------------------------------------------------------------------// +// Query functions // +//-----------------------------------------------------------------------// +//cf +void +GetVariableSet(vector &vars) +{ + unsigned size = GetSize(); + + for(unsigned i = 0; i < size; i++) + { + QcNullableFloat &nf = fIndexMap[i]; + if(nf.isDead()) + continue; + + QcFloat &f = reinterpret_cast(nf); + + if (f.Name()[0] == '\0') + { + char name[20]; + sprintf(name, "$%ld", f.Id()); + f.SetName(name); + } + + vars.push_back(f); + } +} + +//o[d] }; + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/interface/qoca/QcVariableBiMap.hh b/src/kits/interface/qoca/QcVariableBiMap.hh new file mode 100644 index 0000000000..bb56638824 --- /dev/null +++ b/src/kits/interface/qoca/QcVariableBiMap.hh @@ -0,0 +1,41 @@ +// Generated automatically from QcVariableBiMap.ch by /home/pmoulder/usr/local/bin/ch2xx. +#include "QcVariableBiMap.H" +#ifndef QcVariableBiMapIFN +#define QcVariableBiMapIFN +#line 1 "QcVariableBiMap.ch" + +#line 7 "QcVariableBiMap.ch" +#include + + +#line 14 "QcVariableBiMap.ch" +#define super QcAliasedBiMap + + + + + + +#line 28 "QcVariableBiMap.ch" +#ifndef NDEBUG + +#line 53 "QcVariableBiMap.ch" +#endif + + +#line 72 "QcVariableBiMap.ch" +//-----------------------------------------------------------------------// +// Query functions // +//-----------------------------------------------------------------------// + +#line 103 "QcVariableBiMap.ch" +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !QcVariableBiMapIFN */ diff --git a/src/kits/interface/qoca/QcVariableIndexIterator.hh b/src/kits/interface/qoca/QcVariableIndexIterator.hh new file mode 100644 index 0000000000..f99136da03 --- /dev/null +++ b/src/kits/interface/qoca/QcVariableIndexIterator.hh @@ -0,0 +1,75 @@ +// $Id: QcVariableIndexIterator.hh,v 1.4 2000/11/26 02:17:51 pmoulder Exp $ + +//============================================================================// +// Written by Sitt Sen Chok // +//----------------------------------------------------------------------------// +// The QOCA implementation is free software, but it is Copyright (C) // +// 1994-1999 Monash University. It is distributed under the terms of the GNU // +// General Public License. See the file COPYING for copying permission. // +// // +// The QOCA toolkit and runtime are distributed under the terms of the GNU // +// Library General Public License. See the file COPYING.LIB for copying // +// permissions for those files. // +// // +// If those licencing arrangements are not satisfactory, please contact us! // +// We are willing to offer alternative arrangements, if the need should arise.// +// // +// THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR // +// IMPLIED. ANY USE IS AT YOUR OWN RISK. // +// // +// Permission is hereby granted to use or copy this program for any purpose, // +// provided the above notices are retained on all copies. Permission to // +// modify the code and to distribute modified code is granted, provided the // +// above notices are retained, and a notice that the code was modified is // +// included with the above copyright notice. // +//============================================================================// + +#ifndef __QcVariableIndexIteratorH +#define __QcVariableIndexIteratorH + +class QcVariableIndexIterator +{ +public: + //-----------------------------------------------------------------------// + // Constructor. // + //-----------------------------------------------------------------------// + QcVariableIndexIterator (const QcTableau &tab); + + unsigned getIndex() const + { + return fIndex; + } + + //-----------------------------------------------------------------------// + // Iteration functions. // + //-----------------------------------------------------------------------// + bool AtEnd() const + { + return (fIndex == fColumns); + } + + void Increment() + { + qcAssertPre (!AtEnd()); + fIndex++; + } + + void Reset() + { + fIndex = 0; + } + +private: + unsigned fColumns; + unsigned fIndex; +}; + + +inline +QcVariableIndexIterator::QcVariableIndexIterator (const QcTableau &tab) + : fColumns (tab.getNColumns()) +{ + Reset(); +} + +#endif /* !__QcVariableIndexIteratorH */ diff --git a/src/kits/interface/qoca/arith.H b/src/kits/interface/qoca/arith.H new file mode 100644 index 0000000000..8605ebd261 --- /dev/null +++ b/src/kits/interface/qoca/arith.H @@ -0,0 +1,381 @@ +// Generated automatically from arith.ch by /home/pmoulder/usr/local/bin/ch2xx. +#ifndef arithDCL +#define arithDCL +#line 1 "arith.ch" + +#include +#include + +#if NUMT_IS_DOUBLE +typedef double numT; + + inline void + make_neg (double &x) + { + x = -x; + } + + inline void + reciprocate (double &x) + { + x = 1/x; + } + + inline double + dbl_val (double x) + { + return x; + } + + inline bool + is_zero (double x) + { + return x == 0.0; + } + + inline double + recip( double x) + { + return 1.0 / x; + } + +#elif NUMT_IS_PJM_MPQ +/* pjm's own hacked-up toy gmp wrapper */ +# include + +class mpq; +typedef mpq numT; + +class mpq +{ +public: + mpq() + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + } + + mpq( mpq const &other) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + mpq_set( rep, other.rep); + } + + mpq( long int n) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + if (n != 0) + mpq_set_si (rep, n, 1ul); + } + + mpq (int n) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + if (n != 0) + mpq_set_si (rep, n, 1ul); + } + + mpq (unsigned int n) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + if (n != 0) + mpq_set_ui (rep, n, 1ul); + } + + mpq (unsigned long n, unsigned long d = 1) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + if ((n != 0) || (d == 0)) + mpq_set_ui( rep, n, d); + if (d != 1) + mpq_canonicalize( rep); + } + + mpq (double x) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + if (x != 0.0) // common special case. + { + mpq_set_d( rep, x); + mpq_canonicalize( rep); + } + } + + ~mpq() + { + assertIsMpq(); + mpq_clear (rep); + fMagic = 0; + } + + void assertIsMpq() const + { + assert( fMagic == MPQ_MAGIC); + } + + mpq &operator=(mpq const &other) + { + assertIsMpq(); + mpq_set( rep, other.rep); + return *this; + } + + mpq &operator+= (mpq const &other) + { + assertIsMpq(); + mpq_add (rep, rep, other.rep); + return *this; + } + + mpq &operator-= (mpq const &other) + { + assertIsMpq(); + mpq_sub (rep, rep, other.rep); + return *this; + } + + mpq &operator*= (mpq const &other) + { + assertIsMpq(); + mpq_mul (rep, rep, other.rep); + return *this; + } + + mpq &operator/= (mpq const &other) + { + assertIsMpq(); + mpq_div (rep, rep, other.rep); + return *this; + } + + mpq operator* (mpq const &other) const + { + assertIsMpq(); + mpq prod; + mpq_mul( prod.rep, rep, other.rep); + return prod; + } + + mpq operator* (unsigned other) const + { + assertIsMpq(); + mpq prod( other); + mpq_mul( prod.rep, rep, prod.rep); + return prod; + } + + mpq operator/ (mpq const &other) const + { + assertIsMpq(); + mpq quotient; + mpq_div( quotient.rep, rep, other.rep); + return quotient; + } + + mpq operator+ (mpq const &other) const + { + assertIsMpq(); + mpq sum; + mpq_add( sum.rep, rep, other.rep); + return sum; + } + + mpq operator- (mpq const &other) const + { + assertIsMpq(); + mpq diff; + mpq_sub( diff.rep, rep, other.rep); + return diff; + } + + bool operator< (mpq const &other) const + { + assertIsMpq(); + return mpq_cmp( rep, other.rep) < 0; + } + + bool operator> (mpq const &other) const + { return mpq_cmp( rep, other.rep) > 0; } + + bool operator== (mpq const &other) const + { return mpq_equal( rep, other.rep); } + + bool operator!= (mpq const &other) const + { return !mpq_equal( rep, other.rep); } + + bool operator< (int x) const + { + assertIsMpq(); + if (x == 0) + return mpq_sgn( rep) < 0; + else + abort(); + } + + bool operator> (int x) const + { + assertIsMpq(); + if (x == 0) + return mpq_sgn( rep) > 0; + else + abort(); + } + + bool operator>= (int x) const + { + assertIsMpq(); + if (x == 0) + return mpq_sgn( rep) >= 0; + else + abort(); + } + + bool operator== (int x) const + { + assertIsMpq(); + if (x == 0) + return mpq_sgn( rep) == 0; + else if (x > 0) + return mpq_cmp_ui( rep, x, 1u) == 0; + else + abort(); + } + + bool operator== (double x) const + { + assertIsMpq(); + if (x == 0.0) + return mpq_sgn( rep) == 0; + else + abort(); + } + + bool isFinite() const + { + assertIsMpq(); + return mpz_sgn( &rep[0]._mp_den); + } + + long get_lround() const + { + assertIsMpq(); + return lround( mpq_get_d( rep)); + } + + mpz_srcptr get_num_mpz_t() const + { return mpq_numref( rep); } + + mpz_srcptr get_den_mpz_t() const + { return mpq_denref( rep); } + +public: + mpq_t rep; +private: + unsigned fMagic; + static unsigned const MPQ_MAGIC = 0xc04546fb; // from /dev/random +}; + + inline void + make_neg (mpq &x) + { + mpq_neg (x.rep, x.rep); + } + + inline void + reciprocate (mpq &x) + { + mpq_inv (x.rep, x.rep); + } + + inline mpq + recip( mpq const &x) + { + mpq r; + mpq_inv( r.rep, x.rep); + return r; + } + + inline double + dbl_val (mpq const &x) + { + return mpq_get_d (x.rep); + } + + inline bool + is_zero (mpq const &x) + { + return mpq_sgn (x.rep) == 0; + } + + // it should be better to define mp_free in the library + extern "C" { + extern void (*__gmp_free_func)(void *, size_t); + } + inline void mp_free(void *ptr, size_t size) + { + (*__gmp_free_func)(ptr, size); + } + +# ifndef qcNoStream +# include + inline ostream & operator<<(ostream &o, const mpq &q) + { +# if 0 + char *num = mpz_get_str(0, 10, q.get_num_mpz_t()); + o << num; + mp_free(num, strlen(num)+1); + if (mpz_cmp_ui(q.get_den_mpz_t(), 1)) + { + char *den = mpz_get_str(0, 10, q.get_den_mpz_t()); + o << '/' << den; + mp_free(den, strlen(den)+1); + } + return o; +# else + o << dbl_val(q); + return o; +# endif + } +# endif + + inline numT operator-(const numT &x) + { + numT ret = x; + make_neg( ret); + return ret; + } + + inline numT fabs(numT const &x) + { + numT ret = x; + if (mpq_sgn( ret.rep) < 0) + ret.rep[0]._mp_num._mp_size = - ret.rep[0]._mp_num._mp_size; + return ret; + } + +#elif NUMT_IS_GB_MPQ +/* Gerardo Ballabio's sophisticated gmp wrapper. */ +# include "g++.h" +typedef mpq_class numT; + +#else +# error "Don't know numT type." +#endif + + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ + +#endif /* !arithDCL */ diff --git a/src/kits/interface/qoca/arith.ch b/src/kits/interface/qoca/arith.ch new file mode 100644 index 0000000000..092e0ffe72 --- /dev/null +++ b/src/kits/interface/qoca/arith.ch @@ -0,0 +1,375 @@ +//begin o[d] +#include +#include + +#if NUMT_IS_DOUBLE +typedef double numT; + + inline void + make_neg (double &x) + { + x = -x; + } + + inline void + reciprocate (double &x) + { + x = 1/x; + } + + inline double + dbl_val (double x) + { + return x; + } + + inline bool + is_zero (double x) + { + return x == 0.0; + } + + inline double + recip( double x) + { + return 1.0 / x; + } + +#elif NUMT_IS_PJM_MPQ +/* pjm's own hacked-up toy gmp wrapper */ +# include + +class mpq; +typedef mpq numT; + +class mpq +{ +public: + mpq() + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + } + + mpq( mpq const &other) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + mpq_set( rep, other.rep); + } + + mpq( long int n) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + if (n != 0) + mpq_set_si (rep, n, 1ul); + } + + mpq (int n) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + if (n != 0) + mpq_set_si (rep, n, 1ul); + } + + mpq (unsigned int n) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + if (n != 0) + mpq_set_ui (rep, n, 1ul); + } + + mpq (unsigned long n, unsigned long d = 1) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + if ((n != 0) || (d == 0)) + mpq_set_ui( rep, n, d); + if (d != 1) + mpq_canonicalize( rep); + } + + mpq (double x) + : fMagic( MPQ_MAGIC) + { + mpq_init( rep); + if (x != 0.0) // common special case. + { + mpq_set_d( rep, x); + mpq_canonicalize( rep); + } + } + + ~mpq() + { + assertIsMpq(); + mpq_clear (rep); + fMagic = 0; + } + + void assertIsMpq() const + { + assert( fMagic == MPQ_MAGIC); + } + + mpq &operator=(mpq const &other) + { + assertIsMpq(); + mpq_set( rep, other.rep); + return *this; + } + + mpq &operator+= (mpq const &other) + { + assertIsMpq(); + mpq_add (rep, rep, other.rep); + return *this; + } + + mpq &operator-= (mpq const &other) + { + assertIsMpq(); + mpq_sub (rep, rep, other.rep); + return *this; + } + + mpq &operator*= (mpq const &other) + { + assertIsMpq(); + mpq_mul (rep, rep, other.rep); + return *this; + } + + mpq &operator/= (mpq const &other) + { + assertIsMpq(); + mpq_div (rep, rep, other.rep); + return *this; + } + + mpq operator* (mpq const &other) const + { + assertIsMpq(); + mpq prod; + mpq_mul( prod.rep, rep, other.rep); + return prod; + } + + mpq operator* (unsigned other) const + { + assertIsMpq(); + mpq prod( other); + mpq_mul( prod.rep, rep, prod.rep); + return prod; + } + + mpq operator/ (mpq const &other) const + { + assertIsMpq(); + mpq quotient; + mpq_div( quotient.rep, rep, other.rep); + return quotient; + } + + mpq operator+ (mpq const &other) const + { + assertIsMpq(); + mpq sum; + mpq_add( sum.rep, rep, other.rep); + return sum; + } + + mpq operator- (mpq const &other) const + { + assertIsMpq(); + mpq diff; + mpq_sub( diff.rep, rep, other.rep); + return diff; + } + + bool operator< (mpq const &other) const + { + assertIsMpq(); + return mpq_cmp( rep, other.rep) < 0; + } + + bool operator> (mpq const &other) const + { return mpq_cmp( rep, other.rep) > 0; } + + bool operator== (mpq const &other) const + { return mpq_equal( rep, other.rep); } + + bool operator!= (mpq const &other) const + { return !mpq_equal( rep, other.rep); } + + bool operator< (int x) const + { + assertIsMpq(); + if (x == 0) + return mpq_sgn( rep) < 0; + else + abort(); + } + + bool operator> (int x) const + { + assertIsMpq(); + if (x == 0) + return mpq_sgn( rep) > 0; + else + abort(); + } + + bool operator>= (int x) const + { + assertIsMpq(); + if (x == 0) + return mpq_sgn( rep) >= 0; + else + abort(); + } + + bool operator== (int x) const + { + assertIsMpq(); + if (x == 0) + return mpq_sgn( rep) == 0; + else if (x > 0) + return mpq_cmp_ui( rep, x, 1u) == 0; + else + abort(); + } + + bool operator== (double x) const + { + assertIsMpq(); + if (x == 0.0) + return mpq_sgn( rep) == 0; + else + abort(); + } + + bool isFinite() const + { + assertIsMpq(); + return mpz_sgn( &rep[0]._mp_den); + } + + long get_lround() const + { + assertIsMpq(); + return lround( mpq_get_d( rep)); + } + + mpz_srcptr get_num_mpz_t() const + { return mpq_numref( rep); } + + mpz_srcptr get_den_mpz_t() const + { return mpq_denref( rep); } + +public: + mpq_t rep; +private: + unsigned fMagic; + static unsigned const MPQ_MAGIC = 0xc04546fb; // from /dev/random +}; + + inline void + make_neg (mpq &x) + { + mpq_neg (x.rep, x.rep); + } + + inline void + reciprocate (mpq &x) + { + mpq_inv (x.rep, x.rep); + } + + inline mpq + recip( mpq const &x) + { + mpq r; + mpq_inv( r.rep, x.rep); + return r; + } + + inline double + dbl_val (mpq const &x) + { + return mpq_get_d (x.rep); + } + + inline bool + is_zero (mpq const &x) + { + return mpq_sgn (x.rep) == 0; + } + + // it should be better to define mp_free in the library + extern "C" { + extern void (*__gmp_free_func)(void *, size_t); + } + inline void mp_free(void *ptr, size_t size) + { + (*__gmp_free_func)(ptr, size); + } + +# ifndef qcNoStream +# include + inline ostream & operator<<(ostream &o, const mpq &q) + { +# if 0 + char *num = mpz_get_str(0, 10, q.get_num_mpz_t()); + o << num; + mp_free(num, strlen(num)+1); + if (mpz_cmp_ui(q.get_den_mpz_t(), 1)) + { + char *den = mpz_get_str(0, 10, q.get_den_mpz_t()); + o << '/' << den; + mp_free(den, strlen(den)+1); + } + return o; +# else + o << dbl_val(q); + return o; +# endif + } +# endif + + inline numT operator-(const numT &x) + { + numT ret = x; + make_neg( ret); + return ret; + } + + inline numT fabs(numT const &x) + { + numT ret = x; + if (mpq_sgn( ret.rep) < 0) + ret.rep[0]._mp_num._mp_size = - ret.rep[0]._mp_num._mp_size; + return ret; + } + +#elif NUMT_IS_GB_MPQ +/* Gerardo Ballabio's sophisticated gmp wrapper. */ +# include "g++.h" +typedef mpq_class numT; + +#else +# error "Don't know numT type." +#endif +//end o[d] + +/* + Local Variables: + mode:c++ + c-file-style:"gnu" + fill-column:80 + End: + vim: set filetype=c++ : +*/ diff --git a/src/kits/storage/AppFileInfo.cpp b/src/kits/storage/AppFileInfo.cpp index e48ebe497a..8283d56e96 100644 --- a/src/kits/storage/AppFileInfo.cpp +++ b/src/kits/storage/AppFileInfo.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,9 @@ static const char *kSupportedTypesAttribute = "BEOS:FILE_TYPES"; static const char *kVersionInfoAttribute = "BEOS:APP_VERSION"; static const char *kMiniIconAttribute = "BEOS:M:"; static const char *kLargeIconAttribute = "BEOS:L:"; +static const char *kIconAttribute = "BEOS:"; static const char *kStandardIconType = "STD_ICON"; +static const char *kIconType = "ICON"; // resource IDs static const int32 kTypeResourceID = 2; @@ -785,7 +788,38 @@ status_t BAppFileInfo::GetIconForType(const char *type, BBitmap *icon, icon_size which) const { - status_t error = B_OK; + if (InitCheck() != B_OK) + return B_NO_INIT; + + if (!icon || icon->InitCheck() != B_OK) + return B_BAD_VALUE; + + // try vector icon first + BString vectorAttributeName(kIconAttribute); + + // check type param + if (type) { + if (BMimeType::IsValid(type)) + vectorAttributeName += type; + else + return B_BAD_VALUE; + } else { + vectorAttributeName += kIconType; + } + const char* attribute = vectorAttributeName.String(); + + size_t bytesRead; + void* allocatedBuffer; + status_t error = _ReadData(attribute, -1, B_RAW_TYPE, NULL, 0, + bytesRead, &allocatedBuffer); + if (error == B_OK) { + return BIconUtils::GetVectorIcon((uint8*)allocatedBuffer, + bytesRead, icon); + } + + // no vector icon if we got this far + + error = B_OK; // set some icon size related variables BString attributeString; BRect bounds; @@ -805,28 +839,23 @@ BAppFileInfo::GetIconForType(const char *type, BBitmap *icon, attrSize = 32 * 32; break; default: - error = B_BAD_VALUE; - break; + return B_BAD_VALUE; } // check type param - if (error == B_OK) { - if (type) { - if (BMimeType::IsValid(type)) - attributeString += type; - else - error = B_BAD_VALUE; - } else - attributeString += kStandardIconType; - } - const char *attribute = attributeString.String(); + if (type) { + if (BMimeType::IsValid(type)) + attributeString += type; + else + return B_BAD_VALUE; + } else + attributeString += kStandardIconType; + + attribute = attributeString.String(); // check parameter and initialization - if (error == B_OK - && (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { - error = B_BAD_VALUE; - } - if (error == B_OK && InitCheck() != B_OK) - error = B_NO_INIT; + if (icon->Bounds() != bounds) + return B_BAD_VALUE; + // read the data if (error == B_OK) { bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); diff --git a/src/kits/storage/Jamfile b/src/kits/storage/Jamfile index 1095c380cd..379d632c93 100644 --- a/src/kits/storage/Jamfile +++ b/src/kits/storage/Jamfile @@ -2,10 +2,15 @@ SubDir HAIKU_TOP src kits storage ; SetSubDirSupportedPlatforms haiku libbe_test ; +UseLibraryHeaders icon ; + UsePrivateHeaders shared app kernel storage ; UsePrivateHeaders [ FDirName kernel disk_device_manager ] ; UseArchHeaders $(TARGET_ARCH) ; +# for libbe_test +UsePublicHeaders [ FDirName add-ons registrar ] ; + SEARCH_SOURCE += [ FDirName $(SUBDIR) mime ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) sniffer ] ; diff --git a/src/kits/storage/NodeInfo.cpp b/src/kits/storage/NodeInfo.cpp index b7b09ac101..e143805551 100644 --- a/src/kits/storage/NodeInfo.cpp +++ b/src/kits/storage/NodeInfo.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ static const char *kNIPreferredAppAttribute = NI_BEOS ":PREF_APP"; static const char *kNIAppHintAttribute = NI_BEOS ":PPATH"; static const char *kNIMiniIconAttribute = NI_BEOS ":M:STD_ICON"; static const char *kNILargeIconAttribute = NI_BEOS ":L:STD_ICON"; +static const char *kNIIconAttribute = NI_BEOS ":ICON"; /*! \brief Creates an uninitialized BNodeInfo object. @@ -225,81 +227,88 @@ BNodeInfo::SetType(const char *type) status_t BNodeInfo::GetIcon(BBitmap *icon, icon_size k) const { - status_t error = B_OK; - // set some icon size related variables - const char *attribute = NULL; - BRect bounds; - uint32 attrType = 0; - size_t attrSize = 0; - switch (k) { - case B_MINI_ICON: - attribute = kNIMiniIconAttribute; - bounds.Set(0, 0, 15, 15); - attrType = B_MINI_ICON_TYPE; - attrSize = 16 * 16; - break; - case B_LARGE_ICON: - attribute = kNILargeIconAttribute; - bounds.Set(0, 0, 31, 31); - attrType = B_LARGE_ICON_TYPE; - attrSize = 32 * 32; - break; - default: - error = B_BAD_VALUE; - break; - } + const char* iconAttribute = kNIIconAttribute; + const char* miniIconAttribute = kNIMiniIconAttribute; + const char* largeIconAttribute = kNILargeIconAttribute; - // check parameter and initialization - if (error == B_OK - && (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { - error = B_BAD_VALUE; - } - if (error == B_OK && InitCheck() != B_OK) - error = B_NO_INIT; + return BIconUtils::GetIcon(fNode, iconAttribute, miniIconAttribute, + largeIconAttribute, k, icon); - // get the attribute info and check type and size of the attr contents - attr_info attrInfo; - if (error == B_OK) - error = fNode->GetAttrInfo(attribute, &attrInfo); - if (error == B_OK && attrInfo.type != attrType) - error = B_BAD_TYPE; - if (error == B_OK && attrInfo.size != attrSize) - error = B_BAD_DATA; - - // read the attribute - if (error == B_OK) { - bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); - char *buffer = NULL; - ssize_t read; - if (otherColorSpace) { - // other color space than stored in attribute - buffer = new(nothrow) char[attrSize]; - if (!buffer) - error = B_NO_MEMORY; - if (error == B_OK) { - read = fNode->ReadAttr(attribute, attrType, 0, buffer, - attrSize); - } - } else { - read = fNode->ReadAttr(attribute, attrType, 0, icon->Bits(), - attrSize); - } - if (error == B_OK) { - if (read < 0) - error = read; - else if (read != attrInfo.size) - error = B_ERROR; - } - if (otherColorSpace) { - // other color space than stored in attribute - if (error == B_OK) { - error = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW, - 0, B_CMAP8); - } - delete[] buffer; - } - } - return error; +// status_t error = B_OK; +// // set some icon size related variables +// const char *attribute = NULL; +// BRect bounds; +// uint32 attrType = 0; +// size_t attrSize = 0; +// switch (k) { +// case B_MINI_ICON: +// attribute = kNIMiniIconAttribute; +// bounds.Set(0, 0, 15, 15); +// attrType = B_MINI_ICON_TYPE; +// attrSize = 16 * 16; +// break; +// case B_LARGE_ICON: +// attribute = kNILargeIconAttribute; +// bounds.Set(0, 0, 31, 31); +// attrType = B_LARGE_ICON_TYPE; +// attrSize = 32 * 32; +// break; +// default: +// error = B_BAD_VALUE; +// break; +// } +// +// // check parameter and initialization +// if (error == B_OK +// && (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { +// error = B_BAD_VALUE; +// } +// if (error == B_OK && InitCheck() != B_OK) +// error = B_NO_INIT; +// +// // get the attribute info and check type and size of the attr contents +// attr_info attrInfo; +// if (error == B_OK) +// error = fNode->GetAttrInfo(attribute, &attrInfo); +// if (error == B_OK && attrInfo.type != attrType) +// error = B_BAD_TYPE; +// if (error == B_OK && attrInfo.size != attrSize) +// error = B_BAD_DATA; +// +// // read the attribute +// if (error == B_OK) { +// bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); +// char *buffer = NULL; +// ssize_t read; +// if (otherColorSpace) { +// // other color space than stored in attribute +// buffer = new(nothrow) char[attrSize]; +// if (!buffer) +// error = B_NO_MEMORY; +// if (error == B_OK) { +// read = fNode->ReadAttr(attribute, attrType, 0, buffer, +// attrSize); +// } +// } else { +// read = fNode->ReadAttr(attribute, attrType, 0, icon->Bits(), +// attrSize); +// } +// if (error == B_OK) { +// if (read < 0) +// error = read; +// else if (read != attrInfo.size) +// error = B_ERROR; +// } +// if (otherColorSpace) { +// // other color space than stored in attribute +// if (error == B_OK) { +// error = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW, +// 0, B_CMAP8); +// } +// delete[] buffer; +// } +// } +// return error; } // SetIcon @@ -615,6 +624,9 @@ BNodeInfo::SetAppHint(const entry_ref *ref) status_t BNodeInfo::GetTrackerIcon(BBitmap *icon, icon_size iconSize) const { + if (!icon) + return B_BAD_VALUE; + // set some icon size related variables status_t error = B_OK; BRect bounds; @@ -626,13 +638,15 @@ BNodeInfo::GetTrackerIcon(BBitmap *icon, icon_size iconSize) const bounds.Set(0, 0, 31, 31); break; default: - error = B_BAD_VALUE; +// error = B_BAD_VALUE; + // NOTE: added to be less strict and support scaled icons + bounds = icon->Bounds(); break; } // check parameters and initialization if (error == B_OK - && (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { + && (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) { error = B_BAD_VALUE; } if (error == B_OK && InitCheck() != B_OK) diff --git a/src/kits/storage/mime/database_access.cpp b/src/kits/storage/mime/database_access.cpp index 1a60690854..15eb6ac714 100644 --- a/src/kits/storage/mime/database_access.cpp +++ b/src/kits/storage/mime/database_access.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -209,82 +210,117 @@ get_icon(const char *type, BBitmap *icon, icon_size which) */ status_t -get_icon_for_type(const char *type, const char *fileType, BBitmap *icon, - icon_size which) +get_icon_for_type(const char* type, const char* fileType, BBitmap* icon, + icon_size which) { - std::string attr; - attr_info info; - ssize_t err; + if (!type || !icon) + return B_BAD_VALUE; + + // open the node for the given type BNode node; - uint32 attrType = 0; - ssize_t attrSize = 0; - BRect bounds; + ssize_t err = open_type(type, &node); + if (err < B_OK) + return (status_t)err; + + // construct our attribute name + std::string vectorIconAttrName; + std::string smallIconAttrName; + std::string largeIconAttrName; - err = type && icon ? B_OK : B_BAD_VALUE; - - // Figure out what kind of data we *should* find - if (!err) { - switch (which) { - case B_MINI_ICON: - bounds.Set(0, 0, 15, 15); - attrType = kMiniIconType; - attrSize = 16 * 16; - break; - case B_LARGE_ICON: - bounds.Set(0, 0, 31, 31); - attrType = kLargeIconType; - attrSize = 32 * 32; - break; - default: - err = B_BAD_VALUE; - break; - } - } - // Construct our attribute name if (fileType) { - attr = (which == B_MINI_ICON - ? kMiniIconAttrPrefix - : kLargeIconAttrPrefix) - + BPrivate::Storage::to_lower(fileType); + std::string lowerCaseFileType = BPrivate::Storage::to_lower(fileType); + + vectorIconAttrName = kIconAttrPrefix + lowerCaseFileType; + smallIconAttrName = kMiniIconAttrPrefix + lowerCaseFileType; + largeIconAttrName = kLargeIconAttrPrefix + lowerCaseFileType; } else { - attr = (which == B_MINI_ICON) ? kMiniIconAttr : kLargeIconAttr; - } - // Check the icon and attribute to see if they match - if (!err) - err = (icon->InitCheck() == B_OK && icon->Bounds() == bounds) ? B_OK : B_BAD_VALUE; - if (!err) - err = open_type(type, &node); - if (!err) - err = node.GetAttrInfo(attr.c_str(), &info); - if (!err) - err = (attrType == info.type && attrSize == info.size) ? B_OK : B_BAD_VALUE; - // read the attribute - if (!err) { - bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); - char *buffer = NULL; - if (otherColorSpace) { - // other color space than stored in attribute - buffer = new(std::nothrow) char[attrSize]; - if (!buffer) - err = B_NO_MEMORY; - if (!err) - err = node.ReadAttr(attr.c_str(), attrType, 0, buffer, attrSize); - } else { - // same color space, just read direct - err = node.ReadAttr(attr.c_str(), attrType, 0, icon->Bits(), attrSize); - } - if (err >= 0) - err = (err == attrSize) ? (status_t)B_OK : (status_t)B_FILE_ERROR; - if (otherColorSpace) { - if (!err) { - err = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW, - 0, B_CMAP8); - } - delete[] buffer; - } + vectorIconAttrName = kIconAttr; + smallIconAttrName = kMiniIconAttr; + largeIconAttrName = kLargeIconAttr; } - return err; + return BIconUtils::GetIcon(&node, vectorIconAttrName.c_str(), + smallIconAttrName.c_str(), largeIconAttrName.c_str(), + which, icon); + + +// ssize_t err = type && icon ? B_OK : B_BAD_VALUE; +// +// // Figure out what kind of data we *should* find +// uint32 attrType = 0; +// ssize_t attrSize = 0; +// BRect bounds; +// +// if (!err) { +// switch (which) { +// case B_MINI_ICON: +// bounds.Set(0, 0, 15, 15); +// attrType = kMiniIconType; +// attrSize = 16 * 16; +// break; +// case B_LARGE_ICON: +// bounds.Set(0, 0, 31, 31); +// attrType = kLargeIconType; +// attrSize = 32 * 32; +// break; +// default: +// err = B_BAD_VALUE; +// break; +// } +// } +// // Construct our attribute name +// std::string attr; +// if (fileType) { +// attr = (which == B_MINI_ICON +// ? kMiniIconAttrPrefix +// : kLargeIconAttrPrefix) +// + BPrivate::Storage::to_lower(fileType); +// } else { +// attr = (which == B_MINI_ICON) ? kMiniIconAttr : kLargeIconAttr; +// } +// // Check the icon and attribute to see if they match +// if (!err) { +// err = (icon->InitCheck() == B_OK +// && icon->Bounds() == bounds) ? B_OK : B_BAD_VALUE; +// } +// +// BNode node; +// if (!err) +// err = open_type(type, &node); +// +// attr_info info; +// if (!err) +// err = node.GetAttrInfo(attr.c_str(), &info); +// +// if (!err) +// err = (attrType == info.type && attrSize == info.size) ? B_OK : B_BAD_VALUE; +// // read the attribute +// if (!err) { +// bool otherColorSpace = (icon->ColorSpace() != B_CMAP8); +// char *buffer = NULL; +// if (otherColorSpace) { +// // other color space than stored in attribute +// buffer = new(std::nothrow) char[attrSize]; +// if (!buffer) +// err = B_NO_MEMORY; +// if (!err) +// err = node.ReadAttr(attr.c_str(), attrType, 0, buffer, attrSize); +// } else { +// // same color space, just read direct +// err = node.ReadAttr(attr.c_str(), attrType, 0, icon->Bits(), attrSize); +// } +// if (err >= 0) +// err = (err == attrSize) ? (status_t)B_OK : (status_t)B_FILE_ERROR; +// if (otherColorSpace) { +// if (!err) { +// err = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW, +// 0, B_CMAP8); +// } +// delete[] buffer; +// } +// } +// +// return err; } // get_preferred_app diff --git a/src/kits/storage/mime/database_support.cpp b/src/kits/storage/mime/database_support.cpp index 20caaf74b9..98213ba795 100644 --- a/src/kits/storage/mime/database_support.cpp +++ b/src/kits/storage/mime/database_support.cpp @@ -56,7 +56,8 @@ const std::string kApplicationDatabaseDir = kDatabaseDir + "/application"; #define LARGE_ICON_ATTR_PREFIX ATTR_PREFIX "L:" const char *kMiniIconAttrPrefix = MINI_ICON_ATTR_PREFIX; -const char *kLargeIconAttrPrefix = LARGE_ICON_ATTR_PREFIX; +const char *kLargeIconAttrPrefix = LARGE_ICON_ATTR_PREFIX; +const char *kIconAttrPrefix = ATTR_PREFIX; // attribute names const char *kFileTypeAttr = "BEOS:TYPE"; @@ -68,6 +69,7 @@ const char *kLongDescriptionAttr = ATTR_PREFIX "L:DESC"; const char *kFileExtensionsAttr = ATTR_PREFIX "EXTENS"; const char *kMiniIconAttr = MINI_ICON_ATTR_PREFIX "STD_ICON"; const char *kLargeIconAttr = LARGE_ICON_ATTR_PREFIX "STD_ICON"; +const char *kIconAttr = ATTR_PREFIX "ICON"; const char *kPreferredAppAttr = ATTR_PREFIX "PREF_APP"; const char *kSnifferRuleAttr = ATTR_PREFIX "SNIFF_RULE"; const char *kSupportedTypesAttr = ATTR_PREFIX "FILE_TYPES"; @@ -82,6 +84,7 @@ const int32 kLongDescriptionType = 'MLDC'; const int32 kFileExtensionsType = B_MESSAGE_TYPE; const int32 kMiniIconType = B_MINI_ICON_TYPE; const int32 kLargeIconType = B_LARGE_ICON_TYPE; +const int32 kIconType = B_RAW_TYPE; const int32 kPreferredAppType = 'MSIG'; const int32 kSnifferRuleType = B_STRING_TYPE; const int32 kSupportedTypesType = B_MESSAGE_TYPE; diff --git a/src/kits/support/Archivable.cpp b/src/kits/support/Archivable.cpp index 1804404130..ee1dd5075c 100644 --- a/src/kits/support/Archivable.cpp +++ b/src/kits/support/Archivable.cpp @@ -1,31 +1,15 @@ -//------------------------------------------------------------------------------ -// Copyright (c) 2001-2002, OpenBeOS -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -// -// File Name: Archivable.cpp -// Author: Erik Jaesler (erik@cgsoftware.com) -// Description: BArchivable mix-in class defines the archiving -// protocol. Also some global archiving functions. -//------------------------------------------------------------------------------ +/* + * Copyright (c) 2001-2006, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Erik Jaesler (erik@cgsoftware.com) + */ + +/** Description: BArchivable mix-in class defines the archiving + protocol. Also some global archiving functions.*/ + -// Standard Includes ----------------------------------------------------------- #include #include #include @@ -34,7 +18,6 @@ #include #include -// System Includes ------------------------------------------------------------- #include #include #include @@ -46,14 +29,6 @@ #include #include -// Project Includes ------------------------------------------------------------ - -// Local Includes -------------------------------------------------------------- - -// Local Defines --------------------------------------------------------------- - -// Globals --------------------------------------------------------------------- - using std::string; using std::vector; @@ -91,26 +66,26 @@ Log entries graciously coughed up by the Be implementation: Nov 28 01:40:45 instantiate_object failed: Application could not be found (8000200b) */ -//------------------------------------------------------------------------------ + BArchivable::BArchivable() { - ; } -//------------------------------------------------------------------------------ + + BArchivable::BArchivable(BMessage* from) { - ; } -//------------------------------------------------------------------------------ + + BArchivable::~BArchivable() { - ; } -//------------------------------------------------------------------------------ -status_t BArchivable::Archive(BMessage* into, bool deep) const + + +status_t +BArchivable::Archive(BMessage* into, bool deep) const { - if (!into) - { + if (!into) { // TODO: logging/other error reporting? return B_BAD_VALUE; } @@ -120,35 +95,34 @@ status_t BArchivable::Archive(BMessage* into, bool deep) const return into->AddString(B_CLASS_FIELD, name); } -//------------------------------------------------------------------------------ -BArchivable* BArchivable::Instantiate(BMessage* from) + + +BArchivable* +BArchivable::Instantiate(BMessage* from) { debugger("Can't create a plain BArchivable object"); return NULL; } -//------------------------------------------------------------------------------ -status_t BArchivable::Perform(perform_code d, void* arg) + + +status_t +BArchivable::Perform(perform_code d, void* arg) { // TODO: Check against original return B_ERROR; } -//------------------------------------------------------------------------------ -void BArchivable::_ReservedArchivable1() -{ - ; -} -//------------------------------------------------------------------------------ -void BArchivable::_ReservedArchivable2() -{ - ; -} -//------------------------------------------------------------------------------ -void BArchivable::_ReservedArchivable3() -{ - ; -} -//------------------------------------------------------------------------------ -void BuildFuncName(const char* className, BString& funcName) + + +void BArchivable::_ReservedArchivable1() {} +void BArchivable::_ReservedArchivable2() {} +void BArchivable::_ReservedArchivable3() {} + + +// #pragma mark - + + +void +BuildFuncName(const char* className, BString& funcName) { funcName = ""; @@ -158,19 +132,19 @@ void BuildFuncName(const char* className, BString& funcName) funcName.Prepend("Instantiate__"); funcName.Append("P8BMessage"); } -//------------------------------------------------------------------------------ -BArchivable* instantiate_object(BMessage* archive, image_id* id) + + +BArchivable* +instantiate_object(BMessage* archive, image_id* id) { errno = B_OK; // Check our params - if (id) - { + if (id) { *id = B_BAD_VALUE; } - if (!archive) - { + if (!archive) { // TODO: extended error handling errno = B_BAD_VALUE; syslog(LOG_ERR, "instantiate_object failed: NULL BMessage argument"); @@ -180,8 +154,7 @@ BArchivable* instantiate_object(BMessage* archive, image_id* id) // Get class name from archive const char* name = NULL; status_t err = archive->FindString(B_CLASS_FIELD, &name); - if (err) - { + if (err) { // TODO: extended error handling syslog(LOG_ERR, "instantiate_object failed: Failed to find an entry " "defining the class name (%s).", strerror(err)); @@ -196,8 +169,7 @@ BArchivable* instantiate_object(BMessage* archive, image_id* id) // if find_instantiation_func() can't locate Class::Instantiate() // and a signature was specified - if (!iFunc && hasSig) - { + if (!iFunc && hasSig) { // use BRoster::FindApp() to locate an app or add-on with the symbol BRoster Roster; entry_ref ref; @@ -207,33 +179,26 @@ BArchivable* instantiate_object(BMessage* archive, image_id* id) // if an entry_ref is obtained if (!err) - { err = entry.SetTo(&ref); - } - if (err) - { + if (err) { syslog(LOG_ERR, "instantiate_object failed: Error finding app " "with signature \"%s\" (%s)", sig, strerror(err)); } - if (!err) - { + if (!err) { BPath path; err = entry.GetPath(&path); - if (!err) - { + if (!err) { // load the app/add-on image_id theImage = load_add_on(path.Path()); - if (theImage < 0) - { + if (theImage < 0) { // TODO: extended error handling return NULL; } // Save the image_id - if (id) - { + if (id) { *id = theImage; } @@ -247,16 +212,13 @@ BArchivable* instantiate_object(BMessage* archive, image_id* id) } } } - } - else if (!iFunc) - { + } else if (!iFunc) { syslog(LOG_ERR, "instantiate_object failed: No signature specified " "in archive, looking for class \"%s\".", name); errno = B_BAD_VALUE; } - if (err) - { + if (err) { // TODO: extended error handling syslog(LOG_ERR, "instantiate_object failed: %s (%x)", strerror(err), err); @@ -265,27 +227,29 @@ BArchivable* instantiate_object(BMessage* archive, image_id* id) } // if Class::Instantiate(BMessage*) was found - if (iFunc) - { + if (iFunc) { // use to create and return an object instance return iFunc(archive); } return NULL; } -//------------------------------------------------------------------------------ -BArchivable* instantiate_object(BMessage* from) + + +BArchivable* +instantiate_object(BMessage* from) { return instantiate_object(from, NULL); } -//------------------------------------------------------------------------------ -bool validate_instantiation(BMessage* from, const char* class_name) + + +bool +validate_instantiation(BMessage* from, const char* class_name) { errno = B_OK; // Make sure our params are kosher -- original skimped here =P - if (!from) - { + if (!from) { // Not standard; Be implementation has a segment // violation on this error mode errno = B_BAD_VALUE; @@ -295,11 +259,9 @@ bool validate_instantiation(BMessage* from, const char* class_name) status_t err = B_OK; const char* data; - for (int32 index = 0; err == B_OK; ++index) - { + for (int32 index = 0; err == B_OK; ++index) { err = from->FindString(B_CLASS_FIELD, index, &data); - if (!err && strcmp(data, class_name) == 0) - { + if (!err && strcmp(data, class_name) == 0) { return true; } } @@ -309,13 +271,13 @@ bool validate_instantiation(BMessage* from, const char* class_name) return false; } -//------------------------------------------------------------------------------ -instantiation_func find_instantiation_func(const char* class_name, - const char* sig) + + +instantiation_func +find_instantiation_func(const char* class_name, const char* sig) { errno = B_OK; - if (!class_name) - { + if (!class_name) { errno = B_BAD_VALUE; return NULL; } @@ -325,40 +287,44 @@ instantiation_func find_instantiation_func(const char* class_name, BuildFuncName(class_name, funcName); +printf("find_instantiation_func() - looking for '%s'\n", funcName.String()); + thread_id tid = find_thread(NULL); thread_info ti; status_t err = get_thread_info(tid, &ti); - if (!err) - { + if (!err) { // for each image_id in team_id image_info info; int32 cookie = 0; - while (!theFunc && (get_next_image_info(ti.team, &cookie, &info) == B_OK)) - { + while (!theFunc && (get_next_image_info(ti.team, &cookie, &info) == B_OK)) { theFunc = FindFuncInImage(funcName, info.id, err); } - if (theFunc && !CheckSig(sig, info)) - { + if (theFunc && !CheckSig(sig, info)) { // TODO: extended error handling theFunc = NULL; } } +printf("find_instantiation_func(): %p\n", theFunc); + return theFunc; } -//------------------------------------------------------------------------------ -instantiation_func find_instantiation_func(const char* class_name) + + +instantiation_func +find_instantiation_func(const char* class_name) { return find_instantiation_func(class_name, NULL); } -//------------------------------------------------------------------------------ -instantiation_func find_instantiation_func(BMessage* archive_data) + + +instantiation_func +find_instantiation_func(BMessage* archive_data) { errno = B_OK; - if (!archive_data) - { + if (!archive_data) { // TODO: extended error handling errno = B_BAD_VALUE; return NULL; @@ -369,8 +335,7 @@ instantiation_func find_instantiation_func(BMessage* archive_data) status_t err; err = archive_data->FindString(B_CLASS_FIELD, &name); - if (err) - { + if (err) { // TODO: extended error handling return NULL; } @@ -379,22 +344,25 @@ instantiation_func find_instantiation_func(BMessage* archive_data) return find_instantiation_func(name, sig); } -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -int GetNumber(const char*& name) +// #pragma mark - + + +int +GetNumber(const char*& name) { int val = atoi(name); - while (isdigit(*name)) - { + while (isdigit(*name)) { ++name; } return val; } -//------------------------------------------------------------------------------ -void Demangle(const char* name, BString& out) + + +void +Demangle(const char* name, BString& out) { // TODO: add support for template classes // _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl @@ -402,13 +370,12 @@ void Demangle(const char* name, BString& out) out = ""; // Are we in a namespace? - if (*name == 'Q') - { + if (*name == 'Q') { // Yessir, we are; how many deep are we? int nsCount = 0; ++name; - if (*name == '_') // more than 10 deep - { + if (*name == '_') { + // more than 10 deep ++name; if (!isdigit(*name)) ; // TODO: error handling @@ -418,16 +385,13 @@ void Demangle(const char* name, BString& out) ++name; else ; // this should be an error condition - } - else - { + } else { nsCount = *name - '0'; ++name; } int nameLen = 0; - for (int i = 0; i < nsCount - 1; ++i) - { + for (int i = 0; i < nsCount - 1; ++i) { if (!isdigit(*name)) ; // TODO: error handling @@ -440,8 +404,10 @@ void Demangle(const char* name, BString& out) out.Append(name, GetNumber(name)); } -//------------------------------------------------------------------------------ -void Mangle(const char* name, BString& out) + + +void +Mangle(const char* name, BString& out) { // TODO: add support for template classes // _find__t12basic_string3ZcZt18string_char_traits1ZcZt24__default_alloc_template2b0i0PCccUlUl @@ -455,8 +421,7 @@ void Mangle(const char* name, BString& out) string::size_type pos = 0; string::size_type oldpos = 0; - while (pos != string::npos) - { + while (pos != string::npos) { pos = origName.find_first_of("::", oldpos); spacenames.push_back(string(origName, oldpos, pos - oldpos)); pos = origName.find_first_not_of("::", pos); @@ -467,8 +432,7 @@ void Mangle(const char* name, BString& out) // Now mangle it into this: // Q49testthree8testfour9Testthree8Testfour out = ""; - if (count > 1) - { + if (count > 1) { out += 'Q'; if (count > 10) out += '_'; @@ -477,15 +441,15 @@ void Mangle(const char* name, BString& out) out += '_'; } - for (unsigned int i = 0; i < spacenames.size(); ++i) - { + for (unsigned int i = 0; i < spacenames.size(); ++i) { out << (int)spacenames[i].length(); out += spacenames[i].c_str(); } } -//------------------------------------------------------------------------------ -instantiation_func FindFuncInImage(BString& funcName, image_id id, - status_t& err) + + +instantiation_func +FindFuncInImage(BString& funcName, image_id id, status_t& err) { err = B_OK; instantiation_func theFunc = NULL; @@ -497,14 +461,12 @@ instantiation_func FindFuncInImage(BString& funcName, image_id id, int32 funcNameLen; // for each B_SYMBOL_TYPE_TEXT in image_id - for (int32 i = 0; !err; ++i) - { + for (int32 i = 0; !err; ++i) { funcNameLen = FUNC_NAME_LEN; err = get_nth_image_symbol(id, i, foundFuncName, &funcNameLen, &symbolType, (void**)&theFunc); - if (!err && symbolType == B_SYMBOL_TYPE_TEXT) - { + if (!err && symbolType == B_SYMBOL_TYPE_TEXT) { // try to match Class::Instantiate(BMessage*) signature if (funcName.ICompare(foundFuncName, funcNameLen) == 0) break; @@ -517,19 +479,19 @@ instantiation_func FindFuncInImage(BString& funcName, image_id id, err = get_image_symbol(id, funcName.String(), B_SYMBOL_TYPE_TEXT, (void**)&theFunc); - if (err) - { + if (err) { // TODO: error handling theFunc = NULL; } return theFunc; } -//------------------------------------------------------------------------------ -bool CheckSig(const char* sig, image_info& info) + + +bool +CheckSig(const char* sig, image_info& info) { - if (!sig) - { + if (!sig) { // If it wasn't specified, anything "matches" return true; } @@ -539,8 +501,7 @@ bool CheckSig(const char* sig, image_info& info) // Get image signature BFile ImageFile(info.name, B_READ_ONLY); err = ImageFile.InitCheck(); - if (err) - { + if (err) { // TODO: extended error handling return false; } @@ -548,8 +509,7 @@ bool CheckSig(const char* sig, image_info& info) char imageSig[B_MIME_TYPE_LENGTH]; BAppFileInfo AFI(&ImageFile); err = AFI.GetSignature(imageSig); - if (err) - { + if (err) { // TODO: extended error handling syslog(LOG_ERR, "instantiate_object - couldn't get mime sig for %s", info.name); @@ -558,13 +518,4 @@ bool CheckSig(const char* sig, image_info& info) return strcmp(sig, imageSig) == 0; } -//------------------------------------------------------------------------------ - - -/* - * $Log $ - * - * $Id $ - * - */ diff --git a/src/kits/support/List.cpp b/src/kits/support/List.cpp index a6b069b493..c0f1481e19 100644 --- a/src/kits/support/List.cpp +++ b/src/kits/support/List.cpp @@ -120,7 +120,7 @@ BList::AddItem(void *item) // AddList bool -BList::AddList(BList *list, int32 index) +BList::AddList(const BList *list, int32 index) { bool result = (list && index >= 0 && index <= fItemCount); if (result && list->fItemCount > 0) { @@ -138,7 +138,7 @@ BList::AddList(BList *list, int32 index) // AddList bool -BList::AddList(BList *list) +BList::AddList(const BList *list) { bool result = (list != NULL); if (result && list->fItemCount > 0) { @@ -402,6 +402,24 @@ BList::DoForEach(bool (*func)(void *, void*), void * arg) } +// obsolete AddList(BList* list, int32 index) and AddList(BList* list) + +// AddList +extern "C" bool +AddList__5BListP5BListl(BList* self, BList* list, int32 index) +{ + return self->AddList((const BList*)list, index); +} + + +// AddList +extern "C" bool +AddList__5BListP5BList(BList* self, BList* list) +{ + return self->AddList((const BList*)list); +} + + // FBC void BList::_ReservedList1() {} void BList::_ReservedList2() {} diff --git a/src/kits/tracker/Attributes.h b/src/kits/tracker/Attributes.h index a65a1defa5..2433f88042 100644 --- a/src/kits/tracker/Attributes.h +++ b/src/kits/tracker/Attributes.h @@ -64,6 +64,7 @@ namespace BPrivate { #define kAttrPreferredApp "BEOS:PREF_APP" #define kAttrLargeIcon "BEOS:L:STD_ICON" #define kAttrMiniIcon "BEOS:M:STD_ICON" +#define kAttrIcon "BEOS:ICON" #define kAttrDisksFrame "_trk/d_windframe" #define kAttrDisksWorkspace "_trk/d_windwkspc" diff --git a/src/kits/tracker/Bitmaps.cpp b/src/kits/tracker/Bitmaps.cpp index 1da3e1e4ac..d718c649ef 100644 --- a/src/kits/tracker/Bitmaps.cpp +++ b/src/kits/tracker/Bitmaps.cpp @@ -37,6 +37,7 @@ All rights reserved. #include #include #include +#include #include #include @@ -129,17 +130,34 @@ BImageResources::GetIconResource(int32 id, icon_size size, BBitmap *dest) const if (size != B_LARGE_ICON && size != B_MINI_ICON ) return B_ERROR; - size_t len = 0; - const void *data = LoadResource(size == B_LARGE_ICON ? 'ICON' : 'MICN', - id, &len); + size_t length = 0; + const void *data; - if (data == 0 || len != (size_t)(size == B_LARGE_ICON ? 1024 : 256)) { + // try to load vector icon + data = LoadResource(B_RAW_TYPE, id, &length); + + if (data && BIconUtils::GetVectorIcon((uint8*)data, length, dest) == B_OK) + return B_OK; + + // fall back to R5 icon + length = 0; + data = LoadResource(size == B_LARGE_ICON ? 'ICON' : 'MICN', id, &length); + + if (data == 0 || length != (size_t)(size == B_LARGE_ICON ? 1024 : 256)) { TRESPASS(); return B_ERROR; } - - dest->SetBits(data, (int32)len, 0, kDefaultIconDepth); - return B_OK; + + status_t ret = B_OK; + + if (dest->ColorSpace() != B_CMAP8) { + ret = BIconUtils::ConvertFromCMAP8((uint8*)data, size, size, + size, dest); + } else { + dest->SetBits(data, (int32)length, 0, B_CMAP8); + } + + return ret; } image_id diff --git a/src/kits/tracker/FSUtils.cpp b/src/kits/tracker/FSUtils.cpp index 9d5109eecc..6c68b32a7c 100644 --- a/src/kits/tracker/FSUtils.cpp +++ b/src/kits/tracker/FSUtils.cpp @@ -2136,7 +2136,7 @@ FSGetDeskDir(BDirectory *deskDir, dev_t dev) if (result != B_OK) return result; - // make desktop fInvisible + // make desktop invisible PoseInfo poseInfo; poseInfo.fInvisible = true; poseInfo.fInitedDirectory = -1LL; @@ -2155,6 +2155,12 @@ FSGetDeskDir(BDirectory *deskDir, dev_t dev) if (data) deskDir->WriteAttr(kAttrMiniIcon, 'MICN', 0, data, size); + data = GetTrackerResources()-> + LoadResource(B_RAW_TYPE, kResDeskIcon, &size); + + if (data) + deskDir->WriteAttr(kAttrIcon, B_RAW_TYPE, 0, data, size); + return B_OK; } @@ -2651,6 +2657,12 @@ FSCreateTrashDirs() trashDir.WriteAttr(kAttrMiniIcon, 'MICN', 0, data, size); } + data = GetTrackerResources()-> + LoadResource(B_RAW_TYPE, kResTrashIcon, &size); + if (data) { + trashDir.WriteAttr(kAttrIcon, B_RAW_TYPE, 0, + data, size); + } } } } diff --git a/src/kits/tracker/IconCache.cpp b/src/kits/tracker/IconCache.cpp index f54f602665..96ec91605c 100644 --- a/src/kits/tracker/IconCache.cpp +++ b/src/kits/tracker/IconCache.cpp @@ -217,7 +217,25 @@ IconCacheEntry::IconHitTest(BPoint where, IconDrawMode mode, icon_size size) con uchar *bits = (uchar *)bitmap->Bits(); ASSERT(bits); - return *(bits + (int32)(floor(where.y) * size + where.x)) != B_TRANSPARENT_8_BIT; + + BRect bounds(bitmap->Bounds()); + bounds.InsetBy((bounds.Width() + 1.0) / 8.0, (bounds.Height() + 1.0) / 8.0); + if (bounds.Contains(where)) + return true; + + switch (bitmap->ColorSpace()) { + case B_RGBA32: + // test alpha channel + return *(bits + (int32)(floorf(where.y) * bitmap->BytesPerRow() + + floorf(where.x) * 4 + 3)) > 20; + + case B_CMAP8: + return *(bits + (int32)(floorf(where.y) * size + where.x)) + != B_TRANSPARENT_8_BIT; + + default: + return true; + } } @@ -1223,20 +1241,63 @@ IconCache::InitHiliteTable() BBitmap * -IconCache::MakeTransformedIcon(const BBitmap *src, icon_size /*size*/, - int32 colorTransformTable[], LazyBitmapAllocator *lazyBitmap) +IconCache::MakeTransformedIcon(const BBitmap* source, icon_size /*size*/, + int32 colorTransformTable[], LazyBitmapAllocator* lazyBitmap) { if (fInitHiliteTable) InitHiliteTable(); - BBitmap *result = lazyBitmap->Get(); - int32 bitsLength = result->BitsLength(); - // Do I need a SetBits here? could just copy/transform straight from src - result->SetBits(src->Bits(), bitsLength, 0, kDefaultIconDepth); + BBitmap* result = lazyBitmap->Get(); + uint8* src = (uint8*)source->Bits(); + uint8* dst = (uint8*)result->Bits(); - uchar *bits = (uchar *)result->Bits(); - for (int32 index = 0; index < bitsLength; index++) - bits[index] = (uchar)colorTransformTable[(uchar)bits[index]]; +// ASSERT(result->ColorSpace() == source->ColorSpace() +// && result->Bounds() == source->Bounds()); + if (result->ColorSpace() != source->ColorSpace() + || result->Bounds() != source->Bounds()) { + printf("IconCache::MakeTransformedIcon() - " + "bitmap format mismatch!\n"); + return NULL; + } + + switch (result->ColorSpace()) { + case B_RGB32: + case B_RGBA32: { + uint32 width = source->Bounds().IntegerWidth() + 1; + uint32 height = source->Bounds().IntegerHeight() + 1; + uint32 srcBPR = source->BytesPerRow(); + uint32 dstBPR = result->BytesPerRow(); + for (uint32 y = 0; y < height; y++) { + uint8* d = dst; + uint8* s = src; + for (uint32 x = 0; x < width; x++) { + // 66% brightness + d[0] = (int)s[0] * 168 >> 8; + d[1] = (int)s[1] * 168 >> 8; + d[2] = (int)s[2] * 168 >> 8; + d[3] = s[3]; + d += 4; + s += 4; + } + dst += dstBPR; + src += srcBPR; + } + break; + } + + case B_CMAP8: { + int32 bitsLength = result->BitsLength(); + for (int32 i = 0; i < bitsLength; i++) + *dst++ = (uint8)colorTransformTable[*src++]; + break; + } + + default: + memset(dst, 0, result->BitsLength()); + // unkown colorspace, no tinting for you + // "black" should make the problem stand out + break; + } return result; } @@ -1439,11 +1500,19 @@ SharedCacheEntry::SharedCacheEntry(const char *fileType, const char *appSignatur void -SharedCacheEntry::Draw(BView *view, BPoint where, IconDrawMode mode, icon_size size, +SharedCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode, icon_size size, bool async) { - BBitmap *bitmap = IconForMode(mode, size); + BBitmap* bitmap = IconForMode(mode, size); ASSERT(bitmap); + + if (bitmap->ColorSpace() == B_RGBA32) { + view->SetDrawingMode(B_OP_ALPHA); + view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + } else { + view->SetDrawingMode(B_OP_OVER); + } + if (async) view->DrawBitmapAsync(bitmap, where); else @@ -1456,7 +1525,16 @@ SharedCacheEntry::Draw(BView *view, BPoint where, IconDrawMode mode, icon_size s void (*blitFunc)(BView *, BPoint ,BBitmap *, void *), void *passThruState) { BBitmap *bitmap = IconForMode(mode, size); - ASSERT(bitmap); + if (!bitmap) + return; + + if (bitmap->ColorSpace() == B_RGBA32) { + view->SetDrawingMode(B_OP_ALPHA); + view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + } else { + view->SetDrawingMode(B_OP_OVER); + } + (blitFunc)(view, where, bitmap, passThruState); } @@ -1534,6 +1612,16 @@ NodeCacheEntry::Draw(BView *view, BPoint where, IconDrawMode mode, icon_size siz bool async) { BBitmap *bitmap = IconForMode(mode, size); + if (!bitmap) + return; + + if (bitmap->ColorSpace() == B_RGBA32) { + view->SetDrawingMode(B_OP_ALPHA); + view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + } else { + view->SetDrawingMode(B_OP_OVER); + } + if (false && async) { TRESPASS(); // need to copy the bits first in here @@ -1548,6 +1636,16 @@ NodeCacheEntry::Draw(BView *view, BPoint where, IconDrawMode mode, icon_size siz void (*blitFunc)(BView *, BPoint ,BBitmap *, void *), void *passThruState) { BBitmap *bitmap = IconForMode(mode, size); + if (!bitmap) + return; + + if (bitmap->ColorSpace() == B_RGBA32) { + view->SetDrawingMode(B_OP_ALPHA); + view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + } else { + view->SetDrawingMode(B_OP_OVER); + } + (blitFunc)(view, where, bitmap, passThruState); } diff --git a/src/kits/tracker/IconCache.h b/src/kits/tracker/IconCache.h index 89b86a7122..100c120089 100644 --- a/src/kits/tracker/IconCache.h +++ b/src/kits/tracker/IconCache.h @@ -67,7 +67,7 @@ class SharedIconCache; class SharedCacheEntry; enum IconDrawMode { - // Difrent states of icon drawing + // Different states of icon drawing kSelected = 0x01, kNotFocused = 0x02, // Tracker window kOpen = 0x04, // open folder, trash @@ -115,7 +115,7 @@ class IconCacheEntry { // to some other entry that does // This is used for icons that are defined by a preferred app for - // a metamime, types that do not have an icon an get to point to + // a metamime, types that do not have an icon get to point to // generic, etc. public: @@ -140,7 +140,7 @@ public: LazyBitmapAllocator *); // same as above, always uses normal icon as source - bool IconHitTest(BPoint, IconDrawMode , icon_size) const; + bool IconHitTest(BPoint, IconDrawMode, icon_size) const; // given a point, returns true if a non-transparent pixel was hit void RetireIcons(BObjectList *retiredBitmapList); @@ -293,7 +293,7 @@ public: }; class NodeIconCache : public SimpleIconCache { - // NodeIconCache is used for nodes that define their own icon icons + // NodeIconCache is used for nodes that define their own icons public: NodeIconCache(); @@ -311,8 +311,7 @@ public: void Deleting(const node_ref *); // model for this node is getting deleted (not necessarily the node itself) void Removing(const node_ref *); - // used by permanent NodeIconCache entries, when an entry gets - // deleted + // used by permanent NodeIconCache entries, when an entry gets deleted void Deleting(const BView *); void IconChanged(const Model *); @@ -447,7 +446,8 @@ class LazyBitmapAllocator { // Utility class used when we aren't sure that we will keep a bitmap, // need a bitmap or be able to construct it properly public: - LazyBitmapAllocator(icon_size size, color_space colorSpace = kDefaultIconDepth, + LazyBitmapAllocator(icon_size size, + color_space colorSpace = kDefaultIconDepth, bool preallocate = false); ~LazyBitmapAllocator(); diff --git a/src/kits/tracker/InfoWindow.cpp b/src/kits/tracker/InfoWindow.cpp index 96a487dfb2..8e74c68f9f 100644 --- a/src/kits/tracker/InfoWindow.cpp +++ b/src/kits/tracker/InfoWindow.cpp @@ -1131,10 +1131,12 @@ AttributeView::ModelChanged(Model *model, BMessage *message) // watch for icon updates const char *attrName; if (message->FindString("attr", &attrName) == B_OK) { - if (strcmp(attrName, kAttrLargeIcon) == 0) + if (strcmp(attrName, kAttrLargeIcon) == 0 + || strcmp(attrName, kAttrIcon) == 0) { Invalidate(BRect(10, 10, 10 + B_LARGE_ICON, 10 + B_LARGE_ICON)); - if (strcmp(attrName, kAttrMIMEType) == 0) { + } else if (strcmp(attrName, kAttrMIMEType) == 0) { + if (model->OpenNode() == B_OK) { InitStrings(model); model->CloseNode(); diff --git a/src/kits/tracker/Jamfile b/src/kits/tracker/Jamfile index 3f2d81efa0..fc3e6c27b7 100644 --- a/src/kits/tracker/Jamfile +++ b/src/kits/tracker/Jamfile @@ -6,6 +6,8 @@ AddSubDirSupportedPlatforms libbe_test ; UsePrivateHeaders shared ; UsePrivateHeaders tracker ; +UseLibraryHeaders icon ; + AddResources libtracker.so : TrackerIcons.rdef ; SubDirC++Flags @@ -86,7 +88,9 @@ SharedLibrary libtracker.so : ViewState.cpp VolumeWindow.cpp WidgetAttributeText.cpp - : be libtranslation.so + + : be translation libicon.a libagg.a + ; if $(TARGET_PLATFORM) = libbe_test { diff --git a/src/kits/tracker/Model.cpp b/src/kits/tracker/Model.cpp index e575d9936a..c57edabfce 100644 --- a/src/kits/tracker/Model.cpp +++ b/src/kits/tracker/Model.cpp @@ -531,6 +531,14 @@ Model::SetupBaseType() } +static bool +HasVectorIconHint(BNode *node) +{ + attr_info info; + return node->GetAttrInfo(kAttrIcon, &info) == B_OK; +} + + void Model::FinishSettingUpType() { @@ -543,7 +551,8 @@ Model::FinishSettingUpType() // disk again for models that do not have an icon defined by the node if (IsNodeOpen() && fBaseType != kLinkNode - && !CheckNodeIconHintPrivate(fNode, dynamic_cast(be_app) == NULL)) { + && !CheckNodeIconHintPrivate(fNode, dynamic_cast(be_app) == NULL) + && !HasVectorIconHint(fNode)) { // when checking for the node icon hint, if we are libtracker, only check // for small icons - checking for the large icons is a little more // work for the filesystem and this will speed up the test. @@ -813,8 +822,9 @@ Model::AttrChanged(const char *attrName) ASSERT(IsNodeOpen()); if (attrName - && (strcmp(attrName, kAttrMiniIcon) == 0 - || strcmp(attrName, kAttrLargeIcon) == 0)) + && (strcmp(attrName, kAttrIcon) == 0 + || strcmp(attrName, kAttrMiniIcon) == 0 + || strcmp(attrName, kAttrLargeIcon) == 0)) return true; if (!attrName diff --git a/src/kits/tracker/Pose.cpp b/src/kits/tracker/Pose.cpp index a645194cdd..2808253430 100644 --- a/src/kits/tracker/Pose.cpp +++ b/src/kits/tracker/Pose.cpp @@ -645,7 +645,7 @@ BPose::DeselectWithoutErasingBackground(BRect, BPoseView *poseView) DrawIcon(fLocation, poseView, poseView->ViewMode() == kIconMode ? B_LARGE_ICON : B_MINI_ICON, true); else - UpdateIcon(fLocation,poseView); + UpdateIcon(fLocation, poseView); BColumn *column = poseView->FirstColumn(); if (!column) diff --git a/src/kits/tracker/TrashWatcher.cpp b/src/kits/tracker/TrashWatcher.cpp index 1c0f436b07..2f6c23665a 100644 --- a/src/kits/tracker/TrashWatcher.cpp +++ b/src/kits/tracker/TrashWatcher.cpp @@ -162,12 +162,24 @@ BTrashWatcher::UpdateTrashIcons() // apply them onto the trash directory node size_t largeSize = 0; size_t smallSize = 0; + size_t vectorSize = 0; const void *largeData = GetTrackerResources()->LoadResource('ICON', fTrashFull ? kResTrashFullIcon : kResTrashIcon, &largeSize); const void *smallData = GetTrackerResources()->LoadResource('MICN', fTrashFull ? kResTrashFullIcon : kResTrashIcon, &smallSize); + const void *vectorData = GetTrackerResources()->LoadResource( + B_RAW_TYPE, fTrashFull ? kResTrashFullIcon : kResTrashIcon, + &vectorSize); + + if (vectorData) + trashDir.WriteAttr(kAttrIcon, B_RAW_TYPE, 0, + vectorData, vectorSize); +// TODO: enable me once the vector icon is indeed in the resources +// else +// TRESPASS(); + if (largeData) trashDir.WriteAttr(kAttrLargeIcon, 'ICON', 0, largeData, largeSize); diff --git a/src/kits/tracker/Utilities.cpp b/src/kits/tracker/Utilities.cpp index bba91b5b1f..a9f124dd2d 100644 --- a/src/kits/tracker/Utilities.cpp +++ b/src/kits/tracker/Utilities.cpp @@ -43,6 +43,7 @@ All rights reserved. #include #include #include +#include #include #include #include @@ -631,6 +632,8 @@ FlickerFreeStringView::Draw(BRect) edge_info eInfo; switch (Alignment()) { case B_ALIGN_LEFT: + case B_ALIGN_HORIZONTAL_UNSET: + case B_ALIGN_USE_FULL_WIDTH: { // If the first char has a negative left edge give it // some more room by shifting that much more to the right. @@ -1335,22 +1338,45 @@ GetAppIconFromAttr(BFile *file, BBitmap *result, icon_size size) BAppFileInfo appFileInfo(file); return appFileInfo.GetIcon(result, size); #else - const char *attrName = size == B_LARGE_ICON ? kAttrLargeIcon : kAttrMiniIcon; - uint32 type = size == B_LARGE_ICON ? LARGE_ICON_TYPE : MINI_ICON_TYPE; - char buffer[1024]; + const char *attrName = kAttrIcon; + uint32 type = B_RAW_TYPE; + + // try vector icon attr_info ainfo; - status_t err = err = file->GetAttrInfo(attrName, &ainfo); - if (err) - return err; + status_t ret = file->GetAttrInfo(attrName, &ainfo); - ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, (size_t)ainfo.size); + if (ret == B_OK) { + uint8 buffer[ainfo.size]; + ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, + ainfo.size); + if (readResult == ainfo.size) { + if (BIconUtils::GetVectorIcon(buffer, ainfo.size, result) == B_OK) + return B_OK; + } + } + + // try again with R5 icons + attrName = size == B_LARGE_ICON ? kAttrLargeIcon : kAttrMiniIcon; + type = size == B_LARGE_ICON ? LARGE_ICON_TYPE : MINI_ICON_TYPE; + + ret = file->GetAttrInfo(attrName, &ainfo); + if (ret < B_OK) + return ret; + + uint8 buffer[ainfo.size]; + + ssize_t readResult = file->ReadAttr(attrName, type, 0, buffer, ainfo.size); if (readResult <= 0) return (status_t)readResult; - result->SetBits(buffer, result->BitsLength(), 0, B_CMAP8); + if (result->ColorSpace() != B_CMAP8) { + ret = BIconUtils::ConvertFromCMAP8(buffer, size, size, size, result); + } else { + result->SetBits(buffer, result->BitsLength(), 0, B_CMAP8); + } - return B_OK; + return ret; #endif // B_APP_FILE_INFO_IS_FAST } diff --git a/src/kits/tracker/Utilities.h b/src/kits/tracker/Utilities.h index 936b03dd2f..82a9c0c3bd 100644 --- a/src/kits/tracker/Utilities.h +++ b/src/kits/tracker/Utilities.h @@ -75,7 +75,7 @@ const int64 kTBSize = kGBSize * kKBSize; const int32 kMiniIconSeparator = 3; -const color_space kDefaultIconDepth = B_CMAP8; +const color_space kDefaultIconDepth = B_RGBA32; // misc typedefs, constants and structs diff --git a/src/servers/app/drawing/DrawingEngine.cpp b/src/servers/app/drawing/DrawingEngine.cpp index c74594e9f6..4f3cb4f73f 100644 --- a/src/servers/app/drawing/DrawingEngine.cpp +++ b/src/servers/app/drawing/DrawingEngine.cpp @@ -502,8 +502,15 @@ DrawingEngine::DrawEllipse(BRect r, const DrawState *d, bool filled) if (Lock()) { make_rect_valid(r); BRect clipped = r; + fPainter->AlignEllipseRect(&clipped, filled); if (!filled) extend_by_stroke_width(clipped, d); + + clipped.left = floorf(clipped.left); + clipped.top = floorf(clipped.top); + clipped.right = ceilf(clipped.right); + clipped.bottom = ceilf(clipped.bottom); + clipped = fPainter->ClipRect(clipped); if (clipped.IsValid()) { fGraphicsCard->HideSoftwareCursor(clipped); @@ -808,6 +815,12 @@ DrawingEngine::DrawRoundRect(BRect r, float xrad, float yrad, // though I consider this unexpected behaviour. make_rect_valid(r); BRect clipped = fPainter->ClipRect(r); + + clipped.left = floorf(clipped.left); + clipped.top = floorf(clipped.top); + clipped.right = ceilf(clipped.right); + clipped.bottom = ceilf(clipped.bottom); + if (clipped.IsValid()) { fGraphicsCard->HideSoftwareCursor(clipped); @@ -826,6 +839,8 @@ DrawingEngine::DrawShape(const BRect& bounds, int32 opCount, const uint32* opList, int32 ptCount, const BPoint* ptList, const DrawState* d, bool filled) { + // NOTE: hides cursor regardless of if and where + // shape is drawn on screen, TODO: optimize fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawState(d); diff --git a/src/servers/app/drawing/Painter/Painter.cpp b/src/servers/app/drawing/Painter/Painter.cpp index f8a6943b36..225445ed5a 100644 --- a/src/servers/app/drawing/Painter/Painter.cpp +++ b/src/servers/app/drawing/Painter/Painter.cpp @@ -74,7 +74,11 @@ Painter::Painter() fRasterizer(NULL), fRenderer(NULL), fRendererBin(NULL), + fLineProfile(), + fPath(), + fCurve(fPath), + fSubpixelPrecise(false), fPenSize(1.0), @@ -358,11 +362,28 @@ Painter::StrokeLine(BPoint a, BPoint b) b.y += 0.5; } - agg::path_storage path; - path.move_to(a.x, a.y); - path.line_to(b.x, b.y); + fPath.remove_all(); - touched = _StrokePath(path); + if (a == b) { + // special case dots + fPath.move_to(a.x, a.y); + fPath.line_to(a.x + 1, a.y); + fPath.line_to(a.x + 1, a.y + 1); + fPath.line_to(a.x, a.y + 1); + + touched = _FillPath(fPath); + } else { + // do the pixel center offset here + a.x += 0.5; + a.y += 0.5; + b.x += 0.5; + b.y += 0.5; + + fPath.move_to(a.x, a.y); + fPath.line_to(b.x, b.y); + + touched = _StrokePath(fPath); + } return _Clipped(touched); } @@ -458,23 +479,24 @@ Painter::DrawPolygon(BPoint* p, int32 numPts, if (numPts > 0) { - agg::path_storage path; + fPath.remove_all(); + _Transform(p); - path.move_to(p->x, p->y); + fPath.move_to(p->x, p->y); for (int32 i = 1; i < numPts; i++) { p++; _Transform(p); - path.line_to(p->x, p->y); + fPath.line_to(p->x, p->y); } if (closed) - path.close_polygon(); + fPath.close_polygon(); if (filled) - return _FillPath(path); + return _FillPath(fPath); else - return _StrokePath(path); + return _StrokePath(fPath); } return BRect(0.0, 0.0, -1.0, -1.0); } @@ -485,26 +507,24 @@ Painter::DrawBezier(BPoint* p, bool filled) const { CHECK_CLIPPING - agg::path_storage curve; + fPath.remove_all(); _Transform(&(p[0])); _Transform(&(p[1])); _Transform(&(p[2])); _Transform(&(p[3])); - curve.move_to(p[0].x, p[0].y); - curve.curve4(p[1].x, p[1].y, + fPath.move_to(p[0].x, p[0].y); + fPath.curve4(p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y); - agg::conv_curve path(curve); - if (filled) { - curve.close_polygon(); - return _FillPath(path); + fPath.close_polygon(); + return _FillPath(fCurve); } else { - return _StrokePath(path); + return _StrokePath(fCurve); } } @@ -526,18 +546,18 @@ Painter::DrawShape(const int32& opCount, const uint32* opList, // TODO: if shapes are ever used more heavily in Haiku, // it would be nice to use BShape data directly (write // an AGG "VertexSource" adaptor) - agg::path_storage path; + fPath.remove_all(); for (int32 i = 0; i < opCount; i++) { uint32 op = opList[i] & 0xFF000000; if (op & OP_MOVETO) { - path.move_to(points->x + fPenLocation.x, points->y + fPenLocation.y); + fPath.move_to(points->x + fPenLocation.x, points->y + fPenLocation.y); points++; } if (op & OP_LINETO) { int32 count = opList[i] & 0x00FFFFFF; while (count--) { - path.line_to(points->x + fPenLocation.x, points->y + fPenLocation.y); + fPath.line_to(points->x + fPenLocation.x, points->y + fPenLocation.y); points++; } } @@ -545,23 +565,22 @@ Painter::DrawShape(const int32& opCount, const uint32* opList, if (op & OP_BEZIERTO) { int32 count = opList[i] & 0x00FFFFFF; while (count) { - path.curve4(points[0].x + fPenLocation.x, points[0].y + fPenLocation.y, - points[1].x + fPenLocation.x, points[1].y + fPenLocation.y, - points[2].x + fPenLocation.x, points[2].y + fPenLocation.y); + fPath.curve4(points[0].x + fPenLocation.x, points[0].y + fPenLocation.y, + points[1].x + fPenLocation.x, points[1].y + fPenLocation.y, + points[2].x + fPenLocation.x, points[2].y + fPenLocation.y); points += 3; count -= 3; } } if (op & OP_CLOSE) - path.close_polygon(); + fPath.close_polygon(); } - agg::conv_curve curve(path); if (filled) - return _FillPath(curve); + return _FillPath(fCurve); else - return _StrokePath(curve); + return _StrokePath(fCurve); } // StrokeRect @@ -601,19 +620,19 @@ Painter::StrokeRect(const BRect& r) const b.y += 0.5; } - agg::path_storage path; - path.move_to(a.x, a.y); + fPath.remove_all(); + fPath.move_to(a.x, a.y); if (a.x == b.x || a.y == b.y) { // special case rects with one pixel height or width - path.line_to(b.x, b.y); + fPath.line_to(b.x, b.y); } else { - path.line_to(b.x, a.y); - path.line_to(b.x, b.y); - path.line_to(a.x, b.y); + fPath.line_to(b.x, a.y); + fPath.line_to(b.x, b.y); + fPath.line_to(a.x, b.y); } - path.close_polygon(); + fPath.close_polygon(); - return _StrokePath(path); + return _StrokePath(fPath); } // StrokeRect @@ -678,14 +697,14 @@ Painter::FillRect(const BRect& r) const b.x += 1.0; b.y += 1.0; - agg::path_storage path; - path.move_to(a.x, a.y); - path.line_to(b.x, a.y); - path.line_to(b.x, b.y); - path.line_to(a.x, b.y); - path.close_polygon(); + fPath.remove_all(); + fPath.move_to(a.x, a.y); + fPath.line_to(b.x, a.y); + fPath.line_to(b.x, b.y); + fPath.line_to(a.x, b.y); + fPath.close_polygon(); - return _FillPath(path); + return _FillPath(fPath); } // FillRect @@ -810,7 +829,7 @@ Painter::StrokeRoundRect(const BRect& r, float xRadius, float yRadius) const // make the inner rect work as a hole fRasterizer->filling_rule(agg::fill_even_odd); - if (fPenSize > 4) + if (fPenSize > 2) agg::render_scanlines(*fRasterizer, *fPackedScanline, *fRenderer); else agg::render_scanlines(*fRasterizer, *fUnpackedScanline, *fRenderer); @@ -845,24 +864,31 @@ Painter::FillRoundRect(const BRect& r, float xRadius, float yRadius) const return _FillPath(rect); } - + +// AlignEllipseRect +void +Painter::AlignEllipseRect(BRect* rect, bool filled) const +{ + if (!fSubpixelPrecise) { + // align rect to pixels + align_rect_to_pixels(rect); + // account for "pixel index" versus "pixel area" + rect->right++; + rect->bottom++; + if (!filled && fmodf(fPenSize, 2.0) != 0.0) { + // align the stroke + rect->InsetBy(0.5, 0.5); + } + } +} + // DrawEllipse BRect Painter::DrawEllipse(BRect r, bool fill) const { CHECK_CLIPPING - if (!fSubpixelPrecise) { - // align rect to pixels - align_rect_to_pixels(&r); - // account for "pixel index" versus "pixel area" - r.right++; - r.bottom++; - if (!fill && fmodf(fPenSize, 2.0) != 0.0) { - // align the stroke - r.InsetBy(0.5, 0.5); - } - } + AlignEllipseRect(&r, fill); float xRadius = r.Width() / 2.0; float yRadius = r.Height() / 2.0; @@ -948,24 +974,24 @@ Painter::FillArc(BPoint center, float xRadius, float yRadius, agg::conv_curve segmentedArc(arc); - agg::path_storage path; + fPath.remove_all(); // build a new path by starting at the center point, // then traversing the arc, then going back to the center - path.move_to(center.x, center.y); + fPath.move_to(center.x, center.y); segmentedArc.rewind(0); double x; double y; unsigned cmd = segmentedArc.vertex(&x, &y); while (!agg::is_stop(cmd)) { - path.line_to(x, y); + fPath.line_to(x, y); cmd = segmentedArc.vertex(&x, &y); } - path.close_polygon(); + fPath.close_polygon(); - return _FillPath(path); + return _FillPath(fPath); } // #pragma mark - @@ -1249,18 +1275,18 @@ Painter::_DrawTriangle(BPoint pt1, BPoint pt2, BPoint pt3, bool fill) const _Transform(&pt2); _Transform(&pt3); - agg::path_storage path; + fPath.remove_all(); - path.move_to(pt1.x, pt1.y); - path.line_to(pt2.x, pt2.y); - path.line_to(pt3.x, pt3.y); + fPath.move_to(pt1.x, pt1.y); + fPath.line_to(pt2.x, pt2.y); + fPath.line_to(pt3.x, pt3.y); - path.close_polygon(); + fPath.close_polygon(); if (fill) - return _FillPath(path); + return _FillPath(fPath); else - return _StrokePath(path); + return _StrokePath(fPath); } // copy_bitmap_row_cmap8_copy @@ -1327,7 +1353,8 @@ copy_bitmap_row_bgr32_alpha(uint8* dst, const uint8* src, int32 numPixels, // _DrawBitmap void Painter::_DrawBitmap(agg::rendering_buffer& srcBuffer, color_space format, - BRect actualBitmapRect, BRect bitmapRect, BRect viewRect) const + BRect actualBitmapRect, BRect bitmapRect, + BRect viewRect) const { if (!fBuffer || !fValidClipping || !bitmapRect.IsValid() || !bitmapRect.Intersects(actualBitmapRect) @@ -1378,70 +1405,75 @@ Painter::_DrawBitmap(agg::rendering_buffer& srcBuffer, color_space format, switch (format) { case B_RGB32: case B_RGBA32: { - bool generic = true; // maybe we can use an optimized version if (xScale == 1.0 && yScale == 1.0) { if (fDrawingMode == B_OP_COPY) { - _DrawBitmapNoScale32(copy_bitmap_row_bgr32_copy, 4, srcBuffer, xOffset, yOffset, viewRect); - generic = false; + _DrawBitmapNoScale32(copy_bitmap_row_bgr32_copy, 4, + srcBuffer, xOffset, yOffset, viewRect); + return; } else if (fDrawingMode == B_OP_ALPHA - && fAlphaSrcMode == B_PIXEL_ALPHA && fAlphaFncMode == B_ALPHA_OVERLAY) { - _DrawBitmapNoScale32(copy_bitmap_row_bgr32_alpha, 4, srcBuffer, xOffset, yOffset, viewRect); - generic = false; + && fAlphaSrcMode == B_PIXEL_ALPHA + && fAlphaFncMode == B_ALPHA_OVERLAY) { + _DrawBitmapNoScale32(copy_bitmap_row_bgr32_alpha, 4, + srcBuffer, xOffset, yOffset, viewRect); + return; } } - if (generic) { - _DrawBitmapGeneric32(srcBuffer, xOffset, yOffset, xScale, yScale, viewRect); - } + _DrawBitmapGeneric32(srcBuffer, xOffset, yOffset, + xScale, yScale, viewRect); break; } default: { - bool generic = true; if (format == B_CMAP8 && xScale == 1.0 && yScale == 1.0) { if (fDrawingMode == B_OP_COPY) { - _DrawBitmapNoScale32(copy_bitmap_row_cmap8_copy, 1, srcBuffer, xOffset, yOffset, viewRect); - generic = false; + _DrawBitmapNoScale32(copy_bitmap_row_cmap8_copy, 1, + srcBuffer, xOffset, yOffset, viewRect); + return; } else if (fDrawingMode == B_OP_OVER) { - _DrawBitmapNoScale32(copy_bitmap_row_cmap8_over, 1, srcBuffer, xOffset, yOffset, viewRect); - generic = false; + _DrawBitmapNoScale32(copy_bitmap_row_cmap8_over, 1, + srcBuffer, xOffset, yOffset, viewRect); + return; } } - if (generic) { - // TODO: this is only a temporary implementation, - // to really handle other colorspaces, one would - // rather do the conversion with much less overhead, - // for example in the nn filter (hm), or in the - // scanline generator (better) - // maybe we can use an optimized version - BBitmap temp(actualBitmapRect, B_BITMAP_NO_SERVER_LINK, B_RGBA32); - status_t err = temp.ImportBits(srcBuffer.buf(), - srcBuffer.height() * srcBuffer.stride(), - srcBuffer.stride(), - 0, format); - if (err >= B_OK) { - agg::rendering_buffer convertedBuffer; - convertedBuffer.attach((uint8*)temp.Bits(), - (uint32)actualBitmapRect.IntegerWidth() + 1, - (uint32)actualBitmapRect.IntegerHeight() + 1, - temp.BytesPerRow()); - _DrawBitmapGeneric32(convertedBuffer, xOffset, yOffset, xScale, yScale, viewRect); - } else { - fprintf(stderr, "Painter::_DrawBitmap() - colorspace conversion failed: %s\n", strerror(err)); - } + // TODO: this is only a temporary implementation, + // to really handle other colorspaces, one would + // rather do the conversion with much less overhead, + // for example in the nn filter (hm), or in the + // scanline generator (better) + // maybe we can use an optimized version + BBitmap temp(actualBitmapRect, B_BITMAP_NO_SERVER_LINK, B_RGBA32); + status_t err = temp.ImportBits(srcBuffer.buf(), + srcBuffer.height() * srcBuffer.stride(), + srcBuffer.stride(), + 0, format); + if (err >= B_OK) { + agg::rendering_buffer convertedBuffer; + convertedBuffer.attach((uint8*)temp.Bits(), + (uint32)actualBitmapRect.IntegerWidth() + 1, + (uint32)actualBitmapRect.IntegerHeight() + 1, + temp.BytesPerRow()); + _DrawBitmapGeneric32(convertedBuffer, xOffset, yOffset, + xScale, yScale, viewRect); + } else { + fprintf(stderr, "Painter::_DrawBitmap() - " + "colorspace conversion failed: %s\n", strerror(err)); } break; } } } +#define DEBUG_DRAW_BITMAP 0 + // _DrawBitmapNoScale32 template void Painter::_DrawBitmapNoScale32(F copyRowFunction, uint32 bytesPerSourcePixel, agg::rendering_buffer& srcBuffer, - int32 xOffset, int32 yOffset, BRect viewRect) const + int32 xOffset, int32 yOffset, + BRect viewRect) const { // NOTE: this would crash if viewRect was large enough to read outside the // bitmap, so make sure this is not the case before calling this function! @@ -1456,6 +1488,21 @@ Painter::_DrawBitmapNoScale32(F copyRowFunction, uint32 bytesPerSourcePixel, int32 right = (int32)viewRect.right; int32 bottom = (int32)viewRect.bottom; +#if DEBUG_DRAW_BITMAP +if (left - xOffset < 0 || left - xOffset >= (int32)srcBuffer.width() || + right - xOffset >= (int32)srcBuffer.width() || + top - yOffset < 0 || top - yOffset >= (int32)srcBuffer.height() || + bottom - yOffset >= (int32)srcBuffer.height()) { + + char message[256]; + sprintf(message, "reading outside of bitmap (%ld, %ld, %ld, %ld) " + "(%d, %d) (%ld, %ld)", + left - xOffset, top - yOffset, right - xOffset, bottom - yOffset, + srcBuffer.width(), srcBuffer.height(), xOffset, yOffset); + debugger(message); +} +#endif + const rgb_color* colorMap = SystemPalette(); // copy rects, iterate over clipping boxes @@ -1468,10 +1515,12 @@ Painter::_DrawBitmapNoScale32(F copyRowFunction, uint32 bytesPerSourcePixel, int32 y2 = min_c(fBaseRenderer->ymax(), bottom); if (y1 <= y2) { uint8* dstHandle = dst + y1 * dstBPR + x1 * 4; - const uint8* srcHandle = src + (y1 - yOffset) * srcBPR + (x1 - xOffset) * bytesPerSourcePixel; + const uint8* srcHandle = src + (y1 - yOffset) * srcBPR + + (x1 - xOffset) * bytesPerSourcePixel; for (; y1 <= y2; y1++) { - copyRowFunction(dstHandle, srcHandle, x2 - x1 + 1, colorMap); + copyRowFunction(dstHandle, srcHandle, x2 - x1 + 1, + colorMap); dstHandle += dstBPR; srcHandle += srcBPR; @@ -1496,7 +1545,8 @@ Painter::_DrawBitmapGeneric32(agg::rendering_buffer& srcBuffer, agg::trans_affine srcMatrix; // NOTE: R5 seems to ignore this offset when drawing bitmaps -// srcMatrix *= agg::trans_affine_translation(-actualBitmapRect.left, -actualBitmapRect.top); +// srcMatrix *= agg::trans_affine_translation(-actualBitmapRect.left, +// -actualBitmapRect.top); agg::trans_affine imgMatrix; imgMatrix *= agg::trans_affine_scaling(xScale, yScale); @@ -1528,14 +1578,14 @@ Painter::_DrawBitmapGeneric32(agg::rendering_buffer& srcBuffer, viewRect.bottom++; // path enclosing the bitmap - agg::path_storage path; - path.move_to(viewRect.left, viewRect.top); - path.line_to(viewRect.right, viewRect.top); - path.line_to(viewRect.right, viewRect.bottom); - path.line_to(viewRect.left, viewRect.bottom); - path.close_polygon(); + fPath.remove_all(); + fPath.move_to(viewRect.left, viewRect.top); + fPath.line_to(viewRect.right, viewRect.top); + fPath.line_to(viewRect.right, viewRect.bottom); + fPath.line_to(viewRect.left, viewRect.bottom); + fPath.close_polygon(); - agg::conv_transform transformedPath(path, srcMatrix); + agg::conv_transform transformedPath(fPath, srcMatrix); fRasterizer->add_path(transformedPath); // render the path with the bitmap as scanline fill @@ -1669,14 +1719,11 @@ Painter::_StrokePath(VertexSource& path) const stroke.miter_limit(fMiterLimit); fRasterizer->reset(); - agg::conv_clip_polygon > clippedPath(stroke); - clippedPath.clip_box(-500, -500, fBuffer->width() + 500, fBuffer->height() + 500); - fRasterizer->add_path(clippedPath); + clipping_rect cb = fClippingRegion->FrameInt(); + fRasterizer->clip_box(cb.left, cb.top, cb.right + 1, cb.bottom + 1); + fRasterizer->add_path(stroke); - if (fPenSize > 4) - agg::render_scanlines(*fRasterizer, *fPackedScanline, *fRenderer); - else - agg::render_scanlines(*fRasterizer, *fUnpackedScanline, *fRenderer); + agg::render_scanlines(*fRasterizer, *fPackedScanline, *fRenderer); // } else { // TODO: update to AGG 2.3 to get rid of the remaining problems: // rects which are 2 or 1 pixel high/wide don't render at all. @@ -1697,11 +1744,11 @@ BRect Painter::_FillPath(VertexSource& path) const { fRasterizer->reset(); - agg::conv_clip_polygon clippedPath(path); - clippedPath.clip_box(-500, -500, fBuffer->width() + 500, fBuffer->height() + 500); - fRasterizer->add_path(clippedPath); + clipping_rect cb = fClippingRegion->FrameInt(); + fRasterizer->clip_box(cb.left, cb.top, cb.right + 1, cb.bottom + 1); + fRasterizer->add_path(path); agg::render_scanlines(*fRasterizer, *fPackedScanline, *fRenderer); - return _Clipped(_BoundingBox(clippedPath)); + return _Clipped(_BoundingBox(path)); } diff --git a/src/servers/app/drawing/Painter/Painter.h b/src/servers/app/drawing/Painter/Painter.h index a51ad0523d..d0af13424c 100644 --- a/src/servers/app/drawing/Painter/Painter.h +++ b/src/servers/app/drawing/Painter/Painter.h @@ -15,6 +15,9 @@ #include "defines.h" +#include +#include + #include #include @@ -147,6 +150,9 @@ class Painter { float yRadius) const; // ellipses + void AlignEllipseRect(BRect* rect, + bool filled) const; + BRect DrawEllipse( BRect r, bool filled) const; @@ -260,6 +266,8 @@ class Painter { renderer_bin_type* fRendererBin; agg::line_profile_aa fLineProfile; +mutable agg::path_storage fPath; +mutable agg::conv_curve fCurve; // for internal coordinate rounding/transformation bool fSubpixelPrecise; diff --git a/src/tests/kits/interface/layout/Jamfile b/src/tests/kits/interface/layout/Jamfile index db0936381a..0cef967d0c 100644 --- a/src/tests/kits/interface/layout/Jamfile +++ b/src/tests/kits/interface/layout/Jamfile @@ -1,2 +1,15 @@ SubDir HAIKU_TOP src tests kits interface layout ; +SetSubDirSupportedPlatforms haiku libbe_test ; + +SimpleTest LayoutTest1 : + LayoutTest1.cpp + : + be +; + + +if $(TARGET_PLATFORM) = libbe_test { + HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : LayoutTest1 + : tests!apps ; +} diff --git a/src/tests/kits/interface/layout/LayoutTest1.cpp b/src/tests/kits/interface/layout/LayoutTest1.cpp new file mode 100644 index 0000000000..630c45db0c --- /dev/null +++ b/src/tests/kits/interface/layout/LayoutTest1.cpp @@ -0,0 +1,1711 @@ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const rgb_color kBlack = {0, 0, 0, 255}; +static const rgb_color kRed = {255, 0, 0, 255}; + +// message what codes +enum { + MSG_TEST_SELECTED = 'tsts', + + // used in tests + MSG_TOGGLE_1 = 'tgl1', + MSG_TOGGLE_2 = 'tgl2', + + MSG_FIXED_ASPECT_RATIO = 'hwas', + MSG_FIXED_SUM = 'hwfs', + MSG_FIXED_PRODUCT = 'hwfp', +}; + +// HeightForWidthTestView types +enum { + FIXED_SUM, + FIXED_PRODUCT, + FIXED_ASPECT_RATIO, +}; + + +// TestView +class TestView : public BView { +public: + TestView(const rgb_color& color = kBlack) + : BView("test view", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), + fColor(color) + { + } + + void SetColor(const rgb_color& color) + { + fColor = color; + Invalidate(); + } + + virtual void Draw(BRect updateRect) + { + SetHighColor(fColor); + + BRect bounds(Bounds()); + StrokeRect(bounds); + + BPoint rightBottom = bounds.RightBottom(); + StrokeLine(B_ORIGIN, rightBottom); + StrokeLine(BPoint(rightBottom.x, 0), BPoint(0, rightBottom.y)); + } + + virtual BSize MinSize() + { + return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(10, 10)); + } + + virtual BSize PreferredSize() + { + return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), + BSize(50, 50)); + } + +private: + rgb_color fColor; +}; + + +// HeightForWidthTestView +class HeightForWidthTestView : public TestView { +public: + HeightForWidthTestView(uint32 type, float value) + : fType(NULL) + { + SetType(type, value); + } + + HeightForWidthTestView(const rgb_color& color, uint32 type, float value) + : TestView(color), + fType(NULL) + { + SetType(type, value); + } + + ~HeightForWidthTestView() + { + delete fType; + } + + void SetType(uint32 type, float value) + { + delete fType; + + switch (type) { + case FIXED_SUM: + fType = new FixedSumType((int)value); + break; + case FIXED_PRODUCT: + fType = new FixedProductType((int)value); + break; + case FIXED_ASPECT_RATIO: + default: + fType = new FixedAspectRatioType(value); + break; + } + + InvalidateLayout(); + } + + BSize MinSize() { + return BLayoutUtils::ComposeSize(ExplicitMinSize(), fType->MinSize()); + } + + BSize MaxSize() { + return BLayoutUtils::ComposeSize(ExplicitMaxSize(), fType->MaxSize()); + } + + BSize PreferredSize() { + return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), + fType->PreferredSize()); + } + + bool HasHeightForWidth() { + return true; + } + + void GetHeightForWidth(float width, float* minHeight, float* maxHeight, + float* preferredHeight) { + float dummy; + fType->GetHeightForWidth(width, + minHeight ? minHeight : &dummy, + maxHeight ? maxHeight : &dummy, + preferredHeight ? preferredHeight : &dummy); + } + +private: + class HeightForWidthType { + public: + virtual ~HeightForWidthType() + { + } + + virtual BSize MinSize() = 0; + virtual BSize MaxSize() = 0; + virtual BSize PreferredSize() = 0; + virtual void GetHeightForWidth(float width, float* minHeight, + float* maxHeight, float* preferredHeight) = 0; + }; + + class FixedAspectRatioType : public HeightForWidthType { + public: + FixedAspectRatioType(float ratio) + : fAspectRatio(ratio) + { + } + + virtual BSize MinSize() + { + return BSize(-1, -1); + } + + virtual BSize MaxSize() + { + return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); + } + + virtual BSize PreferredSize() + { + float preferredWidth = 49; + float dummy, preferredHeight; + GetHeightForWidth(preferredWidth, &dummy, &dummy, &preferredHeight); + return BSize(preferredWidth, preferredHeight); + } + + virtual void GetHeightForWidth(float width, float* minHeight, + float* maxHeight, float* preferredHeight) + { + float height = floor((width + 1) * fAspectRatio) - 1; + *minHeight = height; + *maxHeight = height; + *preferredHeight = height; + } + + private: + float fAspectRatio; + }; + + class FixedSumType : public HeightForWidthType { + public: + FixedSumType(float sum) + : fSum(sum) + { + } + + virtual BSize MinSize() + { + return BSize(0, 0); + } + + virtual BSize MaxSize() + { + return BSize(fSum - 2, fSum - 2); + } + + virtual BSize PreferredSize() + { + float preferredWidth = floor(fSum / 2) - 1; + float dummy, preferredHeight; + GetHeightForWidth(preferredWidth, &dummy, &dummy, &preferredHeight); + return BSize(preferredWidth, preferredHeight); + } + + virtual void GetHeightForWidth(float width, float* minHeight, + float* maxHeight, float* preferredHeight) + { + float height = fSum - (width + 1) - 1; + *minHeight = height; + *maxHeight = height; + *preferredHeight = height; + } + + private: + float fSum; + }; + + class FixedProductType : public HeightForWidthType { + public: + FixedProductType(float product) + : fProduct(product) + { + } + + virtual BSize MinSize() + { + return BSize(0, 0); + } + + virtual BSize MaxSize() + { + return BSize(fProduct - 1, fProduct - 1); + } + + virtual BSize PreferredSize() + { + float preferredWidth = floor(sqrt(fProduct)); + float dummy, preferredHeight; + GetHeightForWidth(preferredWidth, &dummy, &dummy, &preferredHeight); + return BSize(preferredWidth, preferredHeight); + } + + virtual void GetHeightForWidth(float width, float* minHeight, + float* maxHeight, float* preferredHeight) + { + float height = floor(fProduct / (width + 1)) - 1; + *minHeight = height; + *maxHeight = height; + *preferredHeight = height; + } + + private: + float fProduct; + }; + +private: + HeightForWidthType* fType; +}; + + +// Test +struct Test : BHandler { + BString name; + BView* rootView; + BString description; + + Test(const char* name, BView* view, const char* description) + : BHandler(name), + name(name), + rootView(view), + description(description) + { + } + + virtual ~Test() + { + } + + virtual void RegisterListeners() + { + } +}; + + +// GroupLayoutTest1 +struct GroupLayoutTest1 : public Test { + GroupLayoutTest1() + : Test("Group", NULL, "Simple BGroupLayout.") + { + rootView = BGroupLayoutBuilder(B_HORIZONTAL, 10) + // controls + .AddGroup(B_VERTICAL, 10) + .Add(toggleRowButton = new BButton("Toggle Row", + new BMessage(MSG_TOGGLE_1))) + .Add(toggleViewButton = new BButton("Toggle View", + new BMessage(MSG_TOGGLE_2))) + .AddGlue() + .End() + + // test views + .AddGroup(B_VERTICAL, 10) + // row 1 + .AddGroup(B_HORIZONTAL, 10, 1) + .Add(new TestView(), 1) + .Add(toggledView = new TestView(), 2) + .Add(new TestView(), 3) + .End() + + // row 2 + .AddGroup(B_HORIZONTAL, 10, 2).GetTopView(&toggledRow) + .Add(new TestView()) + .Add(new TestView()) + .Add(new TestView()) + .End() + + // row 3 + .AddGroup(B_HORIZONTAL, 10, 3) + .Add(new TestView(), 3) + .Add(toggledView = new TestView(), 2) + .Add(new TestView(), 1) + .End() + .End() + ; + } + + virtual void RegisterListeners() + { + toggleRowButton->SetTarget(this); + toggleViewButton->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_TOGGLE_1: + { + if (toggledRow->IsHidden(toggledRow)) + toggledRow->Show(); + else + toggledRow->Hide(); + break; + } + + case MSG_TOGGLE_2: + { + if (toggledView->IsHidden(toggledView)) + toggledView->Show(); + else + toggledView->Hide(); + break; + } + + default: + BHandler::MessageReceived(message); + break; + } + } + +private: + BButton* toggleRowButton; + BButton* toggleViewButton; + BView* toggledRow; + TestView* toggledView; +}; + + +// GroupAlignedLayoutTest1 +struct GroupAlignedLayoutTest1 : public Test { + GroupAlignedLayoutTest1() + : Test("Group aligned", NULL, + "Simple BGroupLayout, rows 1 and 3 aligned.") + { + BGroupView* rootView = new BGroupView(B_HORIZONTAL, 10); + this->rootView = rootView; + + // controls + + BGroupView* controls = new BGroupView(B_VERTICAL, 10); + rootView->AddChild(controls); + + toggleRowButton = new BButton("Toggle Row", new BMessage(MSG_TOGGLE_1)); + controls->AddChild(toggleRowButton); + + toggleViewButton = new BButton("Toggle View", + new BMessage(MSG_TOGGLE_2)); + controls->AddChild(toggleViewButton); + + + controls->AddChild(BSpaceLayoutItem::CreateGlue()); + + // test views + + BGroupView* testViews = new BGroupView(B_VERTICAL, 10); + rootView->AddChild(testViews); + + // row 1 + BGroupView* row = new BGroupView(B_HORIZONTAL, 10); + BGroupView* row1 = row; + testViews->GroupLayout()->AddView(row, 1); + + row->GroupLayout()->AddView(new TestView(), 1); + toggledView = new TestView(); + row->GroupLayout()->AddView(toggledView, 2); + row->GroupLayout()->AddView(new TestView(), 3); + + // row 2 + row = new BGroupView(B_HORIZONTAL, 10); + toggledRow = row; + testViews->GroupLayout()->AddView(row, 2); + + row->GroupLayout()->AddView(new TestView()); + row->GroupLayout()->AddView(new TestView()); + row->GroupLayout()->AddView(new TestView()); + + // row 3 + row = new BGroupView(B_HORIZONTAL, 10); + BGroupView* row3 = row; + testViews->GroupLayout()->AddView(row, 3); + + row->GroupLayout()->AddView(new TestView(), 3); + row->GroupLayout()->AddView(new TestView(), 2); + row->GroupLayout()->AddView(new TestView(), 1); + + // align rows 1 and 3 + row1->GroupLayout()->AlignLayoutWith(row3->GroupLayout(), B_HORIZONTAL); + } + + virtual void RegisterListeners() + { + toggleRowButton->SetTarget(this); + toggleViewButton->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_TOGGLE_1: + { + if (toggledRow->IsHidden(toggledRow)) + toggledRow->Show(); + else + toggledRow->Hide(); + break; + } + + case MSG_TOGGLE_2: + { + if (toggledView->IsHidden(toggledView)) + toggledView->Show(); + else + toggledView->Hide(); + break; + } + + default: + BHandler::MessageReceived(message); + break; + } + } + +private: + BButton* toggleRowButton; + BButton* toggleViewButton; + BGroupView* toggledRow; + TestView* toggledView; +}; + + +// GridLayoutTest1 +struct GridLayoutTest1 : public Test { + GridLayoutTest1() + : Test("Grid", NULL, "Simple BGridLayout.") + { + rootView = BGroupLayoutBuilder(B_HORIZONTAL, 10) + // controls + .AddGroup(B_VERTICAL, 10) + .Add(toggleView1Button = new BButton("Toggle View 1", + new BMessage(MSG_TOGGLE_1))) + .Add(toggleView2Button = new BButton("Toggle View 2", + new BMessage(MSG_TOGGLE_2))) + .AddGlue() + .End() + + // test views + .Add(BGridLayoutBuilder(10, 10) + // row 1 + .Add(toggledView1 = new TestView(), 0, 0, 3, 1) + .Add(new TestView(), 3, 0) + .Add(new TestView(), 4, 0) + + // row 2 + .Add(new TestView(), 0, 1) + .Add(new TestView(), 1, 1) + .Add(new TestView(), 2, 1) + .Add(new TestView(), 3, 1) + .Add(new TestView(), 4, 1) + + // row 3 + .Add(new TestView(), 0, 2) + .Add(toggledView2 = new TestView(), 1, 2, 2, 2) + .Add(new TestView(), 3, 2) + .Add(new TestView(), 4, 2) + + // row 4 + .Add(new TestView(), 0, 3) + .Add(new TestView(), 3, 3) + .Add(new TestView(), 4, 3) + + // weights + .SetColumnWeight(0, 1) + .SetColumnWeight(1, 2) + .SetColumnWeight(2, 3) + .SetColumnWeight(3, 4) + .SetColumnWeight(4, 5) + + .SetRowWeight(0, 1) + .SetRowWeight(1, 2) + .SetRowWeight(2, 3) + .SetRowWeight(3, 4) + ) + ; + } + + virtual void RegisterListeners() + { + toggleView1Button->SetTarget(this); + toggleView2Button->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_TOGGLE_1: + { + if (toggledView1->IsHidden(toggledView1)) + toggledView1->Show(); + else + toggledView1->Hide(); + break; + } + + case MSG_TOGGLE_2: + { + if (toggledView2->IsHidden(toggledView2)) + toggledView2->Show(); + else + toggledView2->Hide(); + break; + } + + default: + BHandler::MessageReceived(message); + break; + } + } + +private: + BButton* toggleView1Button; + BButton* toggleView2Button; + TestView* toggledView1; + TestView* toggledView2; +}; + + +// SplitterGroupLayoutTest1 +struct SplitterGroupLayoutTest1 : public Test { + SplitterGroupLayoutTest1() + : Test("Group, splitters 1", NULL, "BGroupLayout with BSplitters.") + { + rootView = BGroupLayoutBuilder(B_HORIZONTAL, 10) + // controls + .AddGroup(B_VERTICAL, 10) + .Add(toggleRowButton = new BButton("Toggle Row", + new BMessage(MSG_TOGGLE_1))) + .Add(toggleViewButton = new BButton("Toggle View", + new BMessage(MSG_TOGGLE_2))) + .AddGlue() + .End() + + // test views + .Add(BSplitLayoutBuilder(B_VERTICAL, 10) + // row 1 + .Add(BSplitLayoutBuilder(B_HORIZONTAL, 10) + .Add(new TestView(), 1) + .Add(toggledView = new TestView(), 2) + .Add(new TestView(), 3) + , 1) + // make the row uncollapsible + .SetCollapsible(false) + + // row 2 + .Add(toggledRow = BSplitLayoutBuilder(B_HORIZONTAL, 10) + .Add(new TestView()) + .Add(new TestView()) + .Add(new TestView()) + , 2) + + // row 3 + .Add(BSplitLayoutBuilder(B_HORIZONTAL, 10) + .Add(new TestView(), 3) + .Add(toggledView = new TestView(), 2) + .Add(new TestView(), 1) + , 3) + // make the row uncollapsible + .SetCollapsible(false) + ) + ; + } + + virtual void RegisterListeners() + { + toggleRowButton->SetTarget(this); + toggleViewButton->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_TOGGLE_1: + { + if (toggledRow->IsHidden(toggledRow)) + toggledRow->Show(); + else + toggledRow->Hide(); + break; + } + + case MSG_TOGGLE_2: + { + if (toggledView->IsHidden(toggledView)) + toggledView->Show(); + else + toggledView->Hide(); + break; + } + + default: + BHandler::MessageReceived(message); + break; + } + } + +private: + BButton* toggleRowButton; + BButton* toggleViewButton; + BView* toggledRow; + TestView* toggledView; +}; + + +// SplitterGroupLayoutTest2 +struct SplitterGroupLayoutTest2 : public Test { + SplitterGroupLayoutTest2() + : Test("Group, splitters 2", NULL, + "BGroupLayout with BSplitters. Restricted maximum widths.") + { + TestView* testView1 = new TestView(); + TestView* testView2 = new TestView(); + TestView* testView3 = new TestView(); + + rootView = BGroupLayoutBuilder(B_HORIZONTAL, 10) + // test views + .AddGroup(B_VERTICAL, 10) + // split view + .Add(BSplitLayoutBuilder(B_HORIZONTAL, 10) + .Add(testView1, 0) + .Add(testView2, 1) + .Add(testView3, 2) + ) + .End() + ; + + // set maximal width on the test views + testView1->SetExplicitMaxSize(BSize(100, B_SIZE_UNSET)); + testView2->SetExplicitMaxSize(BSize(100, B_SIZE_UNSET)); + testView3->SetExplicitMaxSize(BSize(100, B_SIZE_UNSET)); + } +}; + + +// SplitterGridLayoutTest1 +struct SplitterGridLayoutTest1 : public Test { + SplitterGridLayoutTest1() + : Test("Grid, h splitters", NULL, + "BGridLayout with horizontal BSplitters.") + { + BGridLayout* layouts[3]; + + rootView = BGroupLayoutBuilder(B_HORIZONTAL, 10) + // controls + .AddGroup(B_VERTICAL, 10) + .Add(toggleView1Button = new BButton("Toggle View 1", + new BMessage(MSG_TOGGLE_1))) + .Add(toggleView2Button = new BButton("Toggle View 2", + new BMessage(MSG_TOGGLE_2))) + .AddGlue() + .End() + + // test views + .Add(BSplitLayoutBuilder(B_HORIZONTAL, 10) + // splitter element 1 + .Add(BGridLayoutBuilder(10, 10) + .GetGridLayout(&layouts[0]) + // row 1 + .Add(toggledView1 = new TestView(), 0, 0, 3, 1) + // row 2 + .Add(new TestView(), 0, 1) + .Add(new TestView(), 1, 1) + .Add(new TestView(), 2, 1) + // row 3 + .Add(new TestView(), 0, 2) + .Add(toggledView2 = new TestView(), 1, 2, 2, 2) + // row 4 + .Add(new TestView(), 0, 3) + + // column weights + .SetColumnWeight(0, 1) + .SetColumnWeight(1, 2) + .SetColumnWeight(2, 3) + , 6) + + // splitter element 2 + .Add(BGridLayoutBuilder(10, 10) + .GetGridLayout(&layouts[1]) + // row 1 + .Add(new TestView(), 0, 0) + // row 2 + .Add(new TestView(), 0, 1) + // row 3 + .Add(new TestView(), 0, 2) + // row 4 + .Add(new TestView(), 0, 3) + , 4) + + // splitter element 3 + .Add(BGridLayoutBuilder(10, 10) + .GetGridLayout(&layouts[2]) + // row 1 + .Add(new TestView(), 0, 0) + // row 2 + .Add(new TestView(), 0, 1) + // row 3 + .Add(new TestView(), 0, 2) + // row 4 + .Add(new TestView(), 0, 3) + , 5) + ) + ; + + // set row weights + for (int i = 0; i < 3; i++) { + layouts[i]->SetRowWeight(0, 1); + layouts[i]->SetRowWeight(1, 2); + layouts[i]->SetRowWeight(2, 3); + layouts[i]->SetRowWeight(3, 4); + } + + // set explicit min/max heights for toggled views + toggledView1->SetExplicitMinSize(BSize(B_SIZE_UNSET, 100)); + toggledView2->SetExplicitMaxSize(BSize(B_SIZE_UNSET, 200)); + + // align the layouts + layouts[0]->AlignLayoutWith(layouts[1], B_VERTICAL); + layouts[0]->AlignLayoutWith(layouts[2], B_VERTICAL); + } + + virtual void RegisterListeners() + { + toggleView1Button->SetTarget(this); + toggleView2Button->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_TOGGLE_1: + { + if (toggledView1->IsHidden(toggledView1)) + toggledView1->Show(); + else + toggledView1->Hide(); + break; + } + + case MSG_TOGGLE_2: + { + if (toggledView2->IsHidden(toggledView2)) + toggledView2->Show(); + else + toggledView2->Hide(); + break; + } + + default: + BHandler::MessageReceived(message); + break; + } + } + +private: + BButton* toggleView1Button; + BButton* toggleView2Button; + TestView* toggledView1; + TestView* toggledView2; +}; + + +// SplitterGridLayoutTest2 +struct SplitterGridLayoutTest2 : public Test { + SplitterGridLayoutTest2() + : Test("Grid, v splitters", NULL, + "BGridLayout with vertical BSplitters.") + { + BGridLayout* layouts[3]; + + rootView = BGroupLayoutBuilder(B_HORIZONTAL, 10) + // controls + .AddGroup(B_VERTICAL, 10) + .Add(toggleView1Button = new BButton("Toggle View 1", + new BMessage(MSG_TOGGLE_1))) + .Add(toggleView2Button = new BButton("Toggle View 2", + new BMessage(MSG_TOGGLE_2))) + .AddGlue() + .End() + + // test views + .Add(BSplitLayoutBuilder(B_VERTICAL, 10) + // splitter element 1 + .Add(BGridLayoutBuilder(10, 10) + .GetGridLayout(&layouts[0]) + // row 1 + .Add(toggledView1 = new TestView(), 0, 0, 3, 1) + .Add(new TestView(), 3, 0) + .Add(new TestView(), 4, 0) + , 1) + + // splitter element 2 + .Add(BGridLayoutBuilder(10, 10) + .GetGridLayout(&layouts[1]) + // row 2 + .Add(new TestView(), 0, 0) + .Add(new TestView(), 1, 0) + .Add(new TestView(), 2, 0) + .Add(new TestView(), 3, 0) + .Add(new TestView(), 4, 0) + , 2) + + // splitter element 3 + .Add(BGridLayoutBuilder(10, 10) + .GetGridLayout(&layouts[2]) + // row 3 + .Add(new TestView(), 0, 0) + .Add(toggledView2 = new TestView(), 1, 0, 2, 2) + .Add(new TestView(), 3, 0) + .Add(new TestView(), 4, 0) + // row 4 + .Add(new TestView(), 0, 1) + .Add(new TestView(), 3, 1) + .Add(new TestView(), 4, 1) + + // row weights + .SetRowWeight(0, 3) + .SetRowWeight(1, 4) + , 7) + ) + ; + + // set column weights + for (int i = 0; i < 3; i++) { + layouts[i]->SetColumnWeight(0, 1); + layouts[i]->SetColumnWeight(1, 2); + layouts[i]->SetColumnWeight(2, 3); + layouts[i]->SetColumnWeight(3, 4); + layouts[i]->SetColumnWeight(4, 5); + } + + // align the layouts + layouts[0]->AlignLayoutWith(layouts[1], B_HORIZONTAL); + layouts[0]->AlignLayoutWith(layouts[2], B_HORIZONTAL); + } + + virtual void RegisterListeners() + { + toggleView1Button->SetTarget(this); + toggleView2Button->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_TOGGLE_1: + { + if (toggledView1->IsHidden(toggledView1)) + toggledView1->Show(); + else + toggledView1->Hide(); + break; + } + + case MSG_TOGGLE_2: + { + if (toggledView2->IsHidden(toggledView2)) + toggledView2->Show(); + else + toggledView2->Hide(); + break; + } + + default: + BHandler::MessageReceived(message); + break; + } + } + +private: + BButton* toggleView1Button; + BButton* toggleView2Button; + TestView* toggledView1; + TestView* toggledView2; +}; + + +// GroupLayoutHeightForWidthTestHorizontal1 +struct GroupLayoutHeightForWidthTestHorizontal1 : public Test { + GroupLayoutHeightForWidthTestHorizontal1() + : Test("Group, height for width, h", NULL, + "Horizontal BGroupLayout with height for width view.") + { + rootView = BGroupLayoutBuilder(B_HORIZONTAL, 10) + // controls + .AddGroup(B_VERTICAL, 10, 0) + .Add(aspectRatioButton = new BRadioButton("fixed aspect ratio", + new BMessage(MSG_FIXED_ASPECT_RATIO))) + .Add(sumButton = new BRadioButton("fixed sum", + new BMessage(MSG_FIXED_SUM))) + .Add(productButton = new BRadioButton("fixed product", + new BMessage(MSG_FIXED_PRODUCT))) + .AddGlue() + .End() + + // test views + .AddGroup(B_VERTICAL, 10) + // row 1 + .AddGroup(B_HORIZONTAL, 10) + .Add(new TestView()) + .Add(new TestView()) + .Add(new TestView()) + .End() + + // row 2 + .AddGroup(B_HORIZONTAL, 10) + .Add(new TestView()) + .Add(heightForWidthView = new HeightForWidthTestView(kRed, + FIXED_ASPECT_RATIO, 0.5f)) + .Add(new TestView()) + .End() + + // row 3 + .AddGroup(B_HORIZONTAL, 10) + .Add(new TestView()) + .Add(new TestView()) + .Add(new TestView()) + .End() + .End() + ; + + aspectRatioButton->SetValue(1); + } + + virtual void RegisterListeners() + { + aspectRatioButton->SetTarget(this); + sumButton->SetTarget(this); + productButton->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_FIXED_ASPECT_RATIO: + { + heightForWidthView->SetType(FIXED_ASPECT_RATIO, 0.5f); + break; + } + + case MSG_FIXED_SUM: + { + heightForWidthView->SetType(FIXED_SUM, 200); + break; + } + + case MSG_FIXED_PRODUCT: + { + heightForWidthView->SetType(FIXED_PRODUCT, 40000); + break; + } + + default: + BHandler::MessageReceived(message); + break; + } + } + +private: + BRadioButton* aspectRatioButton; + BRadioButton* sumButton; + BRadioButton* productButton; + HeightForWidthTestView* heightForWidthView; +}; + + +// GroupLayoutHeightForWidthTestVertical1 +struct GroupLayoutHeightForWidthTestVertical1 : public Test { + GroupLayoutHeightForWidthTestVertical1() + : Test("Group, height for width, v", NULL, + "Vertical BGroupLayout with height for width view.") + { + rootView = BGroupLayoutBuilder(B_HORIZONTAL, 10) + // controls + .AddGroup(B_VERTICAL, 10, 0) + .Add(aspectRatioButton = new BRadioButton("fixed aspect ratio", + new BMessage(MSG_FIXED_ASPECT_RATIO))) + .Add(sumButton = new BRadioButton("fixed sum", + new BMessage(MSG_FIXED_SUM))) + .Add(productButton = new BRadioButton("fixed product", + new BMessage(MSG_FIXED_PRODUCT))) + .AddGlue() + .End() + + // test views + .AddGroup(B_HORIZONTAL, 10) + // column 1 + .AddGroup(B_VERTICAL, 10) + .Add(new TestView()) + .Add(new TestView()) + .Add(new TestView()) + .End() + + // column 2 + .AddGroup(B_VERTICAL, 10) + .Add(new TestView()) + .Add(heightForWidthView = new HeightForWidthTestView(kRed, + FIXED_ASPECT_RATIO, 0.5f)) + .Add(new TestView()) + .End() + + // column 3 + .AddGroup(B_VERTICAL, 10) + .Add(new TestView()) + .Add(new TestView()) + .Add(new TestView()) + .End() + .End() + ; + + aspectRatioButton->SetValue(1); + } + + virtual void RegisterListeners() + { + aspectRatioButton->SetTarget(this); + sumButton->SetTarget(this); + productButton->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_FIXED_ASPECT_RATIO: + { + heightForWidthView->SetType(FIXED_ASPECT_RATIO, 0.5f); + break; + } + + case MSG_FIXED_SUM: + { + heightForWidthView->SetType(FIXED_SUM, 200); + break; + } + + case MSG_FIXED_PRODUCT: + { + heightForWidthView->SetType(FIXED_PRODUCT, 40000); + break; + } + + default: + BHandler::MessageReceived(message); + break; + } + } + +private: + BRadioButton* aspectRatioButton; + BRadioButton* sumButton; + BRadioButton* productButton; + HeightForWidthTestView* heightForWidthView; +}; + + +// GridLayoutHeightForWidthTest1 +struct GridLayoutHeightForWidthTest1 : public Test { + GridLayoutHeightForWidthTest1() + : Test("Grid, height for width", NULL, + "BGridLayout with height for width view.") + { + rootView = BGroupLayoutBuilder(B_HORIZONTAL, 10) + // controls + .AddGroup(B_VERTICAL, 10, 0) + .Add(aspectRatioButton = new BRadioButton("fixed aspect ratio", + new BMessage(MSG_FIXED_ASPECT_RATIO))) + .Add(sumButton = new BRadioButton("fixed sum", + new BMessage(MSG_FIXED_SUM))) + .Add(productButton = new BRadioButton("fixed product", + new BMessage(MSG_FIXED_PRODUCT))) + .AddGlue() + .End() + + // test views + .Add(BGridLayoutBuilder(10, 10) + // row 1 + .Add(new TestView(), 0, 0, 3, 1) + .Add(new TestView(), 3, 0) + .Add(new TestView(), 4, 0) + + // row 2 + .Add(new TestView(), 0, 1) + .Add(new TestView(), 1, 1) + .Add(new TestView(), 2, 1) + .Add(new TestView(), 3, 1) + .Add(new TestView(), 4, 1) + + // row 3 + .Add(new TestView(), 0, 2) + .Add(heightForWidthView = new HeightForWidthTestView(kRed, + FIXED_ASPECT_RATIO, 0.5f), 1, 2, 2, 2) + .Add(new TestView(), 3, 2) + .Add(new TestView(), 4, 2) + + // row 4 + .Add(new TestView(), 0, 3) + .Add(new TestView(), 3, 3) + .Add(new TestView(), 4, 3) + + // weights + .SetColumnWeight(0, 1) + .SetColumnWeight(1, 2) + .SetColumnWeight(2, 3) + .SetColumnWeight(3, 4) + .SetColumnWeight(4, 5) + + .SetRowWeight(0, 1) + .SetRowWeight(1, 2) + .SetRowWeight(2, 3) + .SetRowWeight(3, 4) + ) + ; + + aspectRatioButton->SetValue(1); + } + + virtual void RegisterListeners() + { + aspectRatioButton->SetTarget(this); + sumButton->SetTarget(this); + productButton->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_FIXED_ASPECT_RATIO: + { + heightForWidthView->SetType(FIXED_ASPECT_RATIO, 0.5f); + break; + } + + case MSG_FIXED_SUM: + { + heightForWidthView->SetType(FIXED_SUM, 200); + break; + } + + case MSG_FIXED_PRODUCT: + { + heightForWidthView->SetType(FIXED_PRODUCT, 40000); + break; + } + + default: + BHandler::MessageReceived(message); + break; + } + } + +private: + BRadioButton* aspectRatioButton; + BRadioButton* sumButton; + BRadioButton* productButton; + HeightForWidthTestView* heightForWidthView; +}; + + +// SplitterGroupLayoutHeightForWidthTest1 +struct SplitterGroupLayoutHeightForWidthTest1 : public Test { + SplitterGroupLayoutHeightForWidthTest1() + : Test("Group, splitters, height for width", NULL, + "Horizontal BGroupLayout with height for width view and " + "BSplitters.") + { + rootView = BGroupLayoutBuilder(B_HORIZONTAL, 10) + // controls + .AddGroup(B_VERTICAL, 10, 0) + .Add(aspectRatioButton = new BRadioButton("fixed aspect ratio", + new BMessage(MSG_FIXED_ASPECT_RATIO))) + .Add(sumButton = new BRadioButton("fixed sum", + new BMessage(MSG_FIXED_SUM))) + .Add(productButton = new BRadioButton("fixed product", + new BMessage(MSG_FIXED_PRODUCT))) + .AddGlue() + .End() + + // test views + .Add(BSplitLayoutBuilder(B_VERTICAL, 10) + // row 1 + .Add(BSplitLayoutBuilder(B_HORIZONTAL, 10) + .Add(new TestView(), 1) + .Add(new TestView(), 2) + .Add(new TestView(), 3) + , 1) + // make the row uncollapsible + .SetCollapsible(false) + + // row 2 + .Add(BSplitLayoutBuilder(B_HORIZONTAL, 10) + .Add(new TestView()) + .Add(heightForWidthView = new HeightForWidthTestView(kRed, + FIXED_ASPECT_RATIO, 0.5f)) + .Add(new TestView()) + , 2) + + // row 3 + .Add(BSplitLayoutBuilder(B_HORIZONTAL, 10) + .Add(new TestView(), 3) + .Add(new TestView(), 2) + .Add(new TestView(), 1) + , 3) + // make the row uncollapsible + .SetCollapsible(false) + ) + ; + + aspectRatioButton->SetValue(1); + } + + virtual void RegisterListeners() + { + aspectRatioButton->SetTarget(this); + sumButton->SetTarget(this); + productButton->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_FIXED_ASPECT_RATIO: + { + heightForWidthView->SetType(FIXED_ASPECT_RATIO, 0.5f); + break; + } + + case MSG_FIXED_SUM: + { + heightForWidthView->SetType(FIXED_SUM, 200); + break; + } + + case MSG_FIXED_PRODUCT: + { + heightForWidthView->SetType(FIXED_PRODUCT, 40000); + break; + } + + default: + BHandler::MessageReceived(message); + break; + } + } + +private: + BRadioButton* aspectRatioButton; + BRadioButton* sumButton; + BRadioButton* productButton; + HeightForWidthTestView* heightForWidthView; +}; + + +// SplitterGridLayoutHeightForWidthTest1 +struct SplitterGridLayoutHeightForWidthTest1 : public Test { + SplitterGridLayoutHeightForWidthTest1() + : Test("Grid, splitters, height for width", NULL, + "BGridLayout with height for width view and horizontal BSplitters.") + { + BGridLayout* layouts[3]; + + rootView = BGroupLayoutBuilder(B_HORIZONTAL, 10) + // controls + .AddGroup(B_VERTICAL, 10, 0) + .Add(aspectRatioButton = new BRadioButton("fixed aspect ratio", + new BMessage(MSG_FIXED_ASPECT_RATIO))) + .Add(sumButton = new BRadioButton("fixed sum", + new BMessage(MSG_FIXED_SUM))) + .Add(productButton = new BRadioButton("fixed product", + new BMessage(MSG_FIXED_PRODUCT))) + .AddGlue() + .End() + + // test views + .Add(BSplitLayoutBuilder(B_HORIZONTAL, 10) + // splitter element 1 + .Add(BGridLayoutBuilder(10, 10) + .GetGridLayout(&layouts[0]) + // row 1 + .Add(new TestView(), 0, 0, 3, 1) + // row 2 + .Add(new TestView(), 0, 1) + .Add(new TestView(), 1, 1) + .Add(new TestView(), 2, 1) + // row 3 + .Add(new TestView(), 0, 2) + .Add(heightForWidthView = new HeightForWidthTestView(kRed, + FIXED_ASPECT_RATIO, 0.5f), 1, 2, 2, 2) + // row 4 + .Add(new TestView(), 0, 3) + + // column weights + .SetColumnWeight(0, 1) + .SetColumnWeight(1, 2) + .SetColumnWeight(2, 3) + , 6) + + // splitter element 2 + .Add(BGridLayoutBuilder(10, 10) + .GetGridLayout(&layouts[1]) + // row 1 + .Add(new TestView(), 0, 0) + // row 2 + .Add(new TestView(), 0, 1) + // row 3 + .Add(new TestView(), 0, 2) + // row 4 + .Add(new TestView(), 0, 3) + , 4) + + // splitter element 3 + .Add(BGridLayoutBuilder(10, 10) + .GetGridLayout(&layouts[2]) + // row 1 + .Add(new TestView(), 0, 0) + // row 2 + .Add(new TestView(), 0, 1) + // row 3 + .Add(new TestView(), 0, 2) + // row 4 + .Add(new TestView(), 0, 3) + , 5) + ) + ; + + // set row weights + for (int i = 0; i < 3; i++) { + layouts[i]->SetRowWeight(0, 1); + layouts[i]->SetRowWeight(1, 2); + layouts[i]->SetRowWeight(2, 3); + layouts[i]->SetRowWeight(3, 4); + } + + // align the layouts + layouts[0]->AlignLayoutWith(layouts[1], B_VERTICAL); + layouts[0]->AlignLayoutWith(layouts[2], B_VERTICAL); + + aspectRatioButton->SetValue(1); + } + + virtual void RegisterListeners() + { + aspectRatioButton->SetTarget(this); + sumButton->SetTarget(this); + productButton->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_FIXED_ASPECT_RATIO: + { + heightForWidthView->SetType(FIXED_ASPECT_RATIO, 0.5f); + break; + } + + case MSG_FIXED_SUM: + { + heightForWidthView->SetType(FIXED_SUM, 200); + break; + } + + case MSG_FIXED_PRODUCT: + { + heightForWidthView->SetType(FIXED_PRODUCT, 40000); + break; + } + + default: + BHandler::MessageReceived(message); + break; + } + } + +private: + BRadioButton* aspectRatioButton; + BRadioButton* sumButton; + BRadioButton* productButton; + HeightForWidthTestView* heightForWidthView; +}; + + +// LabelTest1 +struct LabelTest1 : public Test { + LabelTest1() + : Test("BTextControl, BMenuField, grid", NULL, + "Aligning BTextControl/BMenuField labels using a 2 column " + "BGridLayout.") + { + textControl1 = new BTextControl("Label", NULL, NULL); + textControl2 = new BTextControl("Long Label", NULL, NULL); + textControl3 = new BTextControl("Very Long Label", NULL, NULL); + + menuField1 = new BMenuField("Label", new BMenu("Options"), NULL); + menuField2 = new BMenuField("Long Label", + new BMenu("More Options"), NULL); + menuField3 = new BMenuField("Very Long Label", + new BMenu("Obscure Options"), NULL); + + rootView = BGroupLayoutBuilder(B_VERTICAL, 10) + // controls + .AddGroup(B_HORIZONTAL, 10) + .Add(changeLabelsButton = new BButton("Random Labels", + new BMessage(MSG_TOGGLE_1))) + .AddGlue() + .End() + + .AddGlue() + + // test views + .Add(BGridLayoutBuilder(10, 10) + // padding + .Add(BSpaceLayoutItem::CreateGlue(), 0, 0) + .Add(BSpaceLayoutItem::CreateGlue(), 1, 0) + + // row 1 + .Add(textControl1->CreateLabelLayoutItem(), 0, 1) + .Add(textControl1->CreateTextViewLayoutItem(), 1, 1) + + // row 2 + .Add(textControl2->CreateLabelLayoutItem(), 0, 2) + .Add(textControl2->CreateTextViewLayoutItem(), 1, 2) + + // row 3 + .Add(textControl3->CreateLabelLayoutItem(), 0, 3) + .Add(textControl3->CreateTextViewLayoutItem(), 1, 3) + + // row 4 + .Add(menuField1->CreateLabelLayoutItem(), 0, 4) + .Add(menuField1->CreateMenuBarLayoutItem(), 1, 4) + + // row 5 + .Add(menuField2->CreateLabelLayoutItem(), 0, 5) + .Add(menuField2->CreateMenuBarLayoutItem(), 1, 5) + + // row 6 + .Add(menuField3->CreateLabelLayoutItem(), 0, 6) + .Add(menuField3->CreateMenuBarLayoutItem(), 1, 6) + + // padding + .Add(BSpaceLayoutItem::CreateGlue(), 0, 7) + .Add(BSpaceLayoutItem::CreateGlue(), 1, 7) + ) + + .AddGlue() + ; + } + + virtual void RegisterListeners() + { + changeLabelsButton->SetTarget(this); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_TOGGLE_1: + { + BTextControl* textControls[] = { + textControl1, textControl2, textControl3 + }; + + BMenuField* menuFields[] = { + menuField1, menuField2, menuField3 + }; + + for (int i = 0; i < 3; i++) { + BTextControl* textControl = textControls[i]; + BMenuField* menuField = menuFields[i]; + + textControl->SetLabel(_RandomLabel().String()); + menuField->SetLabel(_RandomLabel().String()); + } + } + + default: + BHandler::MessageReceived(message); + break; + } + } + + BString _RandomLabel() const + { + const char* digits = "0123456789"; + + int length = rand() % 20; + BString label("Random "); + for (int k = 0; k < length; k++) + label.Append(digits[k % 10], 1); + + return label; + } + +private: + BButton* changeLabelsButton; + BTextControl* textControl1; + BTextControl* textControl2; + BTextControl* textControl3; + BMenuField* menuField1; + BMenuField* menuField2; + BMenuField* menuField3; +}; + + +// TestWindow +class TestWindow : public BWindow { +public: + TestWindow() + : BWindow(BRect(100, 100, 700, 500), "LayoutTest1", + B_TITLED_WINDOW, + B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE + | B_AUTO_UPDATE_SIZE_LIMITS) + { + SetLayout(new BGroupLayout(B_HORIZONTAL)); + + BGroupView* rootView = new BGroupView(B_HORIZONTAL, 10); + BGroupLayout* layout = rootView->GroupLayout(); + AddChild(rootView); + layout->SetInsets(5, 5, 5, 5); + + fTestList = new BListView(BRect(0, 0, 10, 10), "test list", +B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL); + BView* scrollView = new BScrollView("test scroll view", fTestList); + scrollView->SetExplicitMaxSize(BSize(190, B_SIZE_UNLIMITED)); + layout->AddView(scrollView); + + fTestCardLayout = new BCardLayout(); + BView* cardView = new BView("card view", 0, fTestCardLayout); + layout->AddView(cardView); + + // add the tests + _AddTest(new GroupLayoutTest1()); + _AddTest(new GroupAlignedLayoutTest1()); + _AddTest(new GridLayoutTest1()); + _AddTest(new SplitterGroupLayoutTest1()); + _AddTest(new SplitterGroupLayoutTest2()); + _AddTest(new SplitterGridLayoutTest1()); + _AddTest(new SplitterGridLayoutTest2()); + _AddTest(new GroupLayoutHeightForWidthTestHorizontal1()); + _AddTest(new GroupLayoutHeightForWidthTestVertical1()); + _AddTest(new GridLayoutHeightForWidthTest1()); + _AddTest(new SplitterGroupLayoutHeightForWidthTest1()); + _AddTest(new SplitterGridLayoutHeightForWidthTest1()); + _AddTest(new LabelTest1()); + + fTestList->SetSelectionMessage(new BMessage(MSG_TEST_SELECTED)); +_DumpViewHierarchy(rootView); + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + case MSG_TEST_SELECTED: + fTestCardLayout->SetVisibleItem(fTestList->CurrentSelection()); + break; + default: + BWindow::MessageReceived(message); + break; + } + } + +private: + void _AddTest(Test* test) { + fTestList->AddItem(new BStringItem(test->name.String())); + + BGroupView* containerView = new BGroupView(B_VERTICAL); + + // description +// BStringView* descriptionView = new BStringView(test->description.String()); + BStringView* descriptionView = new BStringView(BRect(0, 0, 0, 0), + "test description", test->description.String()); + + descriptionView->SetExplicitMinSize(BSize(0, B_SIZE_UNSET)); + containerView->AddChild(descriptionView); + + // spacing/glue + containerView->GroupLayout()->AddItem( + BSpaceLayoutItem::CreateVerticalStrut(10), 0); + containerView->GroupLayout()->AddItem( + BSpaceLayoutItem::CreateGlue(), 0); + + // the test view: wrap it, so we can have unlimited size + BGroupView* wrapperView = new BGroupView(B_HORIZONTAL); + containerView->AddChild(wrapperView); + wrapperView->AddChild(test->rootView); + + // glue + containerView->GroupLayout()->AddItem( + BSpaceLayoutItem::CreateGlue(), 0); + + wrapperView->SetExplicitMaxSize( + BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); + containerView->SetExplicitMaxSize( + BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); + + fTestCardLayout->AddView(containerView); + + AddHandler(test); + test->RegisterListeners(); + } + + void _DumpViewHierarchy(BView* view, int32 indent = 0) + { + for (int32 i = 0; i < indent; i++) + printf(" "); + printf("view: %p", view); + for (int32 i = 0; i < 15 - indent; i++) + printf(" "); + printf("(%s)\n", typeid(*view).name()); + + int32 count = view->CountChildren(); + for (int32 i = 0; i < count; i++) + _DumpViewHierarchy(view->ChildAt(i), indent + 1); + } + +private: + BListView* fTestList; + BCardLayout* fTestCardLayout; +}; + + +int +main() +{ + BApplication app("application/x-vnd.haiku.layout-test1"); + + BWindow* window = new TestWindow; + window->Show(); + + app.Run(); + + return 0; +}