Visier Modeling Language (VML)
Use the Visier Modeling Language (VML) to define plan items in the Visier platform.
This is a complete list of the syntax and functions you can use to define your plan items. Each definition includes a description and a real-life example.
Aggregation
Use aggregation functions to return aggregate values, like average, sum, min, max.
min
Returns the minimum between two numbers.

Get the minimum of the starting headcount or one hundred.
min(Starting_Headcount, 100)
pow
Returns a value raised to the power of an exponent.

Get two raised to the power of three. The numbers can also be plan items or inputs of a number-based data type.
pow(2, 3)
Operator
Use operators to perform math, comparisons, logical tests, and set variables.
!
Keyword to negate an expression. This is interchangeable with not.

Get the previous projected ending headcount, using the starting headcount input, if it is a valid number, otherwise get zero.
if (!isNaN(prev(Projected_Ending_Headcount, Starting_Headcount_Input)))
prev(Projected_Ending_Headcount, Starting_Headcount_Input) else 0
!=
Compares two values and returns true if they are not equal.

Get the previous starting headcount, using the starting headcount input if it is not equal to zero, otherwise get the current starting headcount.
if (prev(Starting_Headcount, Starting_Headcount_Input) != 0)
prev(Starting_Headcount, Starting_Headcount_Input) else Starting_Headcount
&&
Compares two conditions and returns true if both are true. This is interchangeable with and.

Get the annual resignation rate multiplied by the headcount if the annual resignation rate and the headcount are valid numbers, otherwise get zero.
if (!isNaN(Annual_Resignation_Rate) && !isNan(Headcount))
Annual_Resignation_Rate * Headcount else 0
*
Multiplies two values. This operator can be applied to constant values, plan items, inputs, and other calculated values.

Get the FTE ratio multiplied by ending headcount.
Projected Ending FTE Ratio * Projected_Ending_Headcount
+
Adds two values. This can be applied to constant values, plan items, inputs, and other calculated values.

Get the total number of expected exits.
Resignations + Retirements + Involuntary_Turnover
-
Subtracts two values. This operator can be applied to constant values, plan items, inputs, and other calculated values.

Get the difference between budgeted and actual headcount.
Starting_Headcount - Budgeted_Headcount
/
Divides two values. This can be applied to constant values, plan items, inputs, and other calculated values.

Get annual pay for time not worked per employee.
Total_Annual_Pay_For_Time_Not_Worked_Cost / Headcount
<
Compares two values and returns true if the one value is less than the other.

Get the difference between employees with skills and headcount for the plan period.
if (Employees_With_Skills < Headcount) (Headcount - Employees_With_Skills) else 0
<=
Compares two values and returns true if the one value is less than or equal to the other.

Get the difference between employees with skills and headcount for the plan period.
if (Employees_With_Skills <= Headcount + 1) (Headcount - Employees_With_Skills) else 0
=
Compares two values and returns true if they are equal. Also can be used to create a new object to reference in a formula.

Get the total number of employees that equals starting headcount and total starts.
TotalHeadcount = Starting_Headcount + Total_Starts
>
Compares two values and returns true if the one value is greater than the other.

Get the projected ending headcount with a lower limit of 0.
TotalHeadcount = Starting_Headcount + Total_Starts - Total_Exits
if(TotalHeadcount > 0) TotalHeadcount else 0
>=
Compares two values and returns true if the one value is greater than or equal to the other.

Get the projected ending headcount with a lower limit of 0.
TotalHeadcount = Starting_Headcount + Total_Starts - Total_Exits
if(TotalHeadcount >= 1) TotalHeadcount else 0
and
Compares two conditions and returns true if both are true. This is interchangeable with &&.

Get the annual resignation rate multiplied by the headcount if both the annual resignation rate and headcount are valid numbers, otherwise get zero.
if (!isNaN(Annual_Resignation_Rate) and !isNan(Headcount))
Annual_Resignation_Rate * Headcount else 0
else
Keyword to define a conditional statement that returns the value of a given object if the data point does not pass any preceding filters. This is used in conjunction with if.

Get the total headcount, calculated as the starting headcount plus total starts minus total exits, if the result is greater than or equal to one, otherwise get zero.
TotalHeadcount = Starting_Headcount + Total_Starts - Total_Exits
if(TotalHeadcount >= 1) TotalHeadcount else 0
if
Keyword for starting the definition of a conditional function that returns the value of a given object if the data point passes a given filter. This is used in conjunction with else.

Get the total headcount, calculated as the starting headcount plus total starts minus total exits, if the result is greater than or equal to one, otherwise get zero.
TotalHeadcount = Starting_Headcount + Total_Starts - Total_Exits
if(TotalHeadcount >= 1) TotalHeadcount else 0
not
Keyword to negate an expression. This is interchangeable with !.

Get the previous projected ending headcount, using the starting headcount input, if it is a valid number, otherwise get zero.
if (not isNaN(prev(Projected_Ending_Headcount, Starting_Headcount_Input)))
prev(Projected_Ending_Headcount, Starting_Headcount_Input) else 0
or
Compares two conditions and returns true if one condition is true. This is interchangeable with ||.

Get the annual resignation rate multiplied by the headcount if both values are valid numbers, otherwise get zero.
if (!(isNaN(Annual_Resignation_Rate) or isNan(Headcount)))
Annual_Resignation_Rate * Headcount else 0
||
Compares two conditions and returns true if one condition is true. This is interchangeable with or.

Get the annual resignation rate multiplied by the headcount if both values are valid numbers, otherwise get zero.
if (!(isNaN(Annual_Resignation_Rate) || isNan(Headcount)))
Annual_Resignation_Rate * Headcount else 0
Time
Time functions are helpful when working with date and time attributes. For example, you can shift a date forward or backward by a number of days, weeks, months, or years.
annualize
Returns a value scaled to a full year by multiplying it by the number of months in the business calendar.
days
Returns a period type that represents a specified number of days. This function acts as a wrapper around a numerical value, making the day count recognizable and usable by other functions such as shift() to correctly interpret and apply time-based offsets.

Get the projected number of absence hours for the current month by taking the projected number of absence hours from 12 months ago (if 12 months ago still lands in a planned period), else take the actual number of absence hours logged from 12 months ago.
shift(back(days(365)), Projected_Absence_Hours, Absence_Hours)
daysInPeriod
Returns the number of days in the current time period.

Get hourly base pay (includes non-working days in calculation).
deannualize(Total_Annual_Base_Pay_Cost) / (daysInPeriod() / 8)
deannualize
Returns a yearly value scaled down to a single period by dividing it by the number of months in the business calendar.

Get workforce allocation costs in a period.
deannualize(Total_Annual_Base_Pay_Cost) / (daysInPeriod() / 8)
months
Returns a period type that represents a specified number of months. This function acts as a wrapper around a numerical value, making the month count recognizable and usable by other functions such as shift() to correctly interpret and apply time-based offsets.

Get the projected number of absence hours for the current month by taking the projected number of absence hours from 12 months ago (if 12 months ago still lands in a planned period), else take the actual number of absence hours logged from 12 months ago.
shift(back(months(12)), Projected_Absence_Hours, Absence_Hours)
perPeriod_average
Returns the average of all values from a specified start point up to the current time period.

Get the average number of absence hours per period over the last 12 months.
perPeriod_average(back(months(12)), Projected_Absence_Hours, Absence_Hours)
perPeriod_max
Returns the maximum of all values from a specified start point up to the current time period.

Get the maximum number of absence hours per period over the last 12 months.
perPeriod_max(back(months(12)), Projected_Absence_Hours, Absence_Hours)
perPeriod_min
Returns the minimum of all values from a specified start point up to the current time period.

Get the minimum number of absence hours per period over the last 12 months.
perPeriod_min(back(months(12)), Projected_Absence_Hours, Absence_Hours)
perPeriod_product
Returns the product of all values from a specified start point up to the current time period.

Get the product of absence hours per period over the last 12 months.
perPeriod_product(back(months(12)), Projected_Absence_Hours, Absence_Hours)
perPeriod_productNoZero
Returns the product of all non-zero values from a specified start point up to the current time period.

Get the product of all non-zero values of absence hours per period over the last 12 months.
perPeriod_productNoZero(back(months(12)), Projected_Absence_Hours, Absence_Hours)
perPeriod_sum
Returns the sum of all values from a specified start point up to the current time period.

Get the sum of absence hours per period over the last 12 months.
perPeriod_sum(back(months(12)), Projected_Absence_Hours, Absence_Hours)
periods
Returns a time period whose length automatically matches the time frame (e.g., months, quarters) of the current query.

Get the projected number of absence hours for the current month by taking the projected number of absence hours from 12 months ago (if 12 months ago still lands in a planned period), else take the actual number of absence hours logged from 12 months ago. In this instance a period represents one month.
shift(back(periods(12)), Projected_Absence_Hours, Absence_Hours)
periodsFromNow
Returns the number of time periods (e.g., months, quarters) between a data points period and the current evaluation period.

Get the base pay cost since the beginning of the last quarter.
shift(back(quarters(1)), deannualize(Projected_Total_Annual_Base_Pay_Cost) * periodsFromNow(), deannualize(Total_Annual_Base_Pay_Cost) * periodsFromNow())
prev
Returns the value from the previous time period for a specified plan item. If there isnt a previous period, or if the plan item has no value in that period, it returns a fallback value. This fallback can be either an input derived from actuals for that same period or a direct numerical value.

Get the previous projected ending headcount, using the starting headcount input if it is a valid number, otherwise get zero.
if (!isNaN(prev(Projected_Ending_Headcount, Starting_Headcount_Input)))
prev(Projected_Ending_Headcount, Starting_Headcount_Input) else 0
prevWithSeed
Returns the value from the previous time period for a specified plan item. If there isnt a previous period, or if the plan item has no value in that period, it returns a fallback value. This fallback can be either an input derived from actuals for that same period or a direct numerical value. This function is a specialized version of prev(), a "seed" is an initial value or starting point. Its used when there isnt a prior value to draw from, such as at the very beginning of a timeline or a data series. The seed provides a default or baseline value, allowing calculations even when historical data is absent.

To get the current months starting headcount, return the Projected Ending Headcount of the previous month if not NaN, else returns 0.
if (!isNaN(prevWithSeed(Starting_Headcount_Input)))
prevWithSeed(Starting_Headcount_Input) else 0
quarters
Returns a period type that represents a specified number of quarters. This function acts as a wrapper around a numerical value, making the quarter count recognizable and usable by other functions such as shift() to correctly interpret and apply time-based offsets.

Get the base pay cost since the beginning of the last quarter.
shift(back(quarters(1)), deannualize(Projected_Total_Annual_Base_Pay_Cost) * periodsFromNow(), deannualize(Total_Annual_Base_Pay_Cost) * periodsFromNow())
shift
Returns a value from a different time period. It it uses three parameters: first, a parameter defining how far to shift in time, such as back(months(5)) to look five months in the past; second, a formula for planned periods, which is a projection formula used when the shifted time falls within your active plan; and third, a formula for unplanned periods, a different projection used if the shifted time is outside your active plan (for instance, in the historical past after a rebaseline). Both formulas pull data from the shifted time, ensuring you get relevant values whether the period is within your active plan or not.

Get the projected number of absence hours for the current month by taking the projected number of absence hours from 12 months ago (if 12 months ago still lands in a planned period), else take the actual number of absence hours logged from 12 months ago.
shift(back(months(12)), Projected_Absence_Hours, Absence_Hours)
weeks
Returns a period type that represents a specified number of weeks. This function acts as a wrapper around a numerical value, making the week count recognizable and usable by other functions such as shift() to correctly interpret and apply time-based offsets.

Get the projected number of absence hours for the current month by taking the projected number of absence hours from 12 months ago (if 12 months ago still lands in a planned period), else take the actual number of absence hours logged from 12 months ago.
shift(back(weeks(52)), Projected_Absence_Hours, Absence_Hours)
workingDaysInPeriod
Returns the number of working days in the current time period.

Get hourly base pay.
deannualize(Total_Annual_Base_Pay_Cost) / (workingDaysInPeriod() / 8)
yearToDate
Returns the sum of all values from the first period of the year to the current time period.

Get the variable pay for all compensation events that occurred from the beginning of the year and up to the current time period.
yearToDate(Variable_Pay_Period, Actual_Total_YTD_Variable_Pay_Input)
years
Returns a period type that represents a specified number of years. This function acts as a wrapper around a numerical value, making the year count recognizable and usable by other functions such as shift() to correctly interpret and apply time-based offsets.

Get the projected number of absence hours for the current month by taking the projected number of absence hours from 12 months ago (if 12 months ago still lands in a planned period), else take the actual number of absence hours logged from 12 months ago.
shift(back(years(1)), Projected_Absence_Hours, Absence_Hours)
Unique
Specialized functions that perform specific operations.
back
Returns the opposite of time period or value. For example, back(10) returns -10.
Parameter types: (ProjectionCalculation)
ceiling
Returns any value with a decimal rounded up to the nearest whole number.

Get the total expected backfill count from all periods in the past 3 years.
perPeriod_sum(
back(years(3)),
if(ceiling(Time_To_Backfill) = periodsFromNow())
(Time_to_Backfill - floor(Time_to_Backfill)) * max(Total_Exits - Additional_Exits, 0)
else
0,
0
)
floor
Returns any value with a decimal rounded down to the nearest whole number.

Get the precise resignations rounded down to the nearest whole number.
floor(Precise_Resignations)
forward
Returns the exact same value or time period that is given, without making any changes. Can also be used to shift periods forward.
Parameter types: (ProjectionCalculation)
isNaN
Returns true if a value is an invalid mathematical result, otherwise it returns false.

Get the previous projected ending headcount, using the starting headcount input if it is a valid number, otherwise get zero.
if (!isNaN(prev(Projected_Ending_Headcount, Starting_Headcount_Input)))
prev(Projected_Ending_Headcount, Starting_Headcount_Input) else 0
positionId
Returns a unique ID for a row based on its hierarchy members.

Get the expected retirements. The random(positionId()) ensures that retirements are spread evenly throughout the planning periods by seeding the Carryover_Retirements with a different number for each row.
max((Annual_Retirement_Rate * Seasonality_Of_Retirements_By_Period * Headcount), 0) + prev(Carryover_Retirements, random(positionId()))
random
Returns a random decimal number from 0 up to (but not including) 1. The number will be the same every time the calculation runs.

Get the expected retirements. The random(positionId()) ensures that retirements are spread evenly throughout the planning periods by seeding the Carryover_Retirements with a different number for each row.
max((Annual_Retirement_Rate * Seasonality_Of_Retirements_By_Period * Headcount), 0) + prev(Carryover_Retirements, random(positionId()))