Tm1 Advanced Rules Guide
Tm1 Advanced Rules Guide
Applix, Inc. 2003. All Rights Reserved. TM1 Rules Guide Version 8.2.1 Part # 001-RULES-01-E-821 Applix, Inc. prepared the information contained in this document for use by Applix personnel, customers, and prospects. Applix reserves the right to change the information in this document without prior notice. The contents herein should not be construed as a representation or warranty by Applix. Applix assumes no responsibility for any errors that may appear in this document. The software described in this document is furnished under a license and may be used only in accordance with the terms of such license. Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Microsoft, Microsoft SQL Server, Microsoft Outlook, MS-DOS, Windows, Windows NT and Windows Internet Explorer are registered trademarks of Microsoft Corporation. ORACLE 8 is a trademark of Oracle Corporation. SYBASE is a registered trademark of SYBASE, Inc. Fulcrum is a registered trademark, and Ful/Text, Intuitive Searching, SearchBuilder, SearchServer, SearchSQL and Surfboard are trademarks of Hummingbird Ltd. Portions of the Applix iEnterprise product are protected under copyrights of Hummingbird Ltd. Crystal Reports for Windows is a trademark of Crystal Computer Services Incorporated. Informix is a registered trademark of Informix Software, Inc. Netscape Communicator is also a trademark of Netscape Communications Corporation, which may be registered in other countries. Novell is a registered trademark of Novell, Inc. Win BEEP 32 is a trademark of Integra Technology International, Inc. and/or IKON Office Solutions. Portions of the Applix iEnterprise product are used under license from ChartWorks Inc. All other brand and product names are trademarks or registered trademarks of their respective owners. NetCharts software is covered by the following copyright: Copyright 1996 Jef Poskanzer. All rights reserved. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure by the U.S. Government is subject to restrictions as set forth in subparagraphs (c) (1) (ii) of SFARS 252.277-7013, or in FAR 52.227-19, as applicable. Print Date: 11/2003
Table of Contents
Preface
Business Performance Management with Applix TM1 . . . . . . . . . . . ix Book Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix Audience for this Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x Conventions Used in This Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x How This Manual Is Organized. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi The Applix TM1 Documentation Set. . . . . . . . . . . . . . . . . . . . . . . . . . .xii
Chapter 1
Index
Chapter 2
A Simple Rule
Setting Your Local Data Directory for Use with this Guide . . . . . . 2-2 Purchase Cost Calculation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-3 Writing the Rule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-6 Opening the Rules Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-7 Creating the Rule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-8 Compiling the Rule. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-14 Viewing the Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-15
Chapter 3
Exchange Rates
Exchange Rate Calculation within a Cube . . . . . . . . . . . . . . . . . . . . . 3-2 Exchange Rate as an Attribute of the Market Dimension . . . . . . . . 3-3 Exchange Rate Tracked by Market . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-3 The DB Formula . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-4 The Rule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-4 How a DB Formula Works . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-5 Writing the Exchange Rate Rule Statement . . . . . . . . . . . . . . . . . 3-8 Exchange Rate Calculation Using a Lookup Cube . . . . . . . . . . . . . 3-11 Using a Nested DB Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-13 Writing Nested DBs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-18 Other Lookup Cube Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-24 Calculating Purchase Cost - USD. . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-25
ii
Index
Chapter 4
Chapter 5
Chapter 6
Chapter 7
Index
A Second Way: Using the DIMNM - DIMIX Idiom. . . . . . . . . . . 7-7 A Third Approach: Using DIMIX for Comparisons . . . . . . . . . 7-10 Best Solution: Using a String Cube to Store a Variable . . . . . . . 7-12 Feeding Time Series . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-19 Hard-Coded Feeders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-19 Deliberate Overfeeding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-20 Using DNEXT for Feeding. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-21
Chapter 8
Fixed Allocations
Calculating the Quantities of Fish Requred by Fishcake Type . . . . 8-2 Creating the Calulation Statement for Qty Required - Kgs . . . . 8-4 Feeding Qty Required - Kgs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-6 Creating the Feeder Statement for Qty Required - Kgs . . . . . . . 8-6
Chapter 9
iv
Index
Chapter 10
Table of Contents
Index
DATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-13 DATES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-14 DAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-15 DAYNO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-16 DB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-17 DELET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-18 DIMIX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-19 DIMNM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-20 DIMSIZ. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-21 DNLEV. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-22 DTYPE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-23 ELCOMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-24 ELCOMPN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-25 ELISANC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-26 ELISCOMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-27 ELISPAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-29 ELLEV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-31 ELPAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-32 ELPARN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-33 ELWEIGHT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-34 EXP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-35 FILL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-36 FV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-37 IF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-38
vi
Index
INSRT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-39 INT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-40 ISLEAF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-41 ISUND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-42 LN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-43 LOG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-44 LONG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-45 LOWER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-46 MAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-47 MIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-48 MOD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-49 MONTH. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-50 NOW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-51 NUMBR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-52 PAYMT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-53 PV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-54 RAND. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-55 ROUND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-56 ROUNDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-57 SCAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-58 SIGN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-59 SIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-60 SQRT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-61 STET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-62
Table of Contents
vii
Index
STR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-63 SUBST. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-64 TABDIM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-65 TAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-66 TIME. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-67 TIMST. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-68 TIMVL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-71 TODAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-73 TRIM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-74 UNDEF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-75 UNDEFVALS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-76 UPPER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-77 YEAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-78
Index
viii
Preface
Business Performance Management with Applix TM1
Business Performance Management is the continuous management and monitoring of financial, operational, customer and organizational performance across the enterprise. Business Performance Management solutions have the following capabilities to facilitate the proactive steering of business direction: Wide deployment Collaborative decision making Continuous and real time review and refinement Monitoring of Key Performance Indicators TM1 integrates business planning, performance measurement and operational data to enable companies to optimize business effectiveness and customer interaction regardless of geography or structure. TM1 provides immediate visibility into data, accountability within a collaborative process and a consistent view of information. It allows managers to quickly stabilize operational fluctuations and take advantage of new opportunities.
Book Description
The TM1 Rules Guide describes how to use TM1 rules to build an application that transforms business data in ways that provide insight not readily
Preface iii
Table of Contents
Index
accomplished with raw data. This guide follows the transformation of data for a fictional company called Fishcakes International, which purchases different types of fish from markets around the world and uses that fish to make fishcakes. The company uses TM1 rules to calculate purchase costs, exchange rates, inventory levels, inventory depletion, and final production costs.
Helvetica Bold
Italics
iv
Table of Contents
Index
Convention Whenever you see a reference to a menu option, the option is identified using the following notation: Menu Name Option Name For example, Choose Forms More.
Preface
Table of Contents
Index
Chapter 5 6 7 8 9
Description Improving Performance with Feeders describes the use of feeders, a performance-enhancing feature of TM1 rules. Moving Data and Changing Levels describes how to use TM1 rules to move data between different levels of consolidation. Rules for Time-Based Calcluations describes how to use several TM1 rules functions to perform time-based calculations. Fixed Allocations uses rules to allocate purchase costs to individual fishcake types within the Fishcakes International model. Stocks and Flows shows how TM1 rules can be used to track inventory levels by following incoming purchases and calculating inventory depletion. Calculating Total Product Costs completes the Fishcakes International model by caclulating daily production costs with TM1 rules.
10
Appendix A Rules Functions is a reference guide to all the functions that can be used in TM1 rules.
1-1
Table of Contents
Index
1-2
Table of Contents
Index
Compiled rules are stored in files called cube_name.rux. When a cube for which you have defined rules is loaded into memory, TM1 searches for the cubes .rux file in the data directory containing the cube. When you create a rule, TM1 also generates a file called cube_name.blb, which contains format information for the Rules Editor. If you want to edit a .rux file in another text editor, you should delete the corresponding .blb file. If you do not, there will be a discrepancy between the contents of the .rux file and the display of the Rules Editor, as the display of the Rules Editor is determined by the .blb file.
1-3
Table of Contents
Index
There are several ways to access the Rules Editor. When first creating a rule for a cube, right-click the cube in the Server Explorer and select Create Rule to open the Rules Editor. When a rule exists for a cube, right-click the cube in the Server Explorer and select Edit Rule. When a rule exists for a cube, you can also double-click the rule to open it for editing.
1-4
Table of Contents
Index
1-5
Table of Contents
Index
from location to location, in which case you would specify different areas (and accompanying formulas) for each location. The following are all valid area definitions for the Purchase cube in the sample database that accompanies this guide. Area Definition [] ['Purchase Cost - LC'] ['Jan-01', 'Price/Kg - LC'] Scope All cells in the cube. All cells identified by the Purchase Cost - LC element. All cells identified by both the Jan - 01and Price/Kg - LC elements. This area definition might reflect special discount pricing available on New Years Day only All cells identified by the Salmon, Helsinki, and Jan-13 elements.
Regardless of the scope of an area, you must follow these conventions when writing an area definition: Enclose each element in single quotes. Use commas to separate each element. Enclose the entire area definition in square brackets. Using Subsets in an Area Definition You can use a subset in place of a single element in an area definition by enclosing all subset members in curly brackets.
1-6
Table of Contents
Index
For example, the following area definition applies a calculation formula to all cube cells identified by the element Trout and any of the elements Karachi, Boston, or Helsinki: [Trout, {'Karachi', 'Boston', 'Helsinki'}] = Using Special Characters and Non-Unique Element Names in an Area Definition You can use the syntax 'dimensionname':'elementname' in an area definition to specify elements that are not unique to a single dimension or for dimension names that contain special characters. For example, the area ['Units', 'Mar', 'Region':'North America'] lets you write a statement when the element North America is not unique to the Region dimension. Similarly, the area ['}Groups':'ADMIN'] allows you to write a statement for the }Groups dimension, which contains the } special character. Using the CONTINUE Function to Apply Multiple Formulas to the Same Area When included as part of a calculation statement formula, the CONTINUE function allows a subsequent statement with the same area definition to be executed. (Normally, TM1 only executes the first calculation statement encountered for a given area.) For example, if a rule contains the following two statements
1-7
Table of Contents
Index
['Jan']= if(!region @= 'Argentina',10,CONTINUE); ['Jan']=20; all cells identified by Jan and Argentina are assigned a value of 10. Cells identified by Jan and any other Region element are assigned a value of 20. Leaf/Consolidation/String Qualifier In TM1, there is a distinction between leaf or numeric cells, whose coordinates are all leaf/numeric (N:) elements in their respective dimensions; consolidated cells, which have at least one consolidated (C:) element among their coordinates; and string cells, which have at least one string (S:) element among their coordinates. The leaf/consolidation/string qualifier indicates whether, for a defined area, a statement applies only to leaf cells, only to consolidated cells, only to string cells, or (in the absence of a qualifier) to all cells. If the qualifier is N:, the statement applies to leaf cells only. If the qualifier is C:, the statement applies only to consolidated cells. If the qualifier is S:, the statement applies to string cells only. If there is no qualifier, the calculation statement applies to all cells in the defined area. IMPORTANT: When a qualifier is used, it must immediately precede the formula component of a statement. A qualifier placed at the start of a statement will cause a syntax error. Restricting a Statement to N: Level Cells Use the following syntax to write a rules statement that applies only to N: level cells in an area: [Area] = N:[Formula]; For example:
1-8 TM1 Rules Guide
Table of Contents
Index
['Sales'] = N:['Price']*['Units']\1000; Restricting a Statement to C: Level Cells Use the following syntax to write a rules statement that applies only to C: level cells in an area. [Area] = C:[Formula]; For example: ['Price'] = C:['Sales']\['Units']*1000; Calculating Values Differently at the N: and C: Levels When a specific area of a cube is calculated differently at the N: and C: levels, you can use the following syntax: [Area] = N:[Formula A]; C:[Formula B]; For example: ['Price'] = N:DB('PriceCube', !Actvsbud, !Region, !Model, !Month); C:['Sales']\['Units']*1000; Formula The formula portion of a calculation statement tells TM1 how to calculate a value for the defined area. Formula expressions can include: Numeric constants Arithmetic operators and parentheses Rules functions see Appendix A to this book for complete descriptions of these functions. Conditional logic
Introduction to TM1 Rules 1-9
Table of Contents
Index
Cube references Numeric Constants The simplest components of a calculation formula are numeric constants. A numeric constant consists of numerals, an optional leading sign, and an optional decimal point. Examples of valid numeric constants are: 5.0, 6, -5. Examples of invalid numeric constants are: 1-, 1A, 3..4. Numeric constants have a maximum length of 20 characters. You can use scientific notation to enter a numeric constant. The following rules statement uses a numeric constant to assign the value 200 to all cells in a cube: [ ] = 200; Arithmetic Operators You can combine numeric constants using the following arithmetic operators. Operator + (plus sign) - (minus sign) * (asterisk) / (forward slash) Meaning Addition Subtraction Multiplication Division
1-10
Table of Contents
Index
Meaning Same as / (forward slash), but returns zero when you divide by zero, rather than an undefined value. Exponentiation
TM1 evaluates arithmetic operators in the following order: 1. Exponentiation 2. Multiplication 3. Division 4. Addition 5. Subtraction Use parentheses to force a different order of evaluation. The expression 2*3+4 produces the same result as (2*3)+4 because multiplication takes precedence over addition. To perform the addition first, rewrite the formula as 2*(3+4). This changes the result from 10 to 14. Using Conditional Logic Use the IF function to include conditional logic in calculation statements. The general format is: IF(Test, Value1, Value2) The IF function returns one of two values depending on the result of a logical test. When the expression Test is true, the IF function returns Value1; when false, it returns Value2. The data type returned by an IF function is determined
Introduction to TM1 Rules 1-11
Table of Contents
Index
by the data types of Value1 and Value2. Value1 and Value2 must be the same data type, either string or numeric. An IF function where Value1 is a string and Value2 is a number yields an error statement. You can also nest IF statements: IF(Test1, Value1, IF (Test2, Value2, Value3)) The following table shows two IF examples. Expression IF (7>6,1,0) IF (7>6, 'True', 'False') Using Comparison Operators You can use the following comparison operators to compare values in the formula portion of a calculation statement. Operator > < >= <= Meaning Greater than Less than Greater than or equal to Less than or equal to Result yields 1 yields 'True'
1-12
Table of Contents
Index
= <>
To compare two string values, insert the @ symbol before the comparison operator, as in the following example: IF ('A' @= 'B',0,1) yields the number 1. Using Logical Operators You can combine expressions in a calculation statement using logical operators. Operator & (ampersand) Meaning AND Example (Value1 > 5) & (Value1 < 10) Returns TRUE if the value is greater than 5 and less than 10. (Value1 > 10) % (Value1 < 5) Returns TRUE if the value is greater than 10 or less than 5. ~(Value1 > 5) Equivalent to (Value1 <= 5)
% (percentage sign)
OR
~ (tilde)
NOT
1-13
Table of Contents
Index
For example, the following expressions returns Rheingold. (Rhein | gold) If the string resulting from a concatenation is longer than 254 characters, TM1 returns an error. Using Cube References The formula portion of a calculation statement can contain cube references, which retrieve values from a cube. They can retrieve values from the cube for which you are writing a rule (internal cube references) or from other cubes on the same TM1 server (external cube references). Cube references are reviewed in great detail later in this book. Internal Cube References Internal cube references use the same syntax as the area definitions. Examples include: ['January'] ['Sales','January'] ['Germany','Sales','January'] In the following example, Gross Margin for Germany is calculated by multiplying Sales for Germany in the same cube by 0.53: ['Gross Margin','Germany']=['Sales']*0.53;
1-14
Table of Contents
Index
External Cube References Use the DB function retrieve values from external cubes. DB('Cube', DimaArg1, DimArg2,...DimArgn) Cube DimArg Name of the external cube. One of the following arguments: the name of an element in the appropriate dimension of the external cube, enclosed in single quotes. the name of the appropriate dimension preceded by an exclamation mark (!). This is called variable notation, which indicates that the reference applies to the element in the external cube that corresponds to the value currently being requested. For example if a DB function is used in a formula that calculates a value for Belgium, the argument !Region resolves to Belgium. an expression that resolves to an element in the appropriate dimension. Specify a DimArg argument for each dimension of the external cube. The DimArg arguments must be ordered to correspond to the order of dimensions in the external cube.
Terminator
The semicolon indicates the end of a rules statement, whether a calculation statement or a feeder statement, and is mandatory.
1-15
Bypassing Rules
Table of Contents
Index
Statements can be distributed over many lines, as long as each statement ends with a semicolon (;). You will see many long calculation statements formatted this way as you develop complex applications in later chapters of this book.
Bypassing Rules
By using the STET function, you can bypass the effect of a calculation statement for specific areas of a cube. For example, you may want to write a statement for Gross Margin that applies to all regions except France. You can write the general rule and the exception in two ways. Write the STET statement first followed by the general rule: [Gross Margin, 'France'] = STET; [Gross Margin] = ['Sales'] * 0.53; Write one rules statement that includes an IF function: ['Gross Margin'] = IF(!Region @= 'France', STET, ['Sales'] * 0.53);
General Considerations
The TM1 rules syntax is not case-sensitive. You can use both uppercase and lowercase letters. You can use spaces within rules to improve clarity. A rules statement can occupy one or more lines in the Rules Editor. It can also contain one or more formulas. End each statement with a semicolon.
1-16
Table of Contents
Index
To add comments and to exclude statements from processing, insert the number sign at the beginning of a line or statement. For example: # The following rule is not active # ['Gross Margin']=['Sales']*0.53;
Calculate on Demand
TM1 calculates values only when requested, or on demand. TM1 uses very efficient data compression to allow large data sets to fit in relatively small amounts of RAM, resulting in improved performance and reduced storage requirements. When a value is requested from a location in a cube, the TM1 server checks if the location corresponds to the area definition of any calculation statements associated with the cube. If the location does correspond to a statement, TM1 evaluates the formula portion of the calculation statement and returns a value to the relevant area. IMPORTANT: TM1 only calculates a value for each cube location once, and the first formula for a given area takes precedence over later formulas for the same area. If you have multiple rules statements that address the same area, you should order them most-specific to least-specific according to area definition. (TM1 does include a rules function named CONTINUE to address the rare instances when you want to apply multiple formulas to the same area. This function is described earlier in this chapter, as well as in the appendix to this guide.)
Introduction to TM1 Rules 1-17
Table of Contents
Index
TM1 processes the statements as follows: The first statement assigns the value 10 to the Germany, Year1 cell. It takes precedence over the second statement, which specifies that all Year1 cells contain 5.
1-18 TM1 Rules Guide
Table of Contents
Index
The second statement takes precedence over the third statement. Therefore, the cell for United States, Year 1 contains 5, even though the third statement specifies that all values for United States should be 6. The last statement [ ] = 2 specifies that all values in the cube contain the value 2. This statement applies to all cells that are not affected by preceding statements, such as France, Year2.
1-19
Table of Contents
Index
A simple example illustrates this issue. Suppose you have a two-dimensional cube named Sales that is composed of the dimensions Product and Month, with product (Total) and quarterly (Q1) consolidations defined. To calculate the grand total (Total, Q1), TM1 can consolidate the product totals for each month or consolidate quarterly totals for each product.
Grand total calculated by consolidating quarterly totals for each product.
Suppose further that you write a rule that calculates a value for total product sales in Jan, and that the rules-calculated value does not sum the individual product values for Jan. If the grand total is calculated by consolidating the product totals for each month, the value will differ from the consolidation of the quarterly totals for each product. This is because the rules-calculated value for total product sales in Jan overrides the natural dimension consolidation. You have no control over the order in which TM1 performs dimension consolidations. Furthermore, depending on which path is optimal at the moment, TM1 may alternate between paths in the same session. For example, you may request the Total, Q1 value twice in the same session and get different results.
1-20
Table of Contents
Index
You can remedy this situation by writing a rules statement that defines the grand total as the sum of product totals for each month, overriding the dimension consolidations. However, there remains an implicit inconsistency in the cube: the sum of the quarterly totals for each product is different from the grand total. Thus, overriding C: level values that are components of other consolidations is not recommended. Stacking Rules A rules statement can refer to a cube cell that is defined by another rules statement, and so on. TM1 stacks rules statements until it can obtain a final value, and then works back to return a result. The number of levels of stacking that can be accommodated is limited only by available memory. If a circular reference occurs within a rules stack, or the maximum level of stacking is exceeded, TM1 returns the error message: Error Evaluating Rule: Possible Circular Reference Here is an example of a circular reference: [Sales] = [Units] * [Price] ; [Price] = [Sales] / [Units] ;
Table of Contents
Index
Values for rules-calculated cells are then stored with the cube in memory. This prevents the same calculation from being repeatedly executed for a cell, and greatly increases performance. TM1 flags calculations as invalid when dependent values in the cube are modified. The next time a rules-derived value is requested, a fresh calculation is performed.
1-22
2 A Simple Rule
The remaining chapters of this guide follow the transformation of data for a fictional company called Fishcakes International, which purchases different types of fish from markets around the world and uses that fish to make fishcakes. Fishcake International purchases fish in local currency. Costs in local currency must be calculated based on quantities purchased and the local currency cost per Kg. Local currency costs must then be transformed into U.S. dollars using exchange rates. All these calculations are done using TM1 rules. Fishcakes International also uses TM1 rules to calculate inventory levels and inventory depletion, as well as to allocate costs for individual fish types to individual fishcake types and to calculate final production costs. In this chapter youll begin the transformation of the Fishcakes International data by creating a rule that calculates purchase costs in local currency.
A Simple Rule
2-1
Setting Your Local Data Directory for Use with this Guide
Table of Contents
Index
Setting Your Local Data Directory for Use with this Guide
Before you can proceed with developing the examples in this guide, you must first set your local data directory to use the appropriate sample data. TM1 ships with several sample data directories. The data directory for this guide is named Rules_sample_data. To set your local data directory: 1. Select File Options in the Server Explorer. The TM1 Options dialog box appears.
2. Click the Browse button. 3. Navigate to the \Applix\Custom\TM1Data\Rules_guide_data directory. If you accepted the default installation directory when installing TM1, the full path to this directory is C:\Program Files\Applix\Custom\TM1Data\Rules_guide_data. 4. Click Open.
2-2 TM1 Rules Guide
Table of Contents
Index
5. Click OK on the TM1 Options dialog box. When you change the local data directory, TM1 automatically restarts the local server with the new directory. Before restarting the local server, TM1 prompts you to save any current changes.
6. Click OK. TM1 restarts the local server using the Rules_guide_data directory, which contains the Fishcakes International data.
A Simple Rule
2-3
Table of Contents
Index
The four dimensions related to fish purchases in the Purchase cube are named and described below: Name Fishtype: Description Contains elements for each type of fish purchased. There are 19 leaf elements in the dimension, as well as a Total Fish Types consolidation. Contains elements for the markets in which fish are purchased. There are seven leaf elements in the dimension, as well as the Total Markets consolidation. Contains elements for the dates on which fish are purchased. The dimension contains 366 leaf elements, as well as multiple consolidations at varying levels. Contains five leaf elements that measure fish purchases. Measure include Purchase Cost - LC, Quantity Purchased - Kgs, and Price/Kg - LC.
Market:
Date:
PurMeas:
Using rules, you need to calculate the purchase cost in local currency by writing one rule statement that defines purchase cost as the product of price and amount purchased. This one statement will apply to all fish, for all markets and all dates in the Purchase cube. Using the element names from the PurMeas dimension and applying the rules syntax presented in the first chapter of this book, you can easily create the following calculation statement: ['Purchase Cost - LC'] = ['Quantity Purchased - Kgs'] * ['Price/Kg - LC'];
2-4
Table of Contents
Index
This says that if the TM1 server is asked for any value that matches the area Purchase Cost - LC, it will multiply the corresponding values for Quantity Purchased - Kgs and Price/Kg - LC and return the answer. When this calculation statement is in place, you can see that Purchase Cost LC values are calculated in the Purchase cube:
But what about the value in the lower right cell? The calculation statement is multiplying Total, Quantity Purchased - Kgs by the Total, Price/Kg - LC. Of course, prices per Kg do not sum, so the value for Total, Purchase Cost - LC is wildly incorrect. (The best way to generate the total Purchase Cost - LC is to sum purchase cost values across fish, which TM1 can do automatically through its dimensional consolidations.)
A Simple Rule
2-5
Table of Contents
Index
Fortunately, you can specify that a rule applies only to leaf cells and not to consolidations such as Total. This is done by inserting an N: in front of the formula portion of the calculation statement: ['Purchase Cost - LC'] = N: ['Quantity Purchased - Kgs'] * ['Price/Kg - LC']; When the statement is corrected as above, consolidations are not calculated by the rule. Accordingly, the total Purchase Cost - LC consolidation is correctly calculated by summing the values of the members of the consolidation, as shown below.
2-6
Table of Contents
Index
A Simple Rule
2-7
Table of Contents
Index
2-8
Table of Contents
Index
This dialog box lets you define a reference to the cube with which the rule is associated. In this case, you want to create a cube reference that defines the area of the rule as ['Purchase Cost - LC'], an element of the PurMeas dimension. 2. Click the PurMeas button. The Subset Editor appears.
A Simple Rule
2-9
Table of Contents
Index
3. Select Purchase Cost - LC. 4. Click OK. The Reference to Cube dialog box appears with the current area definition
Area definition
2-10
Table of Contents
Index
If you wanted to, you could define an area with a selection of single elements from any combination of dimensions. For instance, you could let the statement apply only to one market and one fish type on a certain date. In this example, though, you want Purchase Cost - LC to be calculated the same way for all leaf cells, so the area definition is complete. 5. Click OK. The Rules Editor displays the area definition, formatted correctly with square brackets and single quotes.
The area definition is complete, so you can now begin to write the remainder of the calculation statement.
A Simple Rule
2-11
Table of Contents
Index
button. button.
This button inserts the N: qualifier into the statement. This qualifier is necessary because you want the statement to apply only to leaf elements. Now you must create the formula that calculates values for the specified area. 8. Click the button again.
9. Click the PurMeas button on the Reference to Cube dialog box. 10. In the Subset Editor, select Quantity Purchased - Kgs and click OK. 11. Click OK on the Reference to Cube dialog box. The Rules Editor should now appear as follows.
2-12
Table of Contents
Index
14. Click the PurMeas button on the Reference to Cube dialog box. 15. In the Subset Editor, select Price/Kg - LC and click OK. 16. Click OK on the Reference to Cube dialog box. The Rules Editor should now contain the area definition, leaf qualifier, and formula for the rule.
A Simple Rule
2-13
Table of Contents
Index
The calculation statement is nearly complete. All thats missing is the semicolon indicating the end of the statement. 17. Click the button
IMPORTANT: Dont forget the trailing semicolon! Forgetting the semicolon is the most common syntax error in TM1 rules, even for long-time users.
2-14
Table of Contents
Index
This view confirms that for individual fish types, values for Purchase Cost LC are calculated by multiplying Quantity Purchased Kgs by Price/Kg - LC. The value of Total, Purchase Cost - LC is calculated by the consolidation of individual fish, as defined in the FishType dimension. In the Server Explorer, a rule icon now appears beneath the Purchase cube.
You can double-click the rule icon to open a rule for editing in the Rules Editor.
A Simple Rule
2-15
Table of Contents
Index
2-16
3 Exchange Rates
Fishcakes International purchases fish in multiple markets using different local currencies. To keep accurate track of costs, the company needs to convert these purchases into a common currency. Fishcakes International translates all local currency purchases into US dollars, which it derives through exchange rates. Accurately modeling currency conversions often presents problems because exchange rates can change very quickly, with a heavy impact on the bottom line. Many tools are negatively impacted by the burden of calculating daily exchange rates, or require that the rates be applied monthly. Calculation on demand, though, combined with TM1s efficient indexing, makes it easy to calculate detailed models with daily exchange rates.
Exchange Rates
3-1
Table of Contents
Index
One problem with this approach is that it requires a lot of excess data entry, with the exchange rate being duplicated for each fish type. The exchange rate does not actually vary by fish type, but rather by the day and the currency in use at a particular market. The duplicate data also invites errors; it is easy to make a mistake with one or another of the many identical entries. Though storing exchange rates in the cube where you want to calculate the price in U.S. dollars is a valid approach, it is not the most efficient solution.
3-2
Table of Contents
Index
You could then create a rule that uses the ATTRN rules function to retrieve the necessary attribute values and calculate costs in U.S. dollars. This is a perfectly valid approach, particularly if attribute values are regularly updated through a TurboIntegrator process.
Exchange Rates
3-3
Table of Contents
Index
dollars. This is the solution you will develop, as it provides an excellent example of inter-cube calculations accomplished through the use of DB functions.
The DB Formula
The DB function allows you to write a rule that references values in any other cube on the same TM1 server. TM1 supports multiple interrelated cubes of differing but overlapping dimensionality, so there are all kinds of applications that benefit from DB functions. In the following examples, you will connect purchases in the Purchase cube (dimensioned by fish, market and date) to exchange rates in the ExchangeRate cube (dimensioned only by market and date). In other applications, you might apply commission rates varying by employee to a sales database dimensioned by employee, product and time. Or you could use a cube containing percentages of active ingredients in pharmaceutical products to derive production statistics in another cube, which contains shipments by product.
The Rule
To calculate price per Kg in U.S. dollars, you create a rule statement in the rule for the Purchase cube that divides the price per Kg in local currency by the exchange rate for the current market and date. The exchange rate, which is stored in the MarketExchange cube, is retrieved by a DB function. ['Price/Kg - USD']=['Price/Kg - LC']\DB('MarketExchange',!market,!date); When you compile the rule and browse the cube you can see that the rule indeed returns price per Kg in U.S.dolars (USD).
3-4 TM1 Rules Guide
Table of Contents
Index
DB('MarketExchange',!market,!date) To understand the bang, keep in mind that the rule is executed only when a value is requested. The expression !market tells the rules interpreter to use
Exchange Rates
3-5
Table of Contents
Index
the element of the Market dimension in the MarketExchange cube that matches the Market element for the requested value in the Purchase cube. When using DB functions, note the distinction between the source and target cubes. The target cube is the cube whose rule contains the function, the one receiving the value specified by the rule. The source cube is the cube providing values, the one referenced by the DB function. When writing DB functions always keep in mind the dimensional structure of the target cube for which the rule is being written as well as that of the source cube referenced in the DB functions. When TM1 evaluates a DB function it looks at the cube specified by the first argument to the function and expects to find an argument for each dimension of that cube, in the correct order. Each argument can be any TM1 expression, but it must evaluate to a valid element of the corresponding dimension. To better understand DB functions and the use of the !dimension argument, consider what happens when the TM1 server receives a request for the Price/ Kg - USD of Trout in Karachi on June 16th: 1. The server determines if the value requested matches any rule area definitions. ['Price/Kg - USD']=['Price/Kg - LC']\DB('MarketExchange',!market,!date) 2. The request does match the area definition of the above rule statement, so TM1 begins to evaluate the formula portion of the statement. 3. TM1 retrieves the value of Price/Kg - LC, keeping all other dimension elements constant (Trout, Karachi, Jun -16). In the view above, this value is 76.64. 4. TM1 evaluates the function DB('MarketExchange',!market,!date).
3-6
Table of Contents
Index
4.1. The first argument to the DB function tells TM1 to look in the MarketExchange cube. 4.2. The second argument (!market) tells TM1 to use the element of the Market dimension that corresponds to the value being requested. In this case, the element is Karachi. 4.3. The third argument (!date) tells TM1 to use the element of the Date dimension that corresponds to the value being requested. In this case, the element is Jun -16. 4.4. The DB function evaluates to DB('MarketExchange',Karachi,Jun-16). TM1 retrieves the value for Karachi and Jun -16 from the MarketExchange cube.
Exchange Rates
3-7
Table of Contents
Index
5. The formula portion of the rule evaluates to 76.64\57.4801. 6. TM1 calculates the value of Price/Kg - USD for Trout in Karachi on June 16 to be $1.33.
3-8
Table of Contents
Index
4. Using the buttons on the Rules Editor and the techniques described in the previous chapter, write the area definition and the first part of the formula. When you are done, the incomplete statement should appear as follows. ['Price/Kg - USD']=['Price/Kg - LC'] 5. Click the button.
This button inserts a backslash character. This character is a division operator, but it differs from the normal division operator (the forward slash). When you use the backslash operator, any rule that results in division by zero returns the value 0 rather than the N/A error. 6. Click the button.
The Select Cube dialog box appears. This dialog box lets you pick the cube from which the DB formula retrieves values. 7. Select MarketExchange.
Exchange Rates
3-9
Table of Contents
Index
You want this reference to apply to all markets and all dates, so there is no need to narrow the reference definition. 9. Click OK. 10. Enter the semicolon at the end of the rule statement. The completed rule statement should appear as follows: ['Price/Kg - USD']=['Price/Kg - LC']\DB('MarketExchange',!market,!date); 11. Click Save to save the rule. 12. Open the Price USD view of the Purchase cube to see the result of the new rule statement.
3-10
Table of Contents
Index
Note that all values for Price/Kg - USD are now calculated by the rule.
Exchange Rates
3-11
Table of Contents
Index
You can solve this problem of redundant data by using a cube that stores the relationship of market to currency. The sample data that accompanies this book contains just such a cube, named Currency.
3-12
Table of Contents
Index
This cube is comprised of two dimensions: the Market dimension, and a dimension named MarketCurrency, which contains a single string element (also named MarketCurrency).
When used in conjunction with a lookup cube that stores exchanges rates by currency (CurrencyExchangeRate), you can develop a rule statement that calculates Price/Kg -USD for each market based on the daily exchange rate for a given currency. The next section illustrates the creation of such a statement.
Exchange Rates
3-13
Table of Contents
Index
How It Works When the TM1 server receives a request for the Price/Kg - USD of Trout in Karachi on June 16th from the Purchase cube, the following actions occur: 1. As always, the TM1 server determines if the value requested matches any rule statement area definitions. ['Price/Kg - USD']=['Price/Kg - LC']\ DB('CurrencyExchangeRate',DB('Currency',!market,'MarketCurrency'),!date); 2. The request does match the area definition of the above rule statement, so TM1 begins to evaluate the formula portion of the statement. 3. TM1 retrieves the value of Price/Kg - LC, keeping all other dimension elements constant (Trout, Karachi, Jun -16.) In the Purchase cube, this value is 76.64.
4. TM1 evaluates the nested DB functions DB('CurrencyExchangeRate',DB('Currency',!market,'MarketCurrency'),!date). 4.1. The first argument to the outer DB function tells TM1 to look in the CurrencyExchangeRate cube.
3-14
Table of Contents
Index
4.2. The second argument to the outer function, which must resolve to a valid element of the Currency dimension, is another DB function: DB('Currency',!market,'MarketCurrency') 4.2.1. This nested DB function returns the value from the Currency cube identified by the market for the value being requested (!market) and the element MarketCurrency. In this case, the TM1 server is processing a request for a value in the Karachi market, so the function returns the string Rupee.
Exchange Rates
3-15
Table of Contents
Index
Rupee is used as the second argument to the outer DB function. 4.3. The third argument to the outer DB function is !date, which evaluates to Jun -16, the date of the requested value. 5. The outer DB function evaluates to DB('CurrencyExchangeRate',Karachi,Jun-16). TM1 retrieves the value for Karachi and Jun -16 from the MarketExchange cube.
3-16
Table of Contents
Index
6. The formula portion of the rule statement evaluates to 76.64\57.4801. 7. TM1 calculates the value of Price/Kg - USD for Trout in Karachi on June 16 to be $1.33.
Exchange Rates
3-17
Table of Contents
Index
3-18
Table of Contents
Index
The Rules Editor should already contains a statement to calculate Price/Kg - USD, which you created earlier in this chapter. 3. Insert a # at the beginning of the existing statement. As you recall from Chapter 1, the pound symbol (#) is the comment character for TM1 rules. 4. Create the following text in the Rules Editor on a new line following the existing statement. This text can be entered directly by hand or through the use of the function buttons.
5. Click the
button.
Exchange Rates
3-19
Table of Contents
Index
6. Select CurrencyExchangeRate and click OK. The Reference to Cube dialog box appears.
7. Click OK. 8. Insert a semi-colon at the end of the statement. The rule statement should now appear as follows.
3-20
Table of Contents
Index
Note that the DB function includes the argument !Currency, a reference to the current element of the Currency dimension. However, the rule statement is being written for the Purchase cube, which is composed of the dimensions FishType, Market, Date, and PurMeas. The Purchase cube does not include the Currency dimension; the DB formula as it now exists cannot resolve all arguments and will return an error if you attempt to save the rule.
You must replace !Currency with an argument that resolves to a dimension element of the Purchase cube. 9. Select the text !Currency in the Rules Editor.
Exchange Rates
3-21
Table of Contents
Index
button.
The Select Cube dialog box appears. 11. Select the Currency cube and click OK. The Reference to Cube dialog box appears.
12. Click the Market Currency button. The Subset Editor opens with the sole element of the MarketCurrency dimension.
3-22
Table of Contents
Index
13. Select the MarketCurrency element and click OK. 14. Click OK on the Reference to Cube dialog box. The complete rule statement should appear as follows.
Exchange Rates
3-23
Table of Contents
Index
You can open the Jun -16 view of the Purchase cube to confirm that the new rule statement calculates values for Price/Kg - USD.
This model using nested DB functions is more complicated than the first model used to calculate Price/Kg - USD, but it has the significant advantage of storing exchange rates for each currency in just one place and using a lookup cube to determine the correct currency for each market.
Table of Contents
Index
The rule in the Sales cube: ['Products sold'] = ['Packages sold'] * DB('PkgComp', !Product, 'NoProd'); Labor costs depend on staffing and on salary, which varies by job grade. An Expenses cube holds information on headcount by job grade, broken out by month, division and location. A second lookup cube holds information on average salary for each job grade. A rule yields salary expense by month, division and location. The rule in the Expenses cube: ['Labor costs'] = ['headcount'] * DB('AvgSal', !JobGrade, 'Salary');
Exchange Rates
3-25
Table of Contents
Index
3-26
4-1
Table of Contents
Index
As you can see, the cubes share only the FishType and Date dimensions and the cubes track completely different measures. Yet despite these differences, you can use DB functions to easily move data from the Purchase cube to the Inventory cube.
4-2
Values for each fish type in the Purchase cube must be moved to the corresponding fish type in the Inventory cube. The two cubes share the FishType dimension. Values for each date in the Purchase cube goes to the same date in the Inventory cube. The two cubes share the Date dimension. Values for Quantity Purchased - Kg in the Purchase cube are moved to Quantity in Stock - Kg in the Inventory cube. For any given date, values for newly purchased fish in the Purchase cube are moved to element 1 of the DaysOld dimension in the Inventory cube. The DaysOld dimension contains elements that reflect the age of fish in inventory. Newly purchased fish is considered to be one day old. Later in this book you will develop rules to cycle inventory through the DaysOld dimension on a daily basis as the inventory ages.
4-3
Table of Contents
Index
Value of Quantity in Stock - Kgs for DaysOld batch 1 in the Inventory cube is calculated by retrieving the value of Quantity Purchased - Kgs for Total Markets from the Purchase cube.
4-4
Value of Purchase Cost for DaysOld batch 1 in the Inventory cube is calculated by retrieving the value of purchase Cost - USD for Total Markets from the Purchase cube.
4-5
Table of Contents
Index
4-6
Note that the rules statements calculate values only for DaysOld batch 1. In later chapters youll develop additional statements for the Inventory rule that calculate values for all other DaysOld batches.
4-7
Table of Contents
Index
4-8
5-1
Sparsity
Table of Contents
Index
Sparsity
Before using feeders, you must understand the typical sparse distribution of multidimensional data and TM1s consolidation logic. During consolidations, TM1 uses a sparse consolidation algorithm to skip over cells that contain zero or are empty. This algorithm speeds up consolidation calculations in cubes that are highly sparse. A sparse cube is a cube in which the number of populated cells as a percentage of total cells is low. When consolidating data in cubes that have rules defined, TM1 turns off this sparse consolidation algorithm because one or more empty cells may in fact be calculated by a rule. (Skipping rules-calculated cells will cause consolidated totals to be incorrect). When the sparse consolidation algorithm is turned off, every cell is checked for a value during consolidation. This can slow down calculations in cubes that are very large and sparse. Typically, multidimensional cubes contain many more cells with zeros than with values. For example, consider the Purchase cube, where each type of fish is purchased in just a few markets. A typical view of the Purchase cube looks like this:
5-2
Sparsity
Table of Contents
Index
Most values here are zeros, an indication that this cube is relatively sparse. Multidimensional cubes are almost always sparse. NOTE: Strictly speaking, there is a semantic distinction between a zero and a value that is missing or non-applicable. Sparsity may apply to any of these possible states, with possibly different results. In TM1, though, values can only be real numbers, and the value zero is used to represent all of these states. The impact of sparsity on calculations can be tremendous. Consider the consolidated value (7434) at the intersection of Total Markets and Total Fish Types, located in the lower right corner of the view above. If you add up every possible cell required to calculate this value, you must add values from 119 different cells. However, if you add only the cells with non-zero values, the number of components of the calculation drops to 36.
5-3
Table of Contents
Index
If you change the element of the Date dimension, you see even more sparsity, since not all markets are open on every date, and not all fish are bought on every date. For example, if you drill down on the above view to the single date Jun -16, you see that the number of components of the Total Markets/Total Fish Types consolidation drops to just 20!
On average, the more dimensions a cube has, the greater the degree of sparsity.
5-4
Table of Contents
Index
a consolidation to see if it contains a number. And as you just saw, this can be extremely inefficient. Because consolidations will be incorrect if they skip values derived from rules, TM1s default behavior is to turn off sparse consolidation when rules are defined for a cube. This ensures that all values are correct, but speed can plummet by several orders of magnitude (roughly proportional to the degree of sparsity of the cube data). If you build applications of even modest size that work with sparse data, you will have to write feeders. The process of creating feeders is described in detail in this chapter. Each subsequent chapter in this guide contains instructions for creating feeders to accompany calculation statements.
Single-Cube Feeders
Table of Contents
Index
The feeder area identifies a component of a rules-derived value. When this component contains a non-zero value, a placeholder is fed to cells containing the rules-calculated value identified on the right-hand side of the statement. This placeholder alerts the TM1 consolidation engine to include the rules-derived value when performing consolidations. Precede the feeder statements with the FEEDERS declaration: FEEDERS; NOTE: After inserting a SKIPCHECK; statement at the top of the Rules Editor, you can no longer take for granted that calculations are accurate. Even if rules are correctly defined, consolidation results will be wrong if feeders do not accurately describe where rules-derived values are located. Your goal as a rules writer is to exactly specify all cells that contain rules-derived values. When this is not practical, you can overfeed, or feed a somewhat larger set of cells than is strictly required. Overfeeding does not produce wrong values, but it can slow down the system. However, underfeeding failing to feed cells that contain rules-derived values will result in wrong results and must be avoided at all costs.
Single-Cube Feeders
Generally speaking, every calculation statement in a rule should have a corresponding feeder statement. The simplest feeders are those that apply to calculations within one dimension of one cube, where the presence of a nonzero value in one element implies the presence of one in the other. To illustrate this, recall the first calculation statement you created for the Purchase cube in the previous chapter . ['Purchase Cost - LC']=N:['Quantity Purchased - Kgs']*['Price/Kg - LC'];
5-6 TM1 Rules Guide
Single-Cube Feeders
Table of Contents
Index
This statement calculates values for the area Purchase Cost - LC. Looking at the statement, you can surmise that if the value for Quantity Purchased - Kgs is zero, the rule returns zero for Purchase Cost - LC. If the value for Quantity Purchased - Kgs is non-zero, then the rule returns a non-zero value as well. (This assume that for a given Quantity Purchased - Kgs there is always a nonzero value for Price/Kg - LC.) In this case, Purchase Cost - LC contains a value only when Quantity Purchased - Kgs contains a value. To write accurate feeders, you need to focus on which component(s) of a formula determine when a non-zero value is returned to the area. For example, in the first calculation statement above, Purchase Cost - LC is derived from a product involving Quantity Purchased - Kgs. A view of the Purchase cube might look like this:
If nothing is bought (Quantity Purchased - Kgs is zero), then nothing is paid (Purchase Cost - LC is also zero). In this case, Quantity Purchased - Kgs is the component of the formula that determines when the rule returns a non-zero value. Knowing this fact, you can construct the required feeder as follows:
Improving Performance with Feeders 5-7
Single-Cube Feeders
Table of Contents
Index
['Quantity Purchased - Kgs']=>['Purchase Cost - LC']; This feeder says that when there is a non-zero value for Quantity Purchased Kgs, TM1 should feed a placeholder to Purchase Cost LC. You can use this same approach to create feeders for the other calculation statements in the rule for the Purchase cube. The second calculation statement in the rule calculates values for the area Price/Kg - USD.
['Price/Kg - USD']=N:['Price/Kg -LC']\DB('CurrencyExchangeRate',DB('Currency',!market,'MarketCurrency'),!date);
Here, the value of Price/Kg - USD is dependent upon the value of Price/Kg LC. Specifically, Price/Kg - USD is a quotient dependent upon the dividend Price/Kg -LC. You should use Price/Kg -LC to feed Price/Kg - USD. ['Price/Kg -LC']=>['Price/Kg - USD']; The final calculation statement in the Purchase rule calculates values for the area Purchase Cost - USD.
['Purchase Cost - USD']=N:['Purchase Cost - LC']\DB('CurrencyExchangeRate',DB('Currency',!market,'MarketCurrency'),!date);
The value of Purchase Cost - USD is dependent upon the value of Purchase Cost - LC. Similar to the preceding calculation statement, Purchase Cost USD is a quotient dependent upon the dividend Purchase Cost - LC. You should use 'Purchase Cost - LC to feed Purchase Cost - USD. ['Purchase Cost - LC']=>['Purchase Cost - USD']; Adding Feeders to the Rule for the Purchase Cube To restore the sparse consolidation algorithm to the Purchase cube: 1. Double-click the rule for the Purchase cube in the Server Explorer.
5-8
Single-Cube Feeders
Table of Contents
Index
2. Insert the SKIPCHECK; declaration at the top of the Rules Editor. The SKIPCHECK; declaration must be the first line in the rule. 3. Add the FEEDERS; declaration after the last calculation statement. 4. Enter the following three feeder statements immediately following the FEEDERS; declaration. ['Quantity Purchased - Kgs']=>['Purchase Cost - LC']; ['Price/Kg -LC']=>['Price/Kg - USD']; ['Purchase Cost - LC']=>['Purchase Cost - USD']; The complete rule for the Purchase cube should now appear as follows:
5-9
Table of Contents
Index
5-10
Table of Contents
Index
2. Position the cursor at the beginning of a new line after the last feeder statement in the Purchase rule. 3. Enter the following text:
#Feeders for the Inventory cube follow
Improving Performance with Feeders 5-11
Table of Contents
Index
This line is just a comment that makes the rule more understandable. 4. On a new line below the comment, enter the following feeder statement, either by typing or by using the buttons on the Rules Editor: ['Total Markets','Quantity Purchased - Kgs']=>DB('Inventory',!FishType,!Date,'1','Quantity in Stock - Kgs'); This feeder statement ensures that any location in the Purchase cube identified by the elements Total Markets and Quantity Purchased - Kgs feeds the analogous location in the Inventory cube identified by the elements 1 and Quantity in Stock - Kgs. The feeder is basically the inverse of the calculation statement in the Inventory cube that requires the feeder: ['1','Quantity in Stock - Kgs']= N:DB('Purchase',!FishType,'Total Markets',!Date,'Quantity Purchased - Kgs'); 5. On a new line below the feeder statement you just created, enter the next feeder statement: ['Total Markets','Price/Kg - USD']=>DB('Inventory',!fishtype,!date,'1','Purchase Cost'); Again, note that this feeder statement is the inverse of the calculation statement that requires the feeder: ['1','Purchase Cost'] = N:DB('Purchase',!FishType,'Total Markets',!Date,'Price/Kg - USD'); The Rules Editor for the Purchase rule should now appear as follows:
5-12
Table of Contents
Index
5-13
Troubleshooting Feeders
Table of Contents
Index
Troubleshooting Feeders
TM1 provides a tool called the Rules Tracer to assist in the development and debugging of TM1 rules. When developing feeders, the Rules Tracer lets you: trace feeders, to ensure that selected leaf cells are feeding rules-calculated cells properly check feeders, to ensure that the children of a selected consolidated cell are fed properly Rules Tracer functionality is available only in the Cube Viewer.
Tracing Feeders
The Rules Tracer lets you trace the way a selected cell feeds other rulescalcluated cells. Because you can only feed from a leaf element, this option is not available for consolidated cells. The option is, however, available for leaf cells defined by rules. To trace feeders for a cell: 1. In the Cube Viewer, right-click the cell you want to trace. 2. Select Trace Feeders. The Rules Tracer window opens. This window contains two panes. The top pane displays the definition of the current cell location, as well as the feeder statements associated with the current cell. The bottom pane displays the locations fed by the current cell.
5-14
Troubleshooting Feeders
Table of Contents
Index
The following example shows the result of selecting the Trace Feeders option from the highlighted cell in the Jun - 16 view of the Purchase cube. (This example shows a feeder statement that feeds cells in the Inventory cube. Youll create this feeder statement in later chapter.)
5-15
Troubleshooting Feeders
Table of Contents
Index
3. Double-click a location in the bottom pane. This location becomes the current cell location in the top pane, and the bottom pane displays any locations fed by the new current cell. 4. Continue double-clicking locations in the bottom pane until you have traced the feeders to the level you require.
Checking Feeders
If a cube has a rule attached that uses SKIPCHECK and FEEDERS, you can use the Rules Tracer to check that the components of consolidations are properly fed. To check feeders: 1. In the Cube Viewer, right-click the consolidated cell you want to check. 2. Select Check Feeders. The Rules Tracer window opens. This window contains two panes.
5-16
Troubleshooting Feeders
Table of Contents
Index
The top pane displays the definition of the current cell (consolidation). The bottom pane displays all components of the consolidation that are not properly fed. If the bottom pane is empty, the consolidation is fed properly and cubes values are accurate. If the bottom pane displays components of the consolidation, you must edit the rule associated with the current cube to contain feeder statements that feed all the listed components. NOTE: You can only check feeders for a cell once per session. The action of checking feeders actually feeds the components of the consolidation, so any subsequent checking will not yield accurate results. If you want to check feeders for a cell more than once, you must recycle the TM1 server before every check.
5-17
Troubleshooting Feeders
Table of Contents
Index
5-18
Table of Contents
Index
A second cube may use a similar dimension, but omit the SKU elements and have leaf elements at the product level:
Such a situation often arises when separate cubes are used for planning and actuals data. Typically, actuals data is kept in great detail, while planning data is kept in a less detailed form.
6-1
Table of Contents
Index
In this chapter youll discover how you can use rules to move data from moredetailed cubes to less-detailed cubes and to enter data at multiple levels of detail. This type of scenario often arises when a model includes budgeting and planning for production data where the granularity of production is more detailed than that of the budget (monthly vs.daily).
The key dimensional difference between these cubes is in their handling of time. Actual values in the Production cube are tracked by day in the Date
6-2
Table of Contents
Index
dimension, but values in the Plan cube are tracked only by month in the Month dimension.
As the months go by, Fishcake International executives want to see previous months data from the Production cube appear in the appropriate months in the Plan cube. Thus, January values from Production, which are consolidated, should appear as January values in the Plan cube, where January is a leaf element. The reason Fishcake International maintains a separate cube for Plan data is not to see the monthly aggregates created in the Production cube (this you could easily do directly in the Production cube) but rather to allow for the manual entry of plan numbers at the month level directly into the Plan cube.
Table of Contents
Index
['Planned Production Qty - Kgs']=DB('Production',!CakeType,!Date,'Quantity Produced - Kgs'); However, when you attempt to compile this statement you receive the following error:
What Is the Problem? The above rule statement includes a DB function that references the Date dimension. (The !Date argument to the DB function instructs the TM1 server to use the current element of the Date dimension.) Unfortunately, the Plan cube for which the rule is written does not include the Date dimension. The TM1 server is unable to resolve the !Date argument, resulting in the error. The Plan cube does contain the Month dimension, which shares common element names with the Date dimension. If you substitute a reference to the Month dimension for the original reference to the Date dimension, the rule compiles and correctly moves data from the Production cube into the Plan cube. ['Planned Production Qty - Kgs']=DB('Production',!CakeType,!Month,'Quantity Produced - Kgs'); To create the above calculation statement for the Plan cube: 1. Right-click the Plan cube in the Server Explorer. 2. Select Create Rule. 3. Enter the above statement in the Rules Editor.
6-4 TM1 Rules Guide
Table of Contents
Index
4. Click Save to save the rule. You can now confirm that the rule works by opening the Jan - Mar view for both the Production and Plan cube. The Jan - Mar view of the Plan cube pulls values from the identically structured view of the Production cube.
6-5
Table of Contents
Index
How It Works The trick is that even though the source cube (Production) does not have a Month dimension, the DB function scans the referenced cube for dimension elements whose names match those of elements in the equivalently ordered dimension in the target cube. In this case, the DB function looks for elements in the Month dimension that match element names in the Date dimension. For example, when the following rule statement exists in the rule for the Plan cube, suppose the TM1 server processes a request for the value in the Plan cube at the coordinates Total Fish Cake Types, January, Planned Production Qty - Kgs. ['Planned Production Qty - Kgs']=DB('Production',!CakeType,!Month,'Quantity Produced - Kgs'); When this statement is executed, the TM1 server performs the following actions: 1. It checks if the requested value from the Plan cube corresponds to the area definition of the rule statement. In this example, the requested value lies at the intersection of Total Fish Cake Types, January, Planned Production Qty - Kgs, so it does correspond to the area definition. 2. The server then looks in the Production cube for a value whose CakeType element is Total Fish Cake Types (the CakeType element for the value being requested in the Plan cube), and whose second dimension element corresponds to the Month element for the value being requested. In this case, the second dimension in the Production cube is Date, which contains the element January. This element exactly corresponds to the current Month element for the value being requested in the Plan cube. Note that the server does not try to verify that the Month dimension is part of the Production cube. It simply verifies that the current element in the Month dimension is a valid argument to the DB function.
6-6 TM1 Rules Guide
Table of Contents
Index
3. The server uses Quantity Produced - Kgs as the final argument to the DB function. 4. The DB function returns a value for Planned Production Qty - Kgs. Writing the Required Feeder As with previous rules youve written, you now need to write a feeder that lets the consolidation engine know where there are rules-calculated values in the Plan cube. Keeping in mind the Date/Month discrepancy reviewed above, the following feeder statement in the rule for the Production cube (recall that the feeder in an inter-cube rule always goes in the rule for the source cube) is accurate: ['Quantity Produced - Kgs']=>DB('Plan',!CakeType,!Date,'Planned Production Qty - Kgs'); For a given CakeType and Date, this feeder statement feeds Planned Production Qty - Kgs in the Plan cube when the Production cube contains a value for Quantity Produced - Kgs. Note that the DB function in the feeder statement references the Date dimension, which is not a member of the Plan cube. (Month is actually the second dimension of the Plan cube.) As with the calculation statement above, this works because the Date and Month dimensions share common element names. To add the required feeder statement to the rule for the Production cube: 1. Double-click the Plan rule in the Server Explorer. 2. Enter a SKIPCHECK; declaration at the top of the rule. 3. Click Save on the Rules Editor. 4. Right-click the Production cube in the Server Explorer. 5. Select Create Rule.
Moving Data and Changing Levels 6-7
Table of Contents
Index
The Rules Editor appears. 6. Enter a FEEDERS; declaration in the Rules Editor. 7. Enter the following feeder statement immediately following the FEEDERS; declaration: ['Quantity Produced - Kgs']=>DB('Plan',!CakeType,!Date,'Planned Production Qty - Kgs'); 8. Click Save on the Rules Editor.
6-8
Table of Contents
Index
7-1
The Problem
Table of Contents
Index
The Problem
Youve now moved actual Production data into the Plan cube in the Fishcakes International model, but you still have more to do. The point of a plan is not simply to restate actuals, but to estimate the future. This requires the ability to do various types of time series calculations. Many companies like to produce reports combining actuals with projections. Numbers for past months represent actual performance; those for future months are best-guess projections. Fishcakes International puts both types of data into one Plan cube. Actual values are derived through calculation statements that reference the Production cube; future months are calculated based on performance so far, combined with a month-by-month percentage change in production. Each future months projection is calculated by applying the standard percentage change for that month to the value for the previous month.
7-2
Four Solutions
Table of Contents
Index
In a spreadsheet, the calculation to adjust values on a monthly basis looks like this:
Planned values derived by multiplying previous month by adjustment percentage. For example, the planned value for April is derived by multiplying the planned value for March by the adjustment percentage for April. The function used to derive the planned value for April (cell C10) is =C9*B10. Adjustment percentages
Four Solutions
To illustrate the options available to the you, this chapter explores several
Rules for Time-Based Calculations 7-3
Four Solutions
Table of Contents
Index
different ways to tackle this problem, presented in order of increasing complexity. Each of these solutions has different strengths and weaknesses. In the real world, no two applications are identical; any one of these approaches may be more appropriate for one situation than for another.
7-4
Four Solutions
Table of Contents
Index
The rule statements for the Plan cube would look like this:
As the following view of the Plan cube illustrates, this rule accomplishes the job of moving data into the Plan cube from the Production cube for the months of January and February. The rule also correctly calculates planned Production Quantity Values for the months of March through December.
7-5
Four Solutions
Table of Contents
Index
This solution has the advantage of being easy to write and understand. It has some significant limitations, though: It is excessive to have to write twelve separate statements, one for each month. The statements need to be changed each month as the year advances (new values from the Production cube have to be brought into the Plan cube each month, requiring a change to the statements).
7-6
Four Solutions
Table of Contents
Index
If the associated feeders are similarly hard-coded, they too will need to change each month.
7-7
Four Solutions
Table of Contents
Index
Perhaps most useful, though, a DB function containing the expression DIMNM('Date',DIMIX('Date', !Date) - 1) will step back through every element of the Date dimension and relative to each date element, retrieve the previous date. Using this construction, you can replace the ten month-specific statements in the Plan rule that calculate future planned production quantities with one (somewhat more complex) statement.
The single calculation statement ['Planned Production Qty - Kgs']=DB('Plan',!CakeType,DIMNM('Month',(DIMIX('Month',!Month) -1) ),'Planned Production Qty - Kgs') * ['Adj. % from last month]; accurately retrieves Planned Production Qty - Kgs values for the months March through December. This statement uses a DB formula to refer to the current cube. (As you recall from Chapter 4, the DB formula is much more flexible than square-bracket notation. In this case, a DIMNM function returns the argument
7-8
Four Solutions
Table of Contents
Index
for the Month dimension to the DB formula. Such formulas cannot be used in square-bracket notation.) To better understand how this statement works, consider what happens when the TM1 server receives a request for the value of Planned Production Qty Kgs of Salty Cake in the month of March: 1. The server evaluates !Month to March, the month that is being requested. 2. DIMIX('Month', 'March') evaluates to 3, the index value of March in the Month dimension. 3. 3-1 evaluates to 2. 4. DIMNM('Month',2) evaluates to February. 5. !CakeType evaluates to Salty Cake, the caketype of the value that is being requested. 6. DB('Plan', 'Salty Cake', 'February', 'Planned Production Qty - Kgs') evaluates to 170.00. 7. ['Adj. % from last month'] for Salty Cake and March evaluates to 96%. (Remember, the server is processing a request for a value in March.) 8. The server multiplies the value of 170.00 by 96% to return 163.20, the Planned Production Qty - Kgs of Salty Cake in the month of March. This new statement has the benefit of replacing ten statements with one. However, the rule for the Plan cube still includes two month-specific statements that pull values from the Production cube, and a new monthspecific statement will have to be added to the rule each month to pull the latest actual values into the Plan cube.
7-9
Four Solutions
Table of Contents
Index
Ideally, the rule for the Plan cube should use a single statement to retrieve values for all months, and it should not be necessary to edit the rule from month-to-month.
7-10
Four Solutions
Table of Contents
Index
This single statement accurately retrieves and calculates values for all months. If the value requested is for a month prior to March, the function DB('Production',!CakeType,!Month,'Quantity Produced - Kgs') retrieves the value from the Production cube. If the value requested is for the month of March or later, the formula DB('Plan',!CakeType,DIMNM('Month',(DIMIX('Month',!Month) -1) ),'Planned Production Qty - Kgs')* ['Adj. % from last month'] calculates the value. This single statement is an improvement over previous solutions, but it uses a literal month name as an argument to the second DIMIX function. This month name must be edited as you progress from month to month. Ideally, though, you should not need to edit a rules statement on a monthly basis. One possible solution would be to use the TIMVL function, which returns the numeric value of a component of a date/time value, in combination with the NOW function, which returns the date/time value of the current time. For example, TIMVL(NOW,'M') returns the numeric value of the month for the current time. Any time during the month of March, this function returns 3. This numeric value nicely coincides with the index value for the March element in the Month dimension. (For complete details on all TM1 rules functions, see Appendix A of this book or refer to the TM1 online help.) You can now fine-tune the single calculation statement in the rule for the Plan cube so that values for all months before the current month are pulled from the Production cube, while values for the current month and later are calculated in the Plan cube.
7-11
Four Solutions
Table of Contents
Index
Using the TIMVL function eliminates the monthly rule change requirement. This type of solution is appropriate where you are interested in moment-by moment time changes, for example in stock market applications. For a monthly budgeting application, though, this solution is less than ideal because you might want to control the month for which data is queried. After all, most companies do not have all their actuals ready on the first of the month. Also, you might want to set the month back later, to review projections as they appeared on a previous month.
7-12
Four Solutions
Table of Contents
Index
For example, the cube CurrentMonth is comprised of two dimensions, aNumber and aString. Each dimension contains a single element, so the cube contains just a single cell that can accept the name of the month that you want to set as current.
To retrieve this value, you can use the function: DB('CurrentMonth', 'aNumber', 'aString') You can then pass the DB function as an argument to the DIMIX function to determine the index value of the month as follows: DIMIX('MONTH',DB('CurrentMonth', 'aNumber', 'aString')) This returns the index of the month in the CurrentMonth cube.
7-13
Four Solutions
Table of Contents
Index
You can now further refine the rule statement to incorporate this reference to the CurrentMonth cube.
This statement says that if the month index for the Planned Production Qty Kgs value being requested is less than the index of the month contained in the CurentMonth cube, retrieve the value from the Production cube, otherwise calculate the value by multiplying the Planned Production Qty -Kgs value of the previous month by the Adj. % from last month.
7-14
Four Solutions
Table of Contents
Index
When the string in the CurrentMonth cube is March, the Plan cube pulls Planned Production Qty values for January and February from the Production cube, then calculates all other values directly in the Plan cube.
You can now control the calculation of values in the Plan cube by changing the string in the CurrentMonth cube, which is part of the sample data for this guide.
7-15
Four Solutions
Table of Contents
Index
When you change the string in the CurrentMonth cube to June, the Plan cube pulls Planned Production Qty values for January through May from the Production cube, then calculates all other values directly in the Plan cube.
This solution satisfies all the requirements of a well-written rule. It uses only one rule statement for all months, and it makes it unnecessary for you or other users to edit the statement on a regular basis. Additionally, this solution allows you or other users to set the current month as required. Creating the Calculation Statement for Planned Production Qty - Kgs To create the calculation statement that determines the value of Planned Production Qty -Kgs: 1. Right-click the Plan cube in the Server Explorer.
7-16 TM1 Rules Guide
Four Solutions
Table of Contents
Index
2. Choose Edit Rule. 3. Insert a # character at the beginning of the existing calculation statement for ['Planned Production Qty - Kgs']. 4. Enter the following calculation statement below the last existing calcluation statement in the Rules Editor. ['Planned Production Qty - Kgs'] = IF (DIMIX('Month',!Month) < DIMIX('Month',DB('CurrentMonth','aNumber','aString')), DB('Production',!CakeType,!Month,'Quantity Produced - Kgs'), DB('Plan',!CakeType, DIMNM('Month',(DIMIX('Month',!Month) -1) ),'Planned Production Qty - Kgs')* ['Adj. % from last month']); 5. Click Save. You can open the Salty Cake view of the Plan cube to see the result of the statement.
7-17
Four Solutions
Table of Contents
Index
Note that the values in this view vary depending on the month specified in the CurrentMonth cube. The above view reflects values when the CurrentMonth cube contains the string June. All Planned Production Qty - Kgs values for months prior to june are retrieved from the Production cube. All other Planned Production Qty - Kgs values are calculated by applying the Adj. % from last month to the previous monthly value.
7-18
Table of Contents
Index
Hard-Coded Feeders
Recall that the first attempt to create rules for the Plan cube in this chapter used sequential statements with hard-coded month names. Analogous to those rules statements would be a set of feeders in the Plan rule as follows: FEEDERS; ['February','Planned Production Qty - Kgs']=>['March','Planned Production Qty - Kgs']; ['March', 'Planned Production Qty - Kgs']=>['April', 'Planned Production Qty - Kgs']; ['April', 'Planned Production Qty - Kgs'] => ['May', 'Planned Production Qty - Kgs']; ['May', 'Planned Production Qty - Kgs'] => ['June','Planned Production Qty - Kgs']; ['June','Planned Production Qty - Kgs'] => ['July','Planned Production Qty - Kgs']; . . . and so on until all months are fed. The Produce cube would also require statements to feed January and February values in the Plan cube:
Rules for Time-Based Calculations 7-19
Table of Contents
Index
FEEDERS; ['January','Planned Production Qty -Kgs']=>DB('Plan', !caketype, 'January', 'Planned Production Qty -Kgs'); ['February','Planned Production Qty -Kgs']=>DB('Plan', !caketype, 'February', 'Planned Production Qty -Kgs'); Like the calculation statements they accompany, the drawback to the above feeder statements is that they must be must be edited each month. As you proceed from month to month, the top feeder statement in the rules for the Plan cube must be deleted and a new statement must be added to the feeders for the Production cube, reflecting the fact that new monthly values are being pulled into the Plan cube from the Production cube. It is worth noting, however, that this method has a significant advantage as well: the feeders are very precise with no overfeeding at all. In very large, sparse, calculation-intensive applications, feeders like this may produce significant performance improvement.
Deliberate Overfeeding
At the risk of possible massive overfeeding, you can reduce the number of feeder statements by simply feeding the entire Month dimension with one feeder statement in the rule for the Plan cube: ['Planned Production Qty - Kgs'] => ['Planned Production Qty - Kgs', 'Total Year']; Feeding the consolidated element Total Year feeds all of its components; thus any value for Planned Production Qty - Kgs in any month will feed all the rest of the months. In a small, dense cube like the Plan cube, the effect of overfeeding may well be negligible; and such a feeder has the great advantage of being very simple.
7-20
Table of Contents
Index
7-21
Table of Contents
Index
The feeder would feed Q1 from December, Q2 from Q1 and so on through Total Year. Keeping in mind that feeding consolidated elements feeds all their components, this statement ends up feeding the entire cube. One way to solve the probles evident with this feeder is to incorporate an IF function so that when the index value for the current Month element is less than 12, the following month is fed, otherwise December is fed. ['Planned Production Qty -Kgs'] =>DB('Plan', !CakeType, IF(DIMIX('month',!Month) < 12, DNEXT('Month',!Month), 'December'), 'Planned Production Qty -Kgs'); If there is sparse data in the Plan cube, this feeder significantly reduces overfeeding relative to the feeder statements considered previously. This feeder has the additional benefit of never feeding any element beyond
7-22
Table of Contents
Index
December, thus avoiding the possibility of attempting to feed a non-existent element. Creating the Feeder Statement to Feed Planned Production Qty -Kgs To create the feeder statement that feeds Planned Production Qty -Kgs in the Plan cube: 1. Double-click the Plan cube in the Server Explorer. 2. If it does not already exist, insert a SKIPCHECK; declaration immediately preceding the single calculation statement in the rule. 3. Insert a FEEDERS; declaration following the calculation statement. 4. Enter the following feeder statement immediately following the FEEDERS; declaration: ['Planned Production Qty -Kgs'] =>DB('Plan', !CakeType, IF(DIMIX('month',!Month) < 12, DNEXT('Month',!Month), 'December'), 'Planned Production Qty - Kgs'); The complete rule for the Plan cube should now appear as follows:
7-23
Table of Contents
Index
5. Click Save.
7-24
Table of Contents
Index
8 Fixed Allocations
Fishcakes International wants to know the true input costs of each of its fishcakes every day. This is not a simple matter, though, since each fishcake uses fish of various types from different markets, with different prices every day. Sometimes fish is used several days after it is purchased. The company has all the information it needs to calculate these costs. As you saw in earlier chapters, the company has a complete record of fish purchases. Further, the Production cube contains information on the amount of each type of fishcake produced each day. The challenge is to allocate quantities of fish to the production of individual fishcake types. Once this is accomplished, you can then allocate costs to fishcakes, as you will in the final chapter of this guide.
Fixed Allocations
8-1
Table of Contents
Index
Ingredients is a two-dimensional cube that stores the percentage of each fish type used in the composition of fishcakes produced by Fishcakes International. For example, the following view of the Ingredients cube shows that the composition of the Ancient Mariner fishcake is 26% cod, 30% pollack, 10% trout, 10% herring, and 24% hake.
8-2 TM1 Rules Guide
Table of Contents
Index
The FishRequired cube is a workspace where the amount of fish going into each fishcake is calculated. (This cube will later be used to calculate the materials cost of each fishcake.) Its dimensions are CakeType, FishType, Date and FishRequiredMeasures. The only measure youll work with here is Qty Required - Kgs. In the FishRequired cube, Qty Required - Kgs varies by fishcake type, fish type and date. For example, the following view shows the amount of flounder required in the production of several different cake types on January 20.
Fixed Allocations
8-3
Table of Contents
Index
To correctly calculate the amount of each fish type required for a given fishcake type on a given day, you need to create a calculation statement for the FishRequired cube that multiplies the amount of each cake type produced (from the Production cube) by the percentage of each fish used in the cake type (from the Ingredients cube). The statement that calculates Qty Required - Kgs values for the FishRequired cube therefore looks like this: ['Qty Required - Kgs']=N:DB('Production',!CakeType,!Date,'Quantity Produced - Kgs') * DB('Ingredients',!CakeType,!FishType);
8-4
Table of Contents
Index
2. Select Create Rule. The Rules Editor opens. 3. Enter the above calculation statement on the first line of the Rules Editor. 4. Click Save to save the rule. If the TM1 server receives a request for the quantity (in Kgs) of flounder required to make Surf Platter fish cakes on January 20th, the rule calculates as follows.
70 * 20% = 14
Total quantity (Kgs) of flounder required to produce Surf Platter cakes on Jan. 20
You can open the Flounder required - Jan 20 view of the Fish Required cube to confirm that the statement calculates Qty Required - Kgs values.
Fixed Allocations
8-5
Table of Contents
Index
8-6
Table of Contents
Index
6. Enter the above feeder statement on a new line following the existing feeder statement. The feeders for the Production rule should now appear as follows.
7. Click Save to save the Production rule. This new feeder overfeeds the FishType dimension, because feeding Total also feeds all FishTypes elements for every CakeType produced on a given date. This is not uncommon when feeding from one cube to another, because the dimensionality of the target cube is typically greater than that of the source cube. In this example, the target cube FishRequired has the additional FishType dimension that is not part of the Production cube. In such a situation, overfeeding is inevitable.
Fixed Allocations
8-7
Table of Contents
Index
8-8
9-1
Table of Contents
Index
Required amount of fish for the day. The model attempts to satisfy this amount from the oldest inventory in stock.
The spreadsheet works this way: 1. Starting with the required amount of fish for the day (cell B6, which is referenced by cell D10), the model tries to satisfy the requirement using available fish, starting with the oldest fish. 2. The oldest fish available is 3 days old. The quantity available is 10.25 Kgs (cell E13), which is less than the quantity required, so the model uses all 10.25 Kgs (cell F13).
9-2 TM1 Rules Guide
Table of Contents
Index
3. The model subtracts the quantity used from the quantity required and determines that 33.13 Kgs (cell H13) are still required. 4. The model then moves to the 2 days old batch of fish. The quantity still required from the 3 days old batch becomes the current required quantity (cell D14)for the 2 days old batch. 5. The quantity available from the 2 days old batch is 39 Kgs (cell E14), which is greater than the quantity required, so the model uses only the quantity required (cell F14). 6. The model subtracts the quantity used from the quantity required and determines that 0 Kgs (cell H14) are still required. 7. The depletion is complete. The model has successfully satisfied the requirements for 43.38 Kgs of trout on Jan. 10 by depleting inventory from the oldest available batches of fish. 8. The quantity of 2 days old trout remaining after depletion (5.87 Kgs, cell G14) will become the available quantity of 3 days old trout on Jan. 11.
9-3
Table of Contents
Index
This is a single number for any fish type on any date. For example the total need for sole on January 1 is 30 Kgs. This rule statement puts that amount into the Depletion cube as the amount of sole required from DaysOld batch 6. As you further develop rules for the Depletion cube, youll then take as much sole as possible from DaysOld batch 6 (6 day-old fish). If batch 6 cannot satisfy the requirements for sole, youll then turn to DaysOld batch 5, and so on, from oldest to newest until the daily requirement is met. The plan also requires that you create a rule statement for the Depletion cube that establishes available amounts of fish from the Inventory cube: ['Available']=DB('Inventory',!FishType,!Date,!DaysOld,'Quantity in Stock - Kgs'); The Fishcakes International model keeps inventory batched by age with a DaysOld dimension, so the statement pulls in values for six separate batches of fish, by age. For example, available Herring on Jan. 1 falls into six batches: 20 kilos - 6 days old, 14 kilos - 5 days old, 10 kilos - 4 days old, 10 kilos - 3 days old, 84 kilos - 2 days old and 0 kilos - 1 day old. Now you can create a statement that calculates the amount of each batch of fish that should be used to satisfy the required amount: ['Used'] = N:IF( ['Available'] >= ['Required'], ['Required'], ['Available']); In English, this statement says if whats available is greater than or equal to whats required, then take whats required; otherwise take whats available. The calculation of amounts remaining and amounts still required is a matter of subtraction. This subtraction is accomplished through the use of element weights in consolidations found in the DepletionMeasures dimension. For example, by applying a weight of -1 to the Used element in the Remaining consolidation, the value of the Remaining consolidation is calculated by subtracting the value of Used from the value of Available.
9-4
Table of Contents
Index
But you still dont have a Required amount for the DaysOld batches less than 6. The amount required when the model gets to the 5-day old fish is the amount still required after using all available 6-day-old fish; similarly, the amount required of 4-day old fish is the amount still required after using up 5day-old fish, and so on. The statement to calculate required amounts is ['Required']=N:DB('Depletion',!FishType,!Date,DNEXT('DaysOld', !DaysOld), 'Still Required'); The complete rule statements for the Depletion cube now look like this: ['6','Required']=DB('FishRequired','Total Fish Cake Types',!FishType,!Date,'Qty Required - Kgs'); ['Available']=DB('Inventory',!FishType,!Date,!DaysOld,'Quantity in Stock - Kgs'); ['Used']=N:IF(['Available'] >= ['Required'], ['Required'], ['Available']); ['Required']=N:DB('Depletion',!FishType,!Date,DNEXT('DaysOld', !DaysOld), 'Still Required'); Note how the rule for ['6','Required'] comes before the rule for ['Required']. This is in keeping with the practice of placing rules statements in order from mostrestrictive area definition to least-restrictive area definition. To create the rule for the Depletion cube:
Stocks and Flows 9-5
Table of Contents
Index
1. Right-click the Depletion cube in the Server Explorer. 2. Select Create Rule. The Rules Editor appears. 3. Enter the above statements in the Rules Editor. 4. When you are done, the Rules Editor should appear as follows.
5. Click Save to compile and save the rule. Note that the rule does not include a SKIPCHECK; declaration. Youll add this declaration later when you develop feeders for the rule. Now open the Trout view of the Depletion cube to understand the execution of the rule. All values in the Trout view are derived through the rules you just created.
9-6
Table of Contents
Index
1. As you can see, TM1 has determined that the amount of trout required on Jan. 10 is 43.38 Kgs. This value is derived by the statement ['6','Required']=DB('FishRequired','Total Fish Cake Types',!FishType,!Date,'Qty Required - Kgs'), which pulls the value 43.38 from the FishRequired cube. TM1 first attempts satisfy this requirement from the DaysOld batch 6. 2. For the given DaysOld batch, the TM1 server then uses the statement ['Available']=DB('Inventory',!FishType,!Date,!DaysOld,'Quantity in Stock Kgs') to determine the amount of trout available. 3. For the given DaysOld batch, the statement ['Used']=N:IF(['Available'] >= ['Required'], ['Required'], ['Available']) calculates the amount of trout used. When the amount available is greater than or equal to the amount required, only the amount required is used; otherwise, the amount available is used.
9-7
Table of Contents
Index
4. The value for the Remaining consolidation is defined as Available minus Used in the DepletionMeasures dimension.
5. The value for the Still Required consolidation is defined as Required minus Used in the DepletionMeasures dimension.
6. The TM1 server then uses the statement['Required']=N:DB('Depletion',!FishType,!Date,DNEXT('DaysOld', !DaysOld), 'Still Required') to determine the amount of trout required from the next DaysOld batch. TM1 can now perform all the calculations necessary to satisfy the required amount of trout by depleting inventory from the oldest available batches of fish. Youre almost done with the rules required to complete the depletion model. All thats left is to create a statement that takes any remaining amount for a given DaysOld batch and moves it into inventory for the following day, while also incrementing the DaysOld age of the batch by 1. This statement must reside in the rules for the Inventory cube. The following statement accomplishes the goal. ['Quantity in Stock - Kgs']= N: IF(DIMIX('Date', !Date) = 1, 0, DB('Depletion',!FishType,DIMNM('Date', DIMIX('Date', !Date) -1), DIMNM('DaysOld', DIMIX( 'DaysOld', !DaysOld) -1),'Remaining'));
9-8
Table of Contents
Index
This rules say if the current date is the first date in the Date dimension, then Quantity in Stock - Kgs is 0; otherwise Quantity in Stock - Kgs is equal to yesterdays Remaining value from the Depletion cube for the immediately previous DaysOld batch. As the following view of the Inventory cube shows, the above rule statement results in a diagonal pattern of numbers, as quantities are carried over from one day to the next day, but aging one day in the process. You can see how this statement works in the following image.
After depletion, the remaining amount of 2 day-old cod on Jan 10 is 5.87 Kgs. The statement brings this value into the Inventory cube as the Quantity in Stock - Kgs of 3 day-old cod on Jan.11. The value is then carried over from one day to the next day, but aging one day in the process, resulting in the diagonal pattern shown in the Inventory cube.
9-9
Table of Contents
Index
To add this statement to the Inventory cube: 1. Double-click the Inventory cube in the Server Explorer. The Rules Editor appears. 2. Enter the above statement on a new line in the Rules Editor. 3. When you are done, the rule for the Inventory cube should appear as follows.
9-10
Table of Contents
Index
First, you must add a SKIPCHECK statement to the beginning of the rule for the Depletion cube. 1. Double-click the Depletion rule in the Server Explorer. 2. Insert the SKIPCHECK; statement on the first line of the Rules Editor. 3. Click Save to save the rule. Recall that the rule for the Depletion cube is comprised of the following statements: ['6','Required']=DB('FishRequired','Total Fish Cake Types',!FishType,!Date,'Qty Required - Kgs'); ['Available']=DB('Inventory',!FishType,!Date,!DaysOld,'Quantity in Stock - Kgs'); ['Used']=N:IF(['Available'] >= ['Required'], ['Required'], ['Available']); ['Required']=N:DB('Depletion',!FishType,!Date,DNEXT('DaysOld', !DaysOld), 'Still Required');
9-11
Table of Contents
Index
3. Add the following statement immediately following the FEEDERS; declaration. ['Total Fish Cake Types','Qty Required - Kgs']=>DB('Depletion',!fishtype,!date,'6','Required'); The FishRequired rule should now appear as follows:
9-12
Table of Contents
Index
To add this statement to the rule for the Inventory cube: 1. Double-click the Inventory rule in the Server Explorer. 2. Add the above feeder immediately following the existing feeders statements in the rule. The Inventory rule should now appear as follows:
9-13
Table of Contents
Index
The statement that calculates Used values references both Required and Available values: ['Used']=N:IF(['Available'] >= ['Required'], ['Required'], ['Available']); You might be tempted to write the following feeders to accompany this calculation statement: ['Required']=>['Used']; ['Available']=>['Used']; However, for all instances where fish is used, fish is necessarily both required and available.Therefore, you only need to feed Used once, with either Required or Available. If you arbitrarily choose Available, you arrive at the feeder statement: ['Available']=>['Used']; You can now add this feeder statement to the rule for the Depletion cube. 1. Double-click the Depletion rule in the Server Explorer. 2. Insert a FEEDERS; declaration on a line below the existing rule statements in the Rules Editor. 3. Add the above feeder immediately following the FEEDERS; declaration. 4. Click Save to save and compile the rule. Now you must create feeders for the rule statement that calculates the value of Required. ['Required']=N:DB('Depletion',!FishType,!Date,DNEXT('DaysOld', !DaysOld), 'Still Required'); This statement calculates the Required value for a given DaysOld batch based on the Still Required value of the next-oldest DaysOld batch. And remember, this statement calculates Required values for all DaysOld batches except batch
9-14 TM1 Rules Guide
Table of Contents
Index
6. (A separate rule calculates Required values for DaysOld batch 6.) Accordingly, you do not need to feed the area [6, Required]. If there were a large number of elements in the DaysOld dimension you might want to create a single, complex feeder statement that incorporates a series of TM1 rules functions. However, the DaysOld dimension is exceptionally small, so the easiest way to create and maintain the required feeders is to write a separate feeder statement for each area that needs to be fed: ['6', 'Still required']=>['5', 'Required']; ['5', 'Still required']=>['4', 'Required']; ['4', 'Still required']=>['3', 'Required']; ['3', 'Still required']=>['2', 'Required']; ['2', 'Still required']=>['1', 'Required']; You can now add these feeder statements to the rule for the Depletion cube. 1. Double-click the Depletion rule in the Server Explorer. 2. Add the above feeder statements immediately following the existing feeders in the rule. 3. Click Save to save and compile the rule.
Feeding the Calculation for Quantity in Stock - Kgs in the Inventory Cube
The rule for the Inventory cube includes a calculation statement that calculates Quantity in Stock - Kgs based on Remaining values in the Depletion cube. ['Quantity in Stock - Kgs']= N: IF(DIMIX('Date', !Date) = 1, 0, DB('Depletion',!FishType,DIMNM('Date', DIMIX('Date', !Date) -1), DIMNM('DaysOld', DIMIX( 'DaysOld', !DaysOld) -1),'Remaining'));
9-15
Table of Contents
Index
You could use the following feeder to feed Quantity in Stock - Kgs in the Inventory cube: ['Remaining']=>DB('Inventory', !FishType, DNEXT('Date',!Date), DNEXT('DaysOld',!DaysOld), 'Quantity in Stock - Kgs'); However, as you recall from earlier chapters, the DNEXT function will cycle through an entire dimension, feeding both leaf and consolidated elements, resulting in massive overfeeding. TM1 does include a rules function, DTYPE, that lets you determine the type of an element. The function, which is described in detail in Appendix A of this book, returns a single-character string: N for leaf (or numeric) elements, C for consolidated elements, and S for string elements. You can use this function in a feeder statement to determine the type of the current element and to feed only N type elements, as in the following feeder. ['Remaining']=>DB('Inventory', !FishType, IF( DTYPE('DATE', DNEXT('Date',!Date) ) @= 'N', DNEXT('Date',!Date),'Dec-31' ), IF(DTYPE( 'DaysOld', DNEXT('DaysOld',!DaysOld) ) @= 'N',DNEXT('DaysOld', !DaysOld),'1' ), 'Quantity in Stock - Kgs'); NOTE: The @ symbol is the string comparison operator, as described in Chapter 1 of this book. The first IF statement says if the type of the next element in the Date dimension is N, use the next element; otherwise, use Dec-31. The second IF statement says if the type of the next element in the DaysOld dimension is N, use the next element; otherwise use 1. The result of these IF statements is that the feeder never feeds a consolidated element, but instead feeds either Dec-31 (Date element) or 1 (DaysOld element) when a consolidated element is encountered. This yields some minor
9-16
Table of Contents
Index
overfeeding, but nothing of the magnitude that would result from feeding all the consolidated elements in the Date dimension. You can now add the above statement to the feeders for the Depletion rule. 1. Double-click the Depletion rule in the Server Explorer. 2. Add the above feeder immediately following the existing feeders statement in the rule. 3. Click Save to save and compile the rule.
9-17
Table of Contents
Index
9-18
Table of Contents
Index
9-19
Table of Contents
Index
9-20
10-1
Table of Contents
Index
10-2
Table of Contents
Index
An IF statement is required because on the first day of the year there is no fish that is more than one day old and because the formula references the value of Average Purchase Price/Kg for fish on the previous day, which is undefined for the first day of the year. (Recall that the rule for the Inventory cube already includes the statement ['1','Average Purchase Price/Kg'] = N: ['Purchase Cost'] \ ['Quantity in Stock - Kgs'], which calculates the value of Average Purchase Price/Kg for fish in DaysOld batch 1, even on the first day of the year.) To add the statement to calculate Average Purchase Price/Kg to the Inventory rule: 1. Double-click the Inventory rule in the Server Explorer. 2. Add the statement ['Average Purchase Price/Kg'] = IF(DIMIX('Date',!Date) = 1, 0, DB('Inventory',!FishType, DIMNM('Date', DIMIX('Date', !Date) -1), DIMNM('DaysOld', DIMIX('DaysOld', !DaysOld) -1), 'Average Purchase Price/Kg')); immediately following the last calculation statement in the rule. 3. Click Save to save and compile the rule. Values for Average Purchase Price/Kg now travel with each batch of fish as it ages:
10-3
Table of Contents
Index
As this view shows, the value of Average Purchase Price/Kg for trout in DaysOld batch 1 on April 30 becomes the value for DaysOld batch 2 on May 1. This value then travels to DaysOld batch 3 on May 2, then DaysOld batch 4 on May 3, and so on.
10-4
Table of Contents
Index
cube. Accordingly, the above statement applies only to DaysOld batches 2 through 6.) To add the statement to calculate Purchase Cost to the Inventory rule: 1. Double-click the Inventory rule in the Server Explorer. 2. Add the above statement immediately following the last calculation statement in the rule. 3. Click Save to save and compile the rule. As the following view shows, the statement calculates Purchase Cost values.
Table of Contents
Index
matter of subtraction to determine the value for Cost of Fish Used. Specifically, the Cost of Fish Used for any given date and DaysOld batch is determined by subtracting the Purchase Cost for the following date and DaysOld batch from the current date and DaysOld batch. This sounds slightly confusing, so consider the following view of the Inventory cube. Remember that a batch of fish ages as days progress, so DaysOld batch 3 on May 2 becomes DaysOld batch 4 on May 3.
Here you see that the Purchase Cost of trout in DaysOld batch 3 on May 2 is $9,070.25. The quantity in stock is 46.88 Kgs. (Note that Purchase Cost and Quantity in Stock - Kgs are measures of fish at the beginning of the day.) The Purchase Cost of trout in DaysOld batch 4 on May 3 is $3,878.96, and the quantity in stock is 20.05 Kgs. Because both Purchase Cost and Quantity in Stock are reduced at the start of the day on May 3, you can surmise that some trout was used to make fishcakes on May 2.
10-6 TM1 Rules Guide
Table of Contents
Index
You can determine the cost of trout used on May 2 by subtracting the Purchase Cost value of trout in DaysOld batch 4 on May 3 from the Purchase Cost value of trout in DaysOld batch 3 on May 2. $9,070.25 - $3,878.96 = $5,191.29 If you refer back to the above view, you see that $5,191.29 is indeed the Cost of Fish Used for DaysOld batch 3 on May 2. The rule statement required to calculate this value is ['Cost of Fish Used']=N:DB('Inventory',!FishType,!Date,!DaysOld,'Purchase Cost') DB('Inventory',!FishType,DNEXT('Date', !Date),DNEXT('DaysOld', !DaysOld),'Purchase Cost'); Calculating the Cost of Fish Used for DaysOld batch 6 requires a different rule statement, because there is no batch after 6. Once a batch of fish is 6 days old, it is (thankfully) removed from inventory and the entire purchase cost of the batch is charged to the cost of fish used. The following statement accomplishes this calculation. ['6','Cost of Fish Used']=['Purchase Cost']; Recall that rules statements should always be ordered most-restrictive to leastrestrictive according to area definition. In this case, the area ['6','Cost of Fish Used'] is more restrictive than the area ['Cost of Fish Used'], so the statements should appear in the following order: ['6','Cost of Fish Used']=['Purchase Cost']; ['Cost of Fish Used']=N:DB('Inventory',!FishType,!Date,!DaysOld,'Purchase Cost') - DB('Inventory',!FishType,DNEXT('Date', !Date), DNEXT('DaysOld', !DaysOld),'Purchase Cost'); To add these statements to the rule for the Inventory cube:
10-7
Table of Contents
Index
1. Double-click the Inventory rule in the Server Explorer. 2. Add the above statements immediately following the last calculation statement in the rule. The statements must be in the order they appear above. 3. Click Save to save and compile the rule.
Required Feeders
The rules statements youve just created for the Inventory cube require just one new feeder statement, feeding Average Purchase Price/Kg and Cost of Fish Used: ['Purchase Cost']=>['Average Purchase Price/Kg'],['Cost of Fish Used']; Note that this single feeder statement feeds two elements, with each element separated by a comma. You can now add this feeder statement to the rule for the Inventory cube. 1. Double-click the Inventory rule in the Server Explorer. 2. Add the above feeder statements immediately following the last feeder statement in the rule. The complete rule for the Inventory cube should now appear as follows:
10-8
Table of Contents
Index
10-9
Table of Contents
Index
Now if you open the Cost of trout used view of the Inventory cube, you can see the complete effect of the rules that calculate daily costs.
The Purchase Cost of trout in DaysOld batch 1 on April 30 is calculated by the statement
['1','Purchase Cost'] = N:DB('Purchase',!FishType,'Total Markets',!Date,'Purchase Cost - USD').
The Purchase Cost of trout in DaysOld batch 2 on May 1 is calculated by the statement ['Purchase Cost']=N:['Average Purchase Price/Kg'] *['Quantity in Stock - Kgs']. All subsequent Purchase Cost values highlighted in the view are calulated by this statement.
10-10 TM1 Rules Guide
Table of Contents
Index
The Cost of Fish Used for this batch and day is calculated by the statement ['Cost of Fish Used']=N:DB('Inventory',!FishType,!Date,!DaysOld,'Purchase Cost') DB('Inventory',!FishType,DNEXT('Date', !Date),DNEXT('DaysOld', !DaysOld),'Purchase Cost'). This statement subtracts the value of Purchase Cost for DaysOld batch 3 on May 2 ($9,070.25) from the value for DaysOld batch 2 on May 1 ($9,479.75), returning $409.50. The Cost of Fish Used for DaysOld batch 3 on May 2 is calculated in the same manner. In this case, the statement subtracts the value of Purchase Cost for DaysOld batch 4 on May 3 ($3,878.96) from the value for DaysOld batch 3 on May 2 ($9,070.25), returning $5,191.29. Purchase Cost and Cost of Fish Used remain unchanged for batches 4 and 5 on May 3 and May 4, respectively. At the end of the day on May 6, any unused trout in DaysOld batch 6 is discarded and the entire purchase cost of the fish in the batch is charged to the cost of fish used. The statement ['6','Cost of Fish Used']=['Purchase Cost'] derives the Cost of Fish Used for batch 6 from the current Purchase Cost of the batch.
10-11
Table of Contents
Index
This total cost needs to be broken down and allocated to individual fishcake types depending on the quantity of trout used in each fishcake on April 30. You can accomplish this with a statement in the rule for the FishRequired cube: ['Cost']=DB('Inventory',!fishtype,!date,'DaysOld Total','Cost of Fish Used') * ['Qty Required - Kgs'] \ ['Total Fish Cake Types','Qty Required - Kgs']; This statement says that for any given fish type on any given date, the allocated cost of that fish for any given fishcake type is calculated by
10-12 TM1 Rules Guide
Table of Contents
Index
multiplying the total cost of fish used in the Inventory cube by the quantity of the fish required in the FishRequired cube, then dividing that product by the total quantity of the fish required by all fishcake types. A bit later in this chapter youll see a full illustration of how this statement works. You can now add the above statement to the rules for the FishRequired cube: 1. Double-click the FishRequired rule in the Server Explorer. 2. Add the above statement immediately following the last calculation statement in the rule. The rule for the FishRequired cube should now appear as follows:
10-13
Table of Contents
Index
Required Feeder
The above statement calculates the value of Cost in the Fish Required cube based on the value of Cost of Fish Used in the Inventory cube. Accordingly, the following feeder belongs in the Inventory cube. ['Cost of Fish Used']=>DB('FishRequired','Total Fish Cake Types',!FishType,!Date,'Cost'); You can now add this feeder statement to the rules for the Inventory cube: 1. Double-click the Inventory rule in the Server Explorer. 2. Add the above statement immediately following the last feeder statement in the rule. 3. Click Save to compile and save the rule.
10-14
Table of Contents
Index
Here you can see the following values: Total cost of trout used on Apr. 30 $8,585.39 (DaysOld Total from the Cost of trout used - Apr 30 view) Quantity of trout required for the Poseidons Platter fishcake on Apr. 30 20 Kgs Quantity of trout required for all fishcake types on Apr. 30 40.33 Kgs
10-15
Table of Contents
Index
TM1 applies these values to the new calculation statement to determine the allocated cost of trout used in Poseidons Platter fishcakes on Apr. 30: ['Cost'] = $8,585.39 x 20 / 40.33 This yields an allocated cost $4,257.22 for trout used in Poseidons Platter fishcakes on Apr. 30, as shown in the highlighted cell of the Trout required Apr 30 view. If you take the time to manually perform the calculation above youll find that $8,585.39 x 20 / 40.33 = $4,257.57. So why does the Trout required - Apr 30 view report a value of $4,257.22? Because the views above use formatting that only shows two decimal places for values, while the complete values use up to four decimal places. Specifically, the complete value of total cost of trout used on Apr. 30 (from the Cost of trout used - Apr 30 view) is $8,585.3875, while the complete value for the quantity of trout required for all fishcake types on Apr. 30 is 40.3333. If you plug these complete values into the calculation, youll find that $8,585.3875 x 20 / 40.3333 = $4,257.2204. Applying two-decimal formatting yields $4,257.22, the value shown in the view above. Regardless of the formatting applied to a view or a dimension element, TM1 always uses the full underlying value when calculating rules.
10-16
Table of Contents
Index
Unlike the FishRequired cube, the Production cube does not include the FishType dimension; it only keeps information about fishcakes, as defined in the CakeType dimension.
Even though the cubes are of differing dimensionality, you can create a rule statement for the Production cube that calculates production costs based on the value of Total Fish Types in the FishRequired cube. ['Production Cost']=DB('FishRequired',!CakeType,'Total Fish Types',!date,'Cost'); This statements says that for a given fishcake type on a given date, the value of Production Cost in the Production cube is equal to the value of Cost for Total Fish Types in the FishRequired cube. In the Production cube, you also want to calculate the cost per kilogram of fishcakes produced. This is accomplished with a rule statement that divides the value of Production Cost by the value of Quantity Produced - Kgs'. ['Production Cost/Kg']=['Production Cost']\['Quantity Produced - Kgs']; You can now add both the above statements to the rule for the Production cube: 1. Double-click the Production rule in the Server Explorer. 2. Insert a SKIPCHECK; statement at the top of the rule.
10-17
Table of Contents
Index
3. Add the above rules statements immediately following the SKIPCHECK; statement. 4. Click Save to save and compile the rule.
Required Feeders
The new calculation statements in the Production cube require two new feeder statements, one in the rule for the FishRequired cube and on in the rule for the Production cube. The calculation statement ['Production Cost']=DB('FishRequired',!CakeType,'Total Fish Types',!date,'Cost'); requires the following feeder in the rule for the FishRequired cube. ['Total Fish Types','Cost']=>DB('Production',!CakeType,!date,'Production Cost'); To add this feeder statement to the rule for the FishRequired cube: 1. Double-click the FishRequired rule in the Server Explorer. 2. Add the above statement immediately following the existing feeder statement in the rule. The complete rule for the FishRequired cube should now look like this:
10-18
Table of Contents
Index
3. Click Save to compile and save the rule. The calculation statement ['Production Cost/Kg']=['Production Cost']\['Quantity Produced - Kgs']; requires a feeder statement in the rule for the Production cube. You can use either Production Cost or Quantity Produced - Kgs to feed Production Cost/Kg. In this example, youll use Quantity Produced - Kgs, a completely arbitrary choice. ['Quantity Produced - Kgs'] => ['Production Cost/Kg']; To add this feeder statement: 1. Double-click the Production rule in the Server Explorer.
Calculating Total Product Costs 10-19
Table of Contents
Index
2. Add the above statement immediately following the existing feeder statement in the rule. The complete rule for the Production cube should now look like this:
Table of Contents
Index
Cost for Total Fish Types in each fishcake in the FishRequired cube becomes the Production Cost for each fishcake in the Production cube.
Here you can see that the Fishcakes International model reaches its conclusion, with final costs for fishcakes calculated in the Production cube. Production Cost for each fishcake is calculated by retrieving the Cost of Total Fish Types for the corresponding fishcake in the FishRequired cube. (In other words, the production cost for a fishcake is equal to the total cost of all fish
10-21
Table of Contents
Index
types that are used to make the fishcake.) Production Cost/Kg for each fishcake is calculated by dividing Production Cost by Quantity Produced - Kgs.
10-22
A Rules Functions
This appendix contains a complete listing of all TM1 rules functions. You can use any of these functions when writing TM1 rules. You can also incorporate all rules functions, with the exception of the STET function, in TurboIntegrator processes.
A-1
ABS
Table of Contents
Index
ABS
ABS returns the absolute value of a number.
Syntax
ABS(x)
Argument
x The number for which you want to find the absolute value.
Example
ABS(-1.2) returns 1.2
A-2
ACOS
Table of Contents
Index
ACOS
ACOS returns the angle, in radians, whose cosine is x.
Syntax
ACOS(x)
Argument
x The cosine of the angle you want to find. x must be between -1 and 1; otherwise the function returns an error.
Example
ACOS(0) returns 1.5708.
A-3
ASIN
Table of Contents
Index
ASIN
ASIN returns the angle, in radians, whose sine is x.
Syntax
ASIN(x)
Argument
x The sine of the angle you want to find. x must be between -1 and 1; otherwise the function returns an error.
Example
ASIN(1) returns 1.5708.
A-4
ATAN
Table of Contents
Index
ATAN
ATAN returns the angle, in radians, whose tangent is x. The result is between pi/2 and +pi/2.
Syntax
ATAN(x)
Argument
x The tangent of the angle you want to find.
Example
ATAN(1) returns .7854.
A-5
ATTRN
Table of Contents
Index
ATTRN
ATTRN returns a numeric attribute for a specified element of a dimension.
Syntax
ATTRN(dimension, element, attribute)
Arguments
dimension element attribute A valid dimension name. An element of the dimension. The attribute for which you want to retrieve a value. This argument must be a valid attribute of the element.
Example
ATTRN('Model', 'L Series 1.8L Sedan', 'Manufacture Code') In this example, the function returns the numeric value of the Manufacture Code attribute of the L Series 1.8L Sedan element in the Model dimension.
A-6
ATTRS
Table of Contents
Index
ATTRS
ATTRS returns a string attribute for a specified element of a dimension.
Syntax
ATTRS(dimension, element, attribute)
Arguments
dimension element attribute A valid dimension name. An element of the dimension. The attribute for which you want to retrieve a value. This argument must be a valid attribute of the element.
Example
ATTRS('Model', 'L Series 1.8L Sedan', 'Manufacture Code') In this example, the function returns the string value of the Manufacture Code attribute of the L Series 1.8L Sedan element in the Model dimension.
A-7
CAPIT
Table of Contents
Index
CAPIT
CAPIT applies initial capitalization to every word in a string.
Syntax
CAPIT(string)
Argument
string A text string.
Example
CAPIT('first quarter sales') returns 'First Quarter Sales'.
A-8
CHAR
Table of Contents
Index
CHAR
CHAR returns the character identified by a given ASCII numeric code.
Syntax
CHAR(number)
Argument
number An ASCII code number. This number must be between 1 and 255, inclusive.
Example
CHAR(100) returns 'd'.
A-9
CODE
Table of Contents
Index
CODE
CODE returns the ASCII numeric code for a specified character within a string.
Syntax
CODE(string, location)
Arguments
string location A text string. A number specifying the character within the string for which you want to find the ASCII code value.
Example
CODE('321', 2) returns 50. CODE('End', 3) returns 100.
A-10
CONTINUE
Table of Contents
Index
CONTINUE
When included as part of a rules expression, this function allows a subsequent rule with the same area definition to be executed. (Normally, TM1 only executes the first rule encountered for a given area.)
Syntax
CONTINUE
Arguments
None.
Example
['Jan']= if(!region @= 'Argentina',10,CONTINUE); ['Jan']=20; In this example, all cells identified by January and Argentina are assigned a value of 10. Cells identified by Jan and any other Region element are assigned a value of 20.
A-11
COS
Table of Contents
Index
COS
COS returns the cosine of an angle expressed in radians.
Syntax
COS(x)
Argument
x An angle, expressed in radians, for which you want to find the cosine.
Example
COS(0) returns 1.
A-12
DATE
Table of Contents
Index
DATE
DATE returns the date string in yy-mm-dd format for a given serial number.
Syntax
DATE(SerialNumber)
Argument
SerialNumber A date expressed in serial format.
Example
DATE(13947) returns '98-03-09'.
A-13
DATES
Table of Contents
Index
DATES
DATES returns a date string, in the form yy-mm-dd', corresponding to a given year, month, and day.
Syntax
DATES(year, month, day)
Arguments
year month day A year, expressed in yy format. A month, expressed in mm format. A day, expressed in dd format.
Example
DATES(98, 2, 10) returns '98-02-10'.
A-14
DAY
Table of Contents
Index
DAY
DAY returns a numeric value for the day in a given date string.
Syntax
DAY(DateString)
Argument
DateString A date string in YY:MM:DD format.
Example
DAY('02:05:25') returns 25.
A-15
DAYNO
Table of Contents
Index
DAYNO
DAYNO returns the serial date number corresponding to a given date string.
Syntax
DAYNO(DateString)
Argument
DateString A date string expressed in yy-mm-dd format.
Example
DAYNO('98-03-09') returns 13947.
A-16
DB
Table of Contents
Index
DB
DB returns a value from a cube in a TM1 database. DB returns a numeric value if used in a numeric expression and a string value if used in a string expression.
Syntax
DB(cube, e1, e2, [...e16])
Arguments
cube e1,en The name of the cube from which to retrieve the value. Dimension element names that define the intersection containing the value to be retrieved. Arguments e1 through en are sequence-sensitive. e1 must be an element from the first dimension of the cube, e2 must be an element from the second dimension, and so on.
Example
DB('Budget', 'California', '15 Flat Panel Monitors', 'Net Sales', 'January') In this example, Budget is the cube name, and the function returns the value at the intersection of California, 15 Flat Panel Monitors, Net Sales, and January.
A-17
DELET
Table of Contents
Index
DELET
DELET returns the result of deleting a specified number of characters from a specified starting point within a string.
Syntax
DELET(string, start, number)
Arguments
string start number A text string. The character at which to begin deletion. The number of characters to delete.
Example
DELET('payment', 3, 3) returns 'pant'.
A-18
DIMIX
Table of Contents
Index
DIMIX
DIMIX returns the index number of an element within a dimension.
Syntax
DIMIX(dimension, element)
Arguments
dimension element A valid dimension name. The name of an element within the dimension. If the element is not a member of the dimension specified, the function returns 0.
Example
DIMIX('Region','Brazil') Brazil has an index value of three in the Region dimension. The example returns 3.
A-19
DIMNM
Table of Contents
Index
DIMNM
DIMNM returns the element of a dimension that corresponds to the index argument.
Syntax
DIMNM(dimension, index)
Arguments
dimension index A valid dimension name. A value less than or equal to the number of elements in the dimension. If this argument is less than 1, or greater than the number of elements in the dimension, the function returns 0.
Example
DIMNM(Region',2) This example returns Belgium, which is the element within the Region dimension with an index value of 2.
A-20
DIMSIZ
Table of Contents
Index
DIMSIZ
DIMSIZ returns the number of elements within a specified dimension.
Syntax
DIMSIZ(dimension)
Argument
dimension A valid dimension name.
Example
DIMSIZ('Accounts') If the dimension Accounts contains 19 elements, the example returns the value 19.
A-21
DNLEV
Table of Contents
Index
DNLEV
DNLEV returns the number levels in a dimension.
Syntax
DNLEV(dimension)
Argument
dimension A valid dimension name.
Example
DNLEV('Region') In the Region dimension, the various countries (Level 0) add up to regions (Level 1). The regions then add up to super-regions (Level 2), which in turn add up to the world (Level 3).
There are four levels in the Region dimension, so the example returns the value 4.
A-22 TM1 Rules Guide
DTYPE
Table of Contents
Index
DTYPE
DTYPE returns information about the element type of a specified element. It returns N if the element is a numeric element, S if the element is a string element, and C if the element is a consolidated element.
Syntax
DTYPE(dimension, element)
Arguments
dimension element A valid dimension name. The name of an element within the dimension.
Example
DTYPE('Region','Europe') The element Europe is a consolidated element of the Region dimension, so the example returns C.
A-23
ELCOMP
Table of Contents
Index
ELCOMP
ELCOMP returns the name of a child of a consolidated element in a specified dimension. If the element argument is not a consolidated element, the function returns 0.
Syntax
ELCOMP(dimension, element, position)
Arguments
dimension element A valid dimension name. The name of a consolidated element within the dimension. A positive value less than or equal to the total number of children in the specified element.
position
Example
ELCOMP('Region','Central Europe',2) In the dimension Region, the consolidated element Central Europe is a consolidation of the children France and Germany. Germany is in the second position in this consolidation. Accordingly, the example returns Germany.
A-24
ELCOMPN
Table of Contents
Index
ELCOMPN
ELCOMPN returns the number of components in a specified element. If the element argument is not a consolidated element, the function returns 0.
Syntax
ELCOMPN(dimension, element)
Arguments
dimension element A valid dimension name. The name of a consolidated element within the dimension.
Example
ELCOMPN(Region,Scandanavia) In the Region dimension, the element Scandanavia is a consolidation of three elements. The example returns 3.
A-25
ELISANC
Table of Contents
Index
ELISANC
ELISANC determines whether element1 is an ancestor of element2 in the specified dimension. The function returns 1 if element1 is an ancestor of element2, otherwise the function returns 0.
Syntax
ELISANC(dimension, element1, element2)
Arguments
dimension element1 element2 A valid dimension name. The name of an element within the dimension. The name of an element within the dimension.
Example
ELISANC('Region', 'Europe', 'Germany') In the dimension Region, the element Europe is an ancestor of Germany. The example returns 1.
A-26
ELISCOMP
Table of Contents
Index
ELISCOMP
ELISCOMP determines whether element1 is a child of element2 in the specified dimension. The function returns 1 if element1 is a child of element2, otherwise the function returns 0.
Syntax
ELISCOMP(dimension, element1, element2)
Arguments
dimension element1 element2 A valid dimension name. The name of an element within the dimension. The name of an element within the dimension.
Example
ELISCOMP('Region','Germany','Central Europe') In the dimension Region, the element Central Europe is a consolidation of two elements, Germany and France. The example returns 1.
A-27
ELISCOMP
Table of Contents
Index
Note that this function returns 1 only for immediate children. In the above example, Germany is a child of Central Europe. Further, Central Europe is a child of Europe. However, because the function returns 1 only for immediate children, the following example returns 0: ELISCOMP('Region','Germany','Europe')
A-28
ELISPAR
Table of Contents
Index
ELISPAR
ELISPAR determines whether element1 is a parent of element2 in the specified dimension. The function returns 1 if element1 is a parent of element2, otherwise the function returns 0.
Syntax
ELISPAR(dimension, element1, element2)
Arguments
dimension element1 element2 A valid dimension name. The name of an element within the dimension. The name of an element within the dimension.
Example
ELISPAR('Region','Central Europe','Germany') In the dimension Region, the consolidated element Central Europe is the parent of both Germany and France. Accordingly, the example returns 1.
A-29
ELISPAR
Table of Contents
Index
Note that this function returns 1 only for immediate parents. In the above example, Europe is a parent of Central Europe. Further, Central Europe is a parent of Germany. However, because Europe is not an immediate parent of Germany, the following example returns 0: ELISPAR('Region','Europe','Germany')
A-30
ELLEV
Table of Contents
Index
ELLEV
ELLEV returns the level of an element within a dimension.
Syntax
ELLEV(dimension, element)
Arguments
dimension element A valid dimension name. The name of an element within the dimension.
Example
ELLEV('Region','Europe') In the Region dimension, individual countries (Level 0) add up to regions (Level 1). The regions then add up to super-regions (Level 2), which in turn add up to the world (Level 3).
ELPAR
Table of Contents
Index
ELPAR
ELPAR returns the parent of an element in a specified dimension
Syntax
ELPAR(dimension, element, index)
Arguments
dimension element index A valid dimension name. The name of an element within the dimension. A positive value less than or equal to the total number of consolidated elements (parents) that use the element argument as a child.
Example
ELPAR('Model','Wagon 4WD',2) In the dimension Model, the element Wagon 4WD is a child of both Total Wagons and Total 4WD. Therefore, both Total Wagons and Total 4WD are parents of Wagon 4WD. In the structure of the Model dimension, Total Wagons is defined first, Total 4WD is defined second. The example returns Total 4WD, as this is the second instance of a parent to Wagon 4WD within the Model dimension.
A-32
ELPARN
Table of Contents
Index
ELPARN
ELPARN returns the number of parents of an element in a specified dimension.
Syntax
ELPARN(dimension, element)
Arguments
dimension element A valid dimension name. The name of an element within the dimension.
Example
ELPARN('Model','Wagon 4WD') In the Model dimension, the element Wagon 4WD is a child of both Total Wagons and Total 4WD. Therefore, both Total Wagons and Total 4WD are parents of Wagon 4WD. The function returns 2.
A-33
ELWEIGHT
Table of Contents
Index
ELWEIGHT
ELWEIGHT returns the weight of a child in a consolidated element.
Syntax
ELWEIGHT(dimension, element1, element2)
Arguments
dimension element1 A valid dimension name. The name of a consolidated element within the dimension. The name of a child of the consolidated element.
element2
Example
ELWEIGHT('Account1','Gross margin','Variable costs') As the following figure shows, the element Variable costs, which is a child of Gross margin, has a weight of -1.
A-34
EXP
Table of Contents
Index
EXP
EXP returns the natural anti-log of a number.
Syntax
EXP(x)
Argument
x A number for which you want to find the natural anti-log.
Example
EXP(1) returns 2.71828.
A-35
FILL
Table of Contents
Index
FILL
FILL repeats a given string as necessary to return a string of a specified length.
Syntax
FILL(string, length)
Arguments
string A text string. This string is repeated as necessary to achieve the specified length. The length of the string you want the function to return.
length
Example
FILL('-', 5) returns '-----'. FILL('ab', 5) returns 'ababa'.
A-36
FV
Table of Contents
Index
FV
FV returns the value of an annuity at the time of the last payment. An annuity is a series of payments made at equal intervals of time. Payments are assumed to be made at the end of each period.
Syntax
FV(payment, interest, periods)
Arguments
payment The amount of the payment made per period. interest periods The interest rate paid per period. The number of periods in the annuity.
Example
FV(1000, .14, 5) This example returns the value of an annuity at the end of 5 years, with payments of $1,000 per year at 14% interest.
A-37
IF
Table of Contents
Index
IF
IF returns one value if a logical expression you specify is TRUE and another value if it is FALSE.
Syntax
IF(expression, true_value, false_value)
Arguments
expression true_value false_value Any value or expression that can be evaluated to TRUE or FALSE. The value that is returned if expression is TRUE. The value that is returned if expression is FALSE.
NOTE: value_true and value_false must be of the same type. When the IF function is used in a numeric expression, true_value and false_value must be numeric. When used in a string expression, true_value and false_value must be strings.
Example
IF(1<2, 4, 5) returns 4. IF(1>2, 'ABC', 'DEF') returns 'DEF'.
A-38
INSRT
Table of Contents
Index
INSRT
INSRT inserts one string into another string at a specified insertion point.
Syntax
INSRT(string1, string2, location)
Arguments
string1 string2 location A text string. A text string. The character in string1 at which you want to insert string2. The function inserts string 2 into string1 immediately prior to the character you specify.
Example
INSRT('ABC', 'DEF', 2) returns 'DABCEF'.
A-39
INT
Table of Contents
Index
INT
INT returns the largest integer that is less than or equal to a specified value.
Syntax
INT(x)
Argument
x A numeric value.
Examples
INT(5.6) returns 5. INT(-5.6) returns -6.
A-40
ISLEAF
Table of Contents
Index
ISLEAF
ISLEAF returns 1 if a specified cell is a leaf cell (identified solely by leaf elements), otherwise it returns 0.
Syntax
ISLEAF(cube, e1, e2, [...e16])
Arguments
cube e1,en The name of the cube containing the cell to be evaluated. Dimension element names that define the cell to be evaluated. Arguments e1 through en are sequence-sensitive. e1 must be an element from the first dimension of the cube, e2 must be an element from the second dimension, and so on.
Example
You can use ISLEAF in an IF statement to test if a current cell is a leaf cell. For example, IF((ISLEAF=1),TrueStatement, FalseStatement); executes the TrueStatement if the current cell is a leaf cell, otherwise it executes the FalseStatement.
A-41
ISUND
Table of Contents
Index
ISUND
ISUND returns 1 if a specified value is undefined; otherwise it returns 0.
Syntax
ISUND(x)
Argument
x A number or expression.
Examples
ISUND(5.2) returns 0. ISUND(1/0) returns 1.
A-42
LN
Table of Contents
Index
LN
LN returns the natural logarithm (base e) of a number.
Syntax
LN(x)
Argument
x A positive number. The function returns an error if x is negative or zero.
Example
LN(10) returns 2.302585093.
A-43
LOG
Table of Contents
Index
LOG
LOG returns the base 10 logarithm of a positive number.
Syntax
LOG(x)
Argument
x A positive number. The function returns an error if x is negative or zero.
Example
LOG(10) returns 1.
A-44
LONG
Table of Contents
Index
LONG
LONG returns the length of a string.
Syntax
LONG(string)
Argument
string A text string.
Example
LONG('Sales') returns 5.
A-45
LOWER
Table of Contents
Index
LOWER
LOWER converts all upper case characters in a string to lower case.
Syntax
LOWER(string)
Argument
string A text string.
Example
LOWER('First Quarter Sales') returns 'first quarter sales'.
A-46
MAX
Table of Contents
Index
MAX
MAX returns the largest number in a pair of values.
Syntax
MAX(num1, num2)
Arguments
num1 num2 The first in a pair of values. The second in a pair of values.
Example
MAX(10, 3) returns 10.
A-47
MIN
Table of Contents
Index
MIN
MIN returns the smallest number in a pair of values.
Syntax
MIN(num1, num2)
Arguments
num1 num2 The first in a pair of values. The second in a pair of values.
Example
MIN(10, 3) returns 3.
A-48
MOD
Table of Contents
Index
MOD
MOD returns the remainder of dividing a number by a divisor.
Syntax
MOD(number, divisor)
Arguments
number divisor The number for which you want to find the remainder. The value by which the number argument is divided.
Example
MOD(10, 3) returns 1.
A-49
MONTH
Table of Contents
Index
MONTH
MONTH returns a numeric value for the month in a given date string.
Syntax
MONTH(date)
Argument
date A date string in YY:MM:DD format.
Example
MONTH('02:05:25') returns 5.
A-50
NOW
Table of Contents
Index
NOW
NOW returns the current date/time value in serial number format.
Syntax
NOW
Arguments
None.
A-51
NUMBR
Table of Contents
Index
NUMBR
NUMBR converts a string to a number.
Syntax
NUMBR(string)
Argument
string The string you want to convert to a number. All characters other than '0' through '9', '+', '-', '.', and 'E' are ignored.
Examples
NUMBR('-5.6') returns -5.6. NUMBR('-5A. B6C') returns -5.6.
A-52
PAYMT
Table of Contents
Index
PAYMT
PAYMT returns the payment amount of an annuity based on a given initial value or principal, an interest rate, and a number of periods. An annuity is a series of payments made at equal intervals of time.
Syntax
PAYMT(principal, interest, periods)
Arguments
principal The present value, or the total amount that a series of future payments is worth now. interest periods The interest rate paid per period. The number of periods in the annuity. Payments are assumed to be made at the end of each period.
Example
PAYMT(100000, .14, 5) This example returns the payment on a 5-year annuity that is paid yearly, with principal of $100,000 at 14% interest.
A-53
PV
Table of Contents
Index
PV
PV returns the initial or principal value of an annuity.
Syntax
PV(payment, interest, periods)
Arguments
payment The amount of the payment made. interest periods The interest rate paid per period. The number of periods in the annuity. Payments are assumed to be made at the end of each period.
Example
PV(1000, .14, 5) This example returns the principal value of an annuity with 5 yearly payments of $1,000 at 14% interest.
A-54
RAND
Table of Contents
Index
RAND
RAND generates a random number that is uniformly distributed between 0 and 1. The random number generator is seeded when TM1 is loaded.
Syntax
RAND
Arguments
None.
A-55
ROUND
Table of Contents
Index
ROUND
ROUND rounds a given number to the nearest integer.
Syntax
ROUND(number)
Argument
number The number you want to round.
Example
ROUND(1.46) returns 1.
A-56
ROUNDP
Table of Contents
Index
ROUNDP
ROUNDP rounds a given number at a specified decimal precision.
Syntax
ROUNDP(number, decimal)
Arguments
number decimal The number you want to round. The decimal precision at which to apply the rounding. If this argument is positive, the function rounds the specified number of digits to the right of the decimal point. If this argument is negative, the function rounds the specified number of digits to the left of the decimal point. The decimal argument must be between -15 and 15, inclusive.
Examples
ROUNDP(1.46, 1) returns 1.5. ROUNDP(1.466, 2) returns 1.47. ROUNDP(234.56, -1) returns 230.00. ROUNDP(234.56, 0) returns 235.00.
A-57
SCAN
Table of Contents
Index
SCAN
SCAN returns a number indicating the starting location of the first occurrence of a specified substring within a given string. If the substring does not occur in the given string, the function returns zero.
Syntax
SCAN(substring, string)
Arguments
substring The substring you are trying to locate. string The string within which you are searching for the substring.
Example
SCAN('scribe', 'described') returns 3.
A-58
SIGN
Table of Contents
Index
SIGN
SIGN determines if a number is positive, negative, or zero. The function returns 1 if the number is positive, -1 if the number is negative, and 0 if the number is zero.
Syntax
SIGN(number)
Argument
number A number.
Example
SIGN(-2.5) returns -1.
A-59
SIN
Table of Contents
Index
SIN
SIN returns the sine of a given angle.
Syntax
SIN(x)
Argument
x A value, expressed in radians, for which you want the sine.
Example
SIN(1.5708) returns 1.
A-60
SQRT
Table of Contents
Index
SQRT
SQRT returns the square root of a given value.
Syntax
SQRT(x)
Argument
x Any positive value. SQRT returns an error if x is negative.
Example
SQRT(16) returns 4.
A-61
STET
Table of Contents
Index
STET
The STET function cancels the effect of a rule for a particular element.
Syntax
STET
Arguments
None.
Example
['Sales'] = IF(!Region @= 'France',STET, 100); In this example, the rule dictates that the value for Sales is always 100, except for the intersection of Sales and the element France from the Region dimension.
A-62
STR
Table of Contents
Index
STR
STR converts a number to a string.
Syntax
STR(number, length, decimal)
Arguments
number length The number being converted to a string. The length of the string. If necessary, the function inserts leading blank spaces to attain this length. The number of decimal places to include in the function result.
decimal
Example
STR(3.14159, 6, 2) returns ' 3.14'. STR(-3.14159, 6, 0) returns ' -3'.
A-63
SUBST
Table of Contents
Index
SUBST
SUBST returns a substring of a given string.
Syntax
SUBST(string, beginning, length)
Arguments
string beginning length The string from which you want to extract the substring. The character at which the substring begins. The length of the substring.
Example
SUBST('Retirement', 3, 4) returns 'tire'.
A-64
TABDIM
Table of Contents
Index
TABDIM
TABDIM returns the dimension name that corresponds to the index argument.
Syntax
TABDIM(cube, index)
Arguments
cube index A valid cube name. A positive value less than or equal to the total number of dimensions in the cube.
Example
TABDIM('SalesCube',3) The cube SalesCube contains five dimensions: account1, actvsbud, model, month, and region. The example returns model, the third dimension of SalesCube.
A-65
TAN
Table of Contents
Index
TAN
TAN returns the tangent of a given angle.
Syntax
TAN(x)
Argument
x A value, expressed in radians, for which you want the tangent.
Examples
TAN(0) returns 0. TAN(.7854) returns 1.
A-66
TIME
Table of Contents
Index
TIME
TIME returns a string, in HH:MM format, representing the system time on the TM1 server.
Syntax
TIME
Arguments
None
Example
Given a system time of 9:33 AM, TIME returns the string '09:33'. Given a system time of 9:33 PM, TIME returns the string '21:33'.
A-67
TIMST
Table of Contents
Index
TIMST
TIMST returns a formatted date/time string.
Syntax
TIMST(datetime, format)
A-68
TIMST
Table of Contents
Index
Arguments
datetime A date/time serial number. The integer part of the number specifies the date, and the decimal part specifies the time within the day. Day number 0 corresponds to '60-01-01'. Negative numbers correspond to prior years. Years in the 21st Century, up to 2059, are represented by years 00 through 59. An hour is 1/24th of a day, a minute 1/60th of an hour, and a second 1/60th of a minute. format A string that formats the result of the function. All the characters in the format argument appear in the result, except for the following characters, which return date/ time component values: \y the last two digits of the year (97, 98, etc.) \Y the four digits of the year (1997, 1997, etc.) \m the two digits of the month (01 through 12) \M the abbreviation of the month (JAN, FEB, etc.) \d the two digits of the day (01 through 31) \D the digit of the day (1 through 31) \h the hour in military time (00 through 23) \H the standard hour (1 through 12) \i the minute (00 through 59) \s the second (00 through 59) \p a.m. or p.m.
Examples
A-69
TIMST
Table of Contents
Index
TIMST(366.0000, '\M \D, \Y') returns 'JAN 1, 1961'. TIMST(366.5000, '\H\p \imin\ssec') returns '12p.m. 00min00sec'. TIMST(366.1000, 'On \M \D, \Y at \H\p \imin\ssec') returns 'On JAN 1, 1961 at 2a.m. 24min00sec'. TIMST(11111.1100, 'On \M \D, \Y at \H\p \imin\ssec') returns 'On JUN 3,1990 at 2a.m. 38min24sec'.
A-70
TIMVL
Table of Contents
Index
TIMVL
TIMVL returns the numeric value of a component (year, month, etc.) of a date/ time value.
Syntax
TIMVL(datetime, type)
A-71
TIMVL
Table of Contents
Index
Arguments
datetime A date/time serial number. The integer part of the number specifies the date, and the decimal part specifies the time within the day. Day number 0 corresponds to '60-01-01.' Negative numbers correspond to prior years. Years in the 21st Century, up to 2059, are represented by years 00 through 59. An hour is 1/24th of a day, a minute 1/60th of an hour, and a second 1/60th of a minute. type A character that specifies the type of component to be extracted. The following are valid type arguments: Y year value (1997, 1998, etc.) M month value (1 through 12) D day value (1 through 31) H hour value (0 through 23) I minute value (00 through 59) S second value (00 through 59)
Examples
TIMVL(11111.1100, 'Y') returns 1990. TIMVL(11111.1100, 'H') returns 2.
A-72
TODAY
Table of Contents
Index
TODAY
TODAY returns the current date in yy-mm-dd format.
Syntax
TODAY
Arguments
None.
A-73
TRIM
Table of Contents
Index
TRIM
TRIM returns the result of trimming any leading and trailing blanks from a string.
Syntax
TRIM(string)
Argument
string A text string.
Example
TRIM(' First Quarter ') returns 'First Quarter'.
A-74
UNDEF
Table of Contents
Index
UNDEF
UNDEF returns the undefined value. This function can be used to prevent data from being stored in a cube based on a logical test.
Syntax
UNDEF
Argument
None.
A-75
UNDEFVALS
Table of Contents
Index
UNDEFVALS
UNDEFVALS allows users to distinguish between data cells that are empty and cells that actually contain a zero. When a rule includes an UNDEFVALS statement, cells containing zeros display the value zero, but empty cells appear blank. This function can also be used to prevent data from being stored in a cube based on a logical test. UNDEFVALS must be the first statement in a rule without a SKIPCHECK statement. If a rule includes a SKIPCHECK statement, the UNDEFVALS statement must be the second statement in the rule.
Syntax
UNDEFVALS
Arguments
None.
A-76
UPPER
Table of Contents
Index
UPPER
UPPER converts a text string to upper case.
Syntax
UPPER(string)
Argument
string A text string.
Example
UPPER('First Quarter Results') returns FIRST QUARTER RESULTS.
A-77
YEAR
Table of Contents
Index
YEAR
YEAR returns a numeric value for the year in a given date string.
Syntax
YEAR(date)
Argument
date A date string in YY:MM:DD format.
Example
YEAR('02:05:25') returns 2.
A-78
Table of Contents
Index
Symbols
& (ampersand) logical operator in rules 1-13 % (percentage sign) logical operator in rules 1-13 ~ (tilde) logical operator in rules 1-13 ATTRN A-6 ATTRS A-7
B
.blb files 1-3
C
calculate on demand 1-17 calculation statements 1-5 area definition 1-5 components of 1-5 formula expressions 1-9 precedence of 1-18 restricting to C level 1-9 restricting to N level 1-8 terminator 1-15 CAPIT A-8 CHAR A-9 CODE A-10 consolidation qualifier 1-8 CONTINUE A-11 CONTINUE function 1-7 COS A-12
A
ABS A-2 ACOS A-3 area definition 1-5 conventions for 1-6 examples 1-6 leaf qualifier 1-8 non-unique element names 1-7 special characters 1-7 string qualifier 1-8 use of CONTINUE function 1-7 using subsets in 1-6 arithemetic operators order of evaluation 1-11 ASIN A-4 ATAN A-5
Index
Table of Contents
DTYPE A-23
E
ELCOMP A-24 ELCOMPN A-25 ELISANC A-26 ELISCOMP A-27 ELISPAR A-29 ELLEV A-31 ELPAR A-32 ELPARN A-33 ELWEIGHT A-34 exchange rates calculating 3-2 EXP A-35
D
DATE A-13 DATES A-14 DAY A-15 DAYNO A-16 DB A-17 DB formula 3-4 DB function 1-15 example 3-13 nested 3-14 DELET A-18 depletion implementing with rules 9-3 spreadsheet example 9-2 Depletion rule calculating Available quantities 9-6 calculating Required quantities 9-6 calculating Used quantities 9-6 feeding Quantity in Stock - Kgs 9-17 feeding Required 9-15 feeding Used 9-14 DIMIX 7-1, 7-7, A-19 DIMNM 7-1, 7-7, A-20 DIMSIZ A-21 DNLEV A-22
F
feeder statements 1-5, 5-5 feeders 5-2, 5-5 and sparsity 5-2 determining need for 5-7 example 5-7 feeding one cube from another 5-10 inter-cube 5-10 overfeeding 5-6 syntax 5-5 troubleshooting 5-14, 5-16 FEEDERS declaration 1-5, 5-6 FILL A-36
Table of Contents
Fishcakes International description 2-1 FishRequired cube 8-2, 10-17 FishRequired rule calculating Cost 10-13 calculating Qty Required - Kgs 8-4 feeding Production Cost 10-18 feeding Required, 6 9-12 fixed allocations 8-1 formula expressions 1-9 arithemtic operators 1-10 comparison operators 1-12 logical operators 1-13 numeric constants 1-10 using conditional logic in 1-11 using cube references in 1-14 functions A-1 FV A-37
Inventory cube 4-2 Inventory rule adding feeders 5-10 calculating average purchase price per kilogram 4-6 calculating Average Purchase Price/Kg 10-3 calculating Cost of Fish Used 10-8 calculating Purchase Cost 10-5 calculating purchase cost 4-6 calculating quantity in stock 4-6 Calculating Quantity in Stock - Kgs 9-10 feeding Average Purchase Price/Kg 10-8 feeding Available 9-13 feeding Cost 10-14 feeding Cost of Fish Used 10-8 ISLEAF A-41 ISUND A-42
L
leaf qualifier 1-8 LN A-43 LOG A-44 LONG A-45 lookup cubes 3-11 LOWER A-46
H
hard-coded feeders 7-19
I
IF A-38 IF function 1-11 Ingredients cube 8-2 INSRT A-39 INT A-40 inter-cube feeders 5-10
M
MarketExchange cube 3-4 MAX A-47 MIN A-48
Index 3
Table of Contents
adding feeders 5-8 calculating prices in U.S. dollars 3-4, 3-8, 3-18 PV A-54
N
NOW A-51 NUMBR A-52
R
.rux files 1-3 RAND A-55 Reference to Cube dialog box 2-9 ROUND A-56 ROUNDP A-57 rules .blb file 1-3 .rux file 1-3 accessing 1-3 bypassing 1-16 components of 1-5 editing in other than Rules Editor 1-3 icon 1-2 impact on consolidation speed 5-4 overview 1-2 relation to cubes 1-2 saving 2-14 sparsity 5-4 Rules Editor 1-3 opening 1-4, 2-7 rules functions A-1 ABS A-2 ACOS A-3 ASIN A-4
O
overfeeding 5-6
P
PAYMT A-53 Plan cube calculating Planned Production Qty - Kgs 6-4 calculating planned production quantity 6-5 Plan rule calculating Planned Production Qty - Kgs 7-16 precedence of calculation statements example 1-18 Production cube 8-2, 10-17 feeding Qty Required - Kgs 8-6 Production rule calculating Production Cost 10-17 calculating Production Cost/Kg 10-17 feeding Planned Production Qty - Kgs 6-7 feeding Production Cost/Kg 10-19 Purchase cube 2-4, 4-2 Purchase rule 2-8
Table of Contents
ATAN A-5 ATTRN A-6 ATTRS A-7 CAPIT A-8 CHAR A-9 CODE A-10 CONTINUE A-11 COS A-12 DATE A-13 DATES A-14 DAY A-15 DAYNO A-16 DB A-17 DELET A-18 DIMIX A-19 DIMNM A-20 DIMSIZ A-21 DNLEV A-22 DTYPE A-23 ELCOMP A-24 ELCOMPN A-25 ELISANC A-26 ELISCOMP A-27 ELISPAR A-29 ELLEV A-31 ELPAR A-32 ELPARN A-33 ELWEIGHT A-34 EXP A-35
FILL A-36 FV A-37 IF A-38 INSRT A-39 INT A-40 ISLEAF A-41 ISUND A-42 LN A-43 LOG A-44 LONG A-45 LOWER A-46 MAX A-47 MIN A-48 MOD A-49 MONTH A-50 NOW A-51 NUMBR A-52 PAYMT A-53 PV A-54 RAND A-55 ROUND A-56 ROUNDP A-57 SCAN A-58 SIGN A-59 SIN A-60 SQRT A-61 STET A-62 STR A-63 SUBST A-64
Index
Table of Contents
TABDIM A-65 TAN A-66 TIME A-67 TIMST A-68 TIMVL A-71 TODAY A-73 TRIM A-74 UNDEF A-75 UNDEFVALS A-76 UPPER A-77 YEAR A-78 Rules Tracer checking feeders 5-16 tracing feeders 5-14
SQRT A-61 STET A-62 STET function 1-16 STR A-63 string qualifier 1-8 SUBST A-64
T
TABDIM A-65 TAN A-66 terminator 1-15 TIME A-67 time series 7-4 TIMST A-68 TIMVL A-71 TODAY A-73 TRIM A-74
S
sample data setting local data directory to use 2-2 SCAN A-58 SIGN A-59 SIN A-60 skipcheck and feeders 5-5 SKIPCHECK declaration 1-5, 5-5 sparse consolidation algorithm 5-2 sparsity and rules calcluation 5-4 example 5-3 impact on consolidation 5-3
U
UNDEF A-75 UNDEFVALS A-76 UPPER A-77
W
writing a rule 2-6
Y
YEAR A-78