FindObjects

Revision as of 21:14, 12 October 2019 by Max (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

new to Analytica 5.0

FindObjects is a powerful function that searches a model to find objects that match specified criteria. For example, FindObjects('$', Units) returns a set of variables whose 'Units' attribute contains '$'. Among the vast number of criteria you can specify are the search text, the attribute(s) to search and class(s) of object to search (or exclude), what values it contains, which modules to search, variables that influence or are influenced by a variable, or whether an object has user inputs or outputs. For more complex searches, you can combine its results using set operations.

FindObjects() returns a set

The result from FindObjects is a Set -- i.e. a reference to a list of handles to the objects found. So if you want the list of objects, you should preface the function name with the de-reference operator (#), e.g.:

#FindObjects("Cost", Identifier) → [Cost_of_gasoline, Cost_of_diesel, Levelized_cost]

This example returns a list of variables whose identifiers contain "Cost".

Since FindObjects() returns a set, you can use it directly in functions like SetUnion, SetDifference and SetIntersection to combine search criteria -- for example,

#SetUnion([FindObjects('$', Units), FindObjects('₤', Units)])

returns a list of all objects whose Units contain '$' or '₤'.

The function fully supports Intelligent Arrays, meaning it works if any parameter is an array. In that case the results will be an array of sets of search result. Each cell of the array will be a reference to a list that is the result of a distinct search. You cannot dereference the result when the result might be an array of searches, so you shouldn't apply the # operator, unless you know that it returns only a single set.

FindObjects(regExp, attribute..., excludeAttribute..., class..., excludeClass..., value, influences..., influencedBy..., inclusive, within..., withinAny..., contains..., containsAny..., hasUserInput, hasUserOutput, hasInput, hasOutput, isLiteral, outputOf..., inputOf..., caseSensitive)

FindObjects has a huge number of parameters, but all are optional. You should specify at least one parameter unless you want the set of all user-defined objects. It's simplest to use name-based calling syntax for all parameters except optionally the one or two, «regExp» and «attribute»,

Many parameters can be repeated (denoted by ... in the parameter list). For example, you can specify a list of classes and attributes. It returns the union of all objects that match. So,FindObjects('Possible', attribute: Title, Description, Class: Decision, Chance) returns any Decision and Chance objects that have a Title or Description that contains 'Possible'.

A variable using FindObjects() does not update automatically when relevant attributes change or objects are created or deleted. (Analytica's flow architecture (automatic consistency maintenance) propagates changes only from Definitions and Values to other Variables that depend on them, not from other Attributes.) That means you must explicitly cause FindObjects() to recompute if you want to reflect any changes to the objects it may search.

regExp

This first parameters specifies text to search for. It returns a list of objects containing any attribute (or specified attribute) that contains this text value. The match is case insensitive by default. This parameter may also be a regular expression (hence its name) containing wild-cards, special characters, and more for more complex matching.

attribute

By default, FindObjects searches every user-defined attribute of each object. Or you can use this parameters to specify one or more specific attributes in which to match the «searchText» or «value». The search result doesn't include information about which attribute matched.

caseSensitive

Set to True (1) or False (0) to control whether «regExp» is case-sensitive. By default, it is case-insensitive (False).

excludeAttribute

One or more attributes to be excluded from the match.

class

Specify one or more classes of object to search, such as Variable, Objective, Function, Module, or SysFunction. It returns objects of only the specified class(es). If not specified, it searches all user-defined object classes, but not classes of built-in objects, like SysFunction and SysVar. If you specify Any, it searches all object classes, both user and built-in.

excludeClass

One of more object classes to exclude.

value

An atomic value to find. It returns any computed variable that has a matching value as its atomic value or as a cell in its array or table value (deterministic Value or Probvalue). You can search for NaN or Null. It will not find a match unless the value has been computed.

outputOf

Find objects, usually, Variables, Functions, and Buttons, that use the object(s) listed in «outputOf». Use a handle to each object, or its identifier as a text value. Don't just use the variable's identifier directly, because it will try to evaluate it -- e.g.

FindObjects(outputOf: Handle(X), 'Y') not: FindObjects(outputOf: X, Y)

It finds Variables and Functions that mention the object(s) X in their Definitions. Unlike the simple attribute access Outputs OF X, it also finds any Button that uses X in its Onclick attribute or any variable that uses X in its OnChange or Check attribute. It even finds Objects that use a system function or system variable. In these ways, it is more general that the Outputs attribute.

inputOf

Finds objects that are used by the objects listed in «inputOf». As with «outputOf», you should provide a handle to each variable or other object (or its identifier as text) -- and "uses" covers OnClick, OnChange, and Check attributes.

influencedBy

Finds all downstream variables, functions and buttons that are influenced by the specified object(s), directly (as in their OutputOf, above), or indirectly, via other variables or functions. As with «outputOf», you should provide a handle to each variable or other object (or its identifier as text) and "influence" includes effects via OnClick, OnChange, and Check, as well as Definition attributes.

influences

Finds all upstream variables, functions and buttons that influence the specified object(s), directly (as in their InputsOf, above), or indirectly, via other variables or functions. As with «outputOf», you should provide a handle to each variable or other object (or its identifier as text) and "influence" includes effects via OnClick, OnChange, and Check, as well as Definition attributes.

inclusive

Boolean. By default FindObjects(influences: x) does not include x itself. When «inclusive» is true, it includesx in its result. This also applies to parameters «influencedBy», «within», «withinAny», «contains» and «containsAny».

within

When you specify one or more modules, it searches only objects within those modules (and their submodules).

withinAny

Same as «within», but it also includes objects that are inside the specified module(s) only as a result of a module alias being inside the module.

contains

Searches among modules that contain any of the objects specified in «contains».

containsAny

Same as «contains», except that it also includes modules that contain an alias that contains the indicates object(s).

hasUserInput

When true, it returns only objects that have a user input node. When false, it returns only objects that have no user input.

hasUserOutput

When true, it returns only objects that have a user output node. When false, it returns only objects that have no user output.

hasInput

When true, it returns only objects that depend on at least one other variable. When false, returns objects that have no Inputs.

hasOutput

When true, it returns objects that have at least one Output variable or function. When false, returns only objects with no Outputs.

isLiteral

When true, it returns objects that contain only literals (explicit numbers, text, etc.) or are defined as a table with only literals in the cells, but contain no expressions, and refer to no variables other than the Index variables for the table dimensions.

Examples

Objects matching specific text

Find all objects having the text "Bacteria" anywhere within any text attribute (including Identifier, Units, Title, Description, Definition, and User-defined attributes). The match is case insensitive.

#FindObjects("Bacteria")

Find all objects with an identifier that starts with the prefix "Hydro_". The ^ character is the regular expression code for beginning-of-text, which prevents a match to "Cost_of_hydro_power".

#FindObjects("^Hydro_", Identifier)

You can equivalently quote the attribute name, or compute it:

Var att := "Identifier" Do #FindObjects("^Hydro_", att)

Find objects that have both the words "plant" and "animal" within its textual attributes. An object matches if each word appears in a different attribute, for example, "plant" in the Title, and "animal" in the Description. Notice that when using a Set Functions to combine criteria, you don't de-reference the result of FindObjects before passing it to the set function.

#SetUnion([FindObjects("plant"), FindObjects("animal")])

Find objects that have Units of "mph" or "miles per hour", which do not have a divide operator (/) in the Definition.

#SetDifference(FindObjects("(mph)|(miles per hour)", Units), FindObjects("/", Definition))

Find objects in which "lumina" appears in a textual attribute without being capitalized (it is a proper noun, so should be capitalized). It uses the regular expression control '\b to match word-boundaries, so that words like "illumination" that contain the character sequence inside the word is not matched. The search is case-sensitive so that properly capitalized instances of "Lumina" are not included.

#FindObjects("\blumina\b", caseSensitive: True)

Find objects having the text "Power" in either the Identifier on Title. This uses named-calling syntax, but the positional syntax (with three parameters) would also work.

#FindObjects(regExp: "Power", attribute: Identifier, Title)

Find objects having the text "Dynamic" in any textual attribute other than the Definition.

#FindObjects("Dynamic", excludeAttribute]: Definition)

The variable Words contains a vector of words, indexed by the index Word_idx. The variable Attr_to_search contains a list of attribute names, computed using Subset. Find objects having any of the indicated words in any of the indicated attributes. Only full words are matched (by use of the regular expression '\b'), but the match is case insensitive. The full list of attributes from <code>Attr_to_search is passed to the «attribute» parameter by using Repeated parameter forwarding (the ...).

#SetUnion(FindObjects('\b' & Words & '\b', attribute: ...Attr_to_search), Word_idx)

Building on the previous example, but passing Attr_to_search without Repeated parameter forwarding, we end up with a list of results, one for each attribute, since array-abstraction kicks in on the list of attributes. So for example, if Attr_to_search has the value ["Title", "Description", "Help"], the result is an array of three elements, the first having objects in whose Title attribute contains one of the words, the second cell has objects whose Description contains one of the words, etc. An important point here is that we cannot de-reference the result, because the result is collection of sets. Dereferencing would attempt to combine

SetUnion(FindObjects(Words, attribute: Attr_to_search), Word_idx)

To find all objects with no Definition, you will need to use the «value» parameter.

FindObjects(value: Null, attribute: Definition)

Objects of a certain type

Any of these three variations can be used to find all User-defined functions.

#FindObjects(class: Function)
#FindObjects(class: "Function")
#FindObjectsclass: Handle(Function))

Find all non-linked libraries.

#FindObjects(class: "Library")

Find all libraries, whether linked or non-linked.

#FindObjects(class: Library, LinkLibrary)

Find all modules or libraries. In this example, ModuleTypes is a separate constant node in your model. Notice that Repeated Parameter Forwarding is used here to pass the full list of modules as a single call, without array-iterating over them.

Constant ModuleTypes := ["Module", "LinkModule", "Model", "Library", "LinkLibrary", "Form"]
#FindObjects(class: ...ModuleTypes)

You could also allow array-abstraction to iterate, returning the matches to each module type, and then combine the results using SetUnion.

#SetUnion(FindObjects(class: ModuleTypes), ModuleTypes)

Find all built-in system functions or system variables that contain the characters "sample" in the Identifier. Note that built-in objects are normally excluded from searches unless you specify the class explicitly.

#FindObjects("sample", Identifier, class: SysFunction, SysVar)

Find all non-module objects in your model. This uses the ModuleTypes from a previous example a few lines above.

#FindObjects(excludeClass: ...ModuleTypes)

Objects with a certain value

Find all variables having a result value of 1.2 in any cell of the computed result. The search examines all mid- and sample- values that have been previously computed, but does not cause any variable to be computed in order to access its result. Any object having 1.2 in any cell of its result is returned.

#FindObjects(value: 1.2)

NaNs in the result

Find all variables having a NaN in any cell of the computed result. Take note that this only searches results that have been previously computed. It searches both mid-value and sample-value results. It is possible you might see a NaN a statistical view, such as for the standard deviation when there is fewer that 2 numbers in the sample, even though the sample contains no NaNs. In such a case, the object is not included, since the NaN must appear in the sample itself.

#FindObjects(value: NaN)

When searching for the origin of NaNs in your model, it can be useful to limit the search to variables upstream from the variable you are looking at with has NaNs in it. Suppose that variable is X. You must use the Handle function when passing X, otherwise you'd be passing the result of X to the «influences» parameter.

#FindObjects(value: NaN, influences: Handle(X))

Finding upstream or downstream variables

Find all the objects (variables and user-defined functions) that influence Revenue directly or indirectly. You must use the Handle function to specify the variable (or you can specify its textual name), otherwise it will evaluate Revenue and try to use its result (which would cause an error, since it doesn't evaluate to a handle). The result does not include X itself, unless it does depend on itself through a Dynamic or Iterate.

#FindObjects(influences: Handle(Revenue))

Find all objects that are upstream of variable Y, but downstream from variable X.

#FindObjects(influences: Handle(Y), influencedBy: Handle(X))

Find the objects that depend on X and influence Y, and include X and Y in the result.

#FindObjects(influences: Handle(Y), influencedBy: Handle(X), inclusive: true)

Find all variables in the same Dynamic loop at X. #FindObjects(influences: Handle(X), influencedBy: Handle(X))

Finding objects that use a function or variable

Find all variables that use the function DbQuery:

#FindObjects(outputOf: "DbQuery")

The following also finds all variables and functions that use the function DbQuery, but the variable containing this call to FindObjects will also be included in the result.

FindObjects(outputOf: Handle(DbQuery))

The search FindObjects("DbQuery") would also find these variables, but it would also find objects where the text "DbQuery" appears in comments, quotes, or in textual attributes like Description. The «outputOf» search criteria limits the results to cases where an expression makes use of the indicated object.

Find all variables that are immediate children of Gas_price (e.g., that reference Gas_Price in their definition).

FindObjects(outputOf: Handle(Gas_price))

Find all variables in the same dynamic loop as X which have a Dynamic definition.

FindObjects(influences: X, influencedBy: X, inclusive: true, outputOf: Handle(Dynamic))

The inverse of «outputOf» is «inputOf». Find all immediate parents of X.

FindObjects(inputOf: X)

Find all the system functions or system variables that are used by the variable X.

FindObjects(inputOf: X, class: SysVar, SysFunction)

Finding objects by locations within module hierarchy

Find all the non-module objects inside the module Sensitivity_analysis. This uses the constant ModuleTypes that was defined earlier in the examples. This result includes all objects that are inside any sub-module of Sensitivity_analysis, at any depth.

#FindObjects(within: Handle(Sensitivity_analysis), excludeClass: ...ModuleTypes)

Suppose there is a module named Power_generation which is not inside the Sensitivity_analysis module, but an alias of the Power_generation model has been created and placed with the Sensitivity_analysis module. The preceding search using «within» does not include the objects inside the alias module. Find all non-module objects inside Sensitivity_analysis, or any of its submodules or alias submodules, at any depth.

#FindObjects(withinAny: Handle(Sensitivity_analysis), excludeClass: ...ModuleTypes)

Find all the parent and ancestor modules (not following aliased modules) of x.

#FindObjects(contains: Handle(x))

Find all parent and ancestor modules, including module aliases and their parents, of x.

#FindObjects(containsAny: Handle(x))

Find the common modules of X and Y. In other words, those modules that have both X and Y somewhere within their module hierarchy. X and Y may be in different modules.

#FindObjects(contains: X, Y)

Finding model inputs or outputs

Which variable do you consider to be model inputs? The most obvious would be those variables having user input nodes. You can find these using.

#FindObjects(hasUserInput: true)

You might consider an input to be a node with no parents.

#FindObjects(hasInput: false)

but Tables have parents (the indexes), even if all the cells are numbers. So you might want the objects that have only literals in their definitions (text, numbers, null), including tables. This would exclude a table having expressions in their definition or in their table cells.

#FindObjects(isLiteral: true)

Or maybe in addition to these criteria, a variable is only an input when it is actually used by another object.

#FindObjects(isLiteral: true, hasOutput: true)

In a symmetrical fashion, an output might be a variable that has a user output node.

#FindObjects(hasUserOutput: false)

or that has no children of its own.

#FindObjects(hasOutput: false)

Find the inputs that influence the result of Y, using a concept that an input is either an object defined as a literal or table of literals, or is a variable with a user input node.

#SetUnion(FindObjects(hasUserInput: true, influences: Handle(Y)), FindObjects(isLiteral: true, influences: Handle(Y))

FoundSet to tag nodes on a Diagram

You can use the system variable Sys_FoundSet to identify results from FindObjects (or any set of objects) by tagging their nodes with a magnifying glass icon in their Diagrams, and in the Outline view. You can also step through the variable using "Find Next" option from the Object menu, or press ctrl+G, to step through the variables. This can be very helpful while debugging to trace how one variable influences another across several diagrams, for example:

The Found Set depicts all variables on the path(s) from Demand_growth_rate to Dollar_sales_by_product using magnifying glass icons.

Sys_FoundSet normally contains a list of the objects found from the last time you used the Find dialog. You can also assign a result from FindObjects to Sys_FoundSet in a Button OnClick attribute. For example,

Sys_FoundSet := FindObjects(influencedBy: "Demand_growth_rate", influences: "Dollar_sales_by_prod", inclusive: true);

To show the magnifying glass tags, you must also set the system variable DepictFoundSetOnUI to 1:

DepictFoundSetOnUI := 1

(If you make these assignments in a Typescript Window, you must enclose each assignment in parentheses, in line with Typescript syntax.)

History

Introduced in Analytica 5.0.

See Also

Comments


Marksmith

34 months ago
Score 0
Neat. I like how this function makes capturing a list of objects --in a module, ones with characteristics, ones with inputs, ones with outputs, ...-- so much smoother than finding text in (textual) Attributes of objects to construct lists of objects for Sensitivity Analyses, searching for nodes in a model with complicated hierarchy and exploring inputs.

You are not allowed to post comments.